diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-04-02 05:24:24 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2016-04-02 14:04:26 +0300 |
commit | 74e40663da696ac965349204ef4aa4a47271c431 (patch) | |
tree | 59f5338d4a105951818f5a9b8a8cb69704ee3f2a /source/blender/editors/physics/physics_pointcache.c | |
parent | b03ff0bbf8ec33fab734ebd8c61b4410e666f957 (diff) |
Fix T47971: rigid body baking crash due to thread race condition.
Diffstat (limited to 'source/blender/editors/physics/physics_pointcache.c')
-rw-r--r-- | source/blender/editors/physics/physics_pointcache.c | 160 |
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; |