Commit: 45e68e190dca949d4d2018d587b8f3cbb1000700
Author: Brecht Van Lommel
Date:   Sat Apr 2 04:24:24 2016 +0200
Branches: blender-v2.77-release
https://developer.blender.org/rB45e68e190dca949d4d2018d587b8f3cbb1000700

Fix T47971: rigid body baking crash due to thread race condition.

===================================================================

M       source/blender/blenkernel/BKE_pointcache.h
M       source/blender/blenkernel/intern/pointcache.c
M       source/blender/editors/physics/physics_pointcache.c
M       source/blender/render/intern/source/pipeline.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_pointcache.h 
b/source/blender/blenkernel/BKE_pointcache.h
index 40dbffe..8238ea6 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -190,7 +190,7 @@ typedef struct PTCacheBaker {
        int render;
        int anim_init;
        int quick_step;
-       struct PTCacheID *pid;
+       struct PTCacheID pid;
 
        void (*update_progress)(void *data, float progress, int *cancel);
        void *bake_job;
diff --git a/source/blender/blenkernel/intern/pointcache.c 
b/source/blender/blenkernel/intern/pointcache.c
index c8a42d8..448aaaa 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3508,15 +3508,13 @@ void BKE_ptcache_quick_cache_all(Main *bmain, Scene 
*scene)
 {
        PTCacheBaker baker;
 
-       baker.bake=0;
-       baker.pid=NULL;
-       baker.render=0;
+       memset(&baker, 0, sizeof(baker));
+       baker.main = bmain;
+       baker.scene = scene;
+       baker.bake = 0;
+       baker.render = 0;
        baker.anim_init = 0;
-       baker.main=bmain;
-       baker.scene=scene;
-       baker.quick_step=scene->physics_settings.quick_cache_step;
-       baker.update_progress = NULL;
-       baker.bake_job = NULL;
+       baker.quick_step = scene->physics_settings.quick_cache_step;
 
        BKE_ptcache_bake(&baker);
 }
@@ -3541,7 +3539,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
        Scene *sce_iter; /* SETLOOPER macro only */
        Base *base;
        ListBase pidlist;
-       PTCacheID *pid = baker->pid;
+       PTCacheID *pid = &baker->pid;
        PointCache *cache = NULL;
        float frameleno = scene->r.framelen;
        int cfrao = CFRA;
@@ -3552,7 +3550,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
        G.is_break = false;
 
        /* set caches to baking mode and figure out start frame */
-       if (pid) {
+       if (pid->ob) {
                /* cache/bake a single object */
                cache = pid->cache;
                if ((cache->flag & PTCACHE_BAKED)==0) {
diff --git a/source/blender/editors/physics/physics_pointcache.c 
b/source/blender/editors/physics/physics_pointcache.c
index 406b589..e81aa58 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;
diff --git a/source/blender/render/intern/source/pipeline.c 
b/source/blender/render/intern/source/pipeline.c
index 6fef581..f7e35a4 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -3061,15 +3061,13 @@ static void update_physics_cache(Render *re, Scene 
*scene, int UNUSED(anim_init)
 {
        PTCacheBaker baker;
 
+       memset(&baker, 0, sizeof(baker));
        baker.main = re->main;
        baker.scene = scene;
-       baker.pid = NULL;
        baker.bake = 0;
        baker.render = 1;
        baker.anim_init = 1;
        baker.quick_step = 1;
-       baker.update_progress = NULL;
-       baker.bake_job = NULL;
 
        BKE_ptcache_bake(&baker);
 }

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to