Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2016-04-02 05:24:24 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2016-04-02 14:04:26 +0300
commit74e40663da696ac965349204ef4aa4a47271c431 (patch)
tree59f5338d4a105951818f5a9b8a8cb69704ee3f2a /source/blender/editors
parentb03ff0bbf8ec33fab734ebd8c61b4410e666f957 (diff)
Fix T47971: rigid body baking crash due to thread race condition.
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/physics/physics_pointcache.c160
1 files changed, 83 insertions, 77 deletions
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index 406b5892234..e81aa584586 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -30,6 +30,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
@@ -57,12 +58,7 @@
static int ptcache_bake_all_poll(bContext *C)
{
- Scene *scene= CTX_data_scene(C);
-
- if (!scene)
- return 0;
-
- return 1;
+ return CTX_data_scene(C) != NULL;
}
static int ptcache_poll(bContext *C)
@@ -77,14 +73,11 @@ typedef struct PointCacheJob {
float *progress;
PTCacheBaker *baker;
- Object *ob;
- ListBase pidlist;
} PointCacheJob;
static void ptcache_job_free(void *customdata)
{
PointCacheJob *job = customdata;
- BLI_freelistN(&job->pidlist);
MEM_freeN(job->baker);
MEM_freeN(job);
}
@@ -149,7 +142,7 @@ static void ptcache_job_endjob(void *customdata)
WM_set_locked_interface(G.main->wm.first, false);
WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
- WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->ob);
+ WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob);
}
static void ptcache_free_bake(PointCache *cache)
@@ -166,32 +159,60 @@ static void ptcache_free_bake(PointCache *cache)
}
}
-static int ptcache_bake_all_exec(bContext *C, wmOperator *op)
+static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
+ PTCacheBaker *baker = MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker");
- PTCacheBaker *baker = MEM_mallocN(sizeof(PTCacheBaker), "PTCacheBaker");
-
- baker->main = bmain;
- baker->scene = scene;
- baker->pid = NULL;
+ baker->main = CTX_data_main(C);
+ baker->scene = CTX_data_scene(C);
baker->bake = RNA_boolean_get(op->ptr, "bake");
baker->render = 0;
baker->anim_init = 0;
baker->quick_step = 1;
- baker->update_progress = ptcache_job_update;
- PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
- job->baker = baker;
- job->ob = NULL;
- job->pidlist.first = NULL;
- job->pidlist.last = NULL;
+ if (!all) {
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
+ Object *ob = ptr.id.data;
+ PointCache *cache = ptr.data;
+
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, ob, baker->scene, MAX_DUPLI_RECUR);
+
+ for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache == cache) {
+ baker->pid = *pid;
+ break;
+ }
+ }
- baker->bake_job = job;
+ BLI_freelistN(&pidlist);
+ }
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Point Cache",
- WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE);
+ return baker;
+}
+
+static int ptcache_bake_exec(bContext *C, wmOperator *op)
+{
+ bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
+
+ PTCacheBaker *baker = ptcache_baker_create(C, op, all);
+ BKE_ptcache_bake(baker);
+ MEM_freeN(baker);
+
+ return OPERATOR_FINISHED;
+}
+
+static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
+
+ PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
+ job->baker = ptcache_baker_create(C, op, all);
+ job->baker->bake_job = job;
+ job->baker->update_progress = ptcache_job_update;
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C),
+ "Point Cache", WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE);
WM_jobs_customdata_set(wm_job, job, ptcache_job_free);
WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE);
@@ -201,7 +222,33 @@ static int ptcache_bake_all_exec(bContext *C, wmOperator *op)
WM_jobs_start(CTX_wm_manager(C), wm_job);
- return OPERATOR_FINISHED;
+ WM_event_add_modal_handler(C, op);
+
+ /* we must run modal until the bake job is done, otherwise the undo push
+ * happens before the job ends, which can lead to race conditions between
+ * the baking and file writing code */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Scene *scene = (Scene *) op->customdata;
+
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_POINTCACHE)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void ptcache_bake_cancel(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = (Scene *) op->customdata;
+
+ /* kill on cancel, because job is using op->reports */
+ WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_POINTCACHE);
}
static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
@@ -236,7 +283,10 @@ void PTCACHE_OT_bake_all(wmOperatorType *ot)
ot->idname = "PTCACHE_OT_bake_all";
/* api callbacks */
- ot->exec = ptcache_bake_all_exec;
+ ot->exec = ptcache_bake_exec;
+ ot->invoke = ptcache_bake_invoke;
+ ot->modal = ptcache_bake_modal;
+ ot->cancel = ptcache_bake_cancel;
ot->poll = ptcache_bake_all_poll;
/* flags */
@@ -259,53 +309,6 @@ void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
-static int ptcache_bake_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
- Object *ob = ptr.id.data;
- PointCache *cache = ptr.data;
-
- PTCacheBaker *baker = MEM_mallocN(sizeof(PTCacheBaker), "PTCacheBaker");
- baker->main = bmain;
- baker->scene = scene;
- baker->bake = RNA_boolean_get(op->ptr, "bake");
- baker->render = 0;
- baker->anim_init = 0;
- baker->quick_step = 1;
- baker->update_progress = ptcache_job_update;
- baker->pid = NULL;
-
- PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
- job->baker = baker;
- job->ob = ob;
-
- BKE_ptcache_ids_from_object(&job->pidlist, ob, scene, MAX_DUPLI_RECUR);
-
- for (PTCacheID *pid = job->pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- baker->pid = pid;
- break;
- }
- }
-
- baker->bake_job = job;
-
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Point Cache",
- WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE);
-
- WM_jobs_customdata_set(wm_job, job, ptcache_job_free);
- WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE);
- WM_jobs_callbacks(wm_job, ptcache_job_startjob, NULL, NULL, ptcache_job_endjob);
-
- WM_set_locked_interface(CTX_wm_manager(C), true);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
-
- return OPERATOR_FINISHED;
-}
-
static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
@@ -339,6 +342,9 @@ void PTCACHE_OT_bake(wmOperatorType *ot)
/* api callbacks */
ot->exec = ptcache_bake_exec;
+ ot->invoke = ptcache_bake_invoke;
+ ot->modal = ptcache_bake_modal;
+ ot->cancel = ptcache_bake_cancel;
ot->poll = ptcache_poll;
/* flags */
@@ -441,7 +447,7 @@ void PTCACHE_OT_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = ptcache_add_new_exec;
- ot->poll = ptcache_poll; // ptcache_bake_all_poll;
+ ot->poll = ptcache_poll;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;