Recent spinlock commit made scheduling unsafe for threading

Namely, it caused nodes be adding to the pool multiple times.

Returned spin back, but use it only in cases node valency is
zero. So now valency is decreasing without any locks, then
if it's zero spin lock happens, node color (which indicates
whether node is scheduled or not) happens. Actual new task
creation happens outside of locks.

This might sound a bit complicated, but it's straightforward
code which is free from any thread synchronization latency.
This commit is contained in:
Sergey Sharybin
2013-08-14 09:24:15 +00:00
parent 932df91cbd
commit 5be97aba95
6 changed files with 48 additions and 5 deletions

View File

@@ -118,6 +118,10 @@ void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
/* ** Threaded update ** */
/* Global initialization/deinitialization */
void DAG_threaded_init(void);
void DAG_threaded_exit(void);
/* Initialize the DAG for threaded update. */
void DAG_threaded_update_begin(struct Scene *scene);

View File

@@ -120,6 +120,7 @@ void free_blender(void)
IMB_exit();
BKE_images_exit();
DAG_threaded_exit();
BKE_brush_system_exit();

View File

@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
#include "DNA_anim_types.h"
#include "DNA_camera_types.h"
@@ -2658,6 +2659,18 @@ void DAG_pose_sort(Object *ob)
/* ************************ DAG FOR THREADED UPDATE ********************* */
static SpinLock threaded_update_lock;
void DAG_threaded_init(void)
{
BLI_spin_init(&threaded_update_lock);
}
void DAG_threaded_exit(void)
{
BLI_spin_end(&threaded_update_lock);
}
/* Initialize the DAG for threaded update.
*
* Sets up all the data needed for faster check whether DAG node is
@@ -2670,6 +2683,7 @@ void DAG_threaded_update_begin(Scene *scene)
/* We reset valency to zero first... */
for (node = scene->theDag->DagNode.first; node; node = node->next) {
node->valency = 0;
node->color = DAG_WHITE;
}
/* ... and then iterate over all the nodes and
@@ -2698,7 +2712,16 @@ void DAG_threaded_update_foreach_ready_node(Scene *scene,
for (node = scene->theDag->DagNode.first; node; node = node->next) {
if (node->valency == 0) {
func(node, user_data);
bool need_schedule;
BLI_spin_lock(&threaded_update_lock);
need_schedule = node->color == DAG_WHITE;
node->color = DAG_BLACK;
BLI_spin_unlock(&threaded_update_lock);
if (need_schedule) {
func(node, user_data);
}
}
}
}
@@ -2738,11 +2761,21 @@ void DAG_threaded_update_handle_node_updated(void *node_v,
DagAdjList *itA;
for (itA = node->child; itA; itA = itA->next) {
if (itA->node != node) {
atomic_sub_uint32(&itA->node->valency, 1);
DagNode *child_node = itA->node;
if (child_node != node) {
atomic_sub_uint32(&child_node->valency, 1);
if (itA->node->valency == 0) {
func(itA->node, user_data);
if (child_node->valency == 0) {
bool need_schedule;
BLI_spin_lock(&threaded_update_lock);
need_schedule = child_node->color == DAG_WHITE;
child_node->color = DAG_BLACK;
BLI_spin_unlock(&threaded_update_lock);
if (need_schedule) {
func(child_node, user_data);
}
}
}
}

View File

@@ -60,6 +60,7 @@
#include "IMB_imbuf.h"
#include "BKE_blender.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -1198,6 +1199,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
IMB_exit();
BKE_images_exit();
DAG_threaded_exit();
totblock = MEM_get_memory_blocks_in_use();
if (totblock != 0) {

View File

@@ -1519,6 +1519,7 @@ int main(int argc, const char **argv)
IMB_init();
BKE_images_init();
BKE_modifier_init();
DAG_threaded_init();
BKE_brush_system_init();

View File

@@ -458,6 +458,7 @@ int main(int argc, char** argv)
IMB_init();
BKE_images_init();
BKE_modifier_init();
DAG_threaded_init();
#ifdef WITH_FFMPEG
IMB_ffmpeg_init();
@@ -1081,6 +1082,7 @@ int main(int argc, char** argv)
IMB_exit();
BKE_images_exit();
DAG_threaded_exit();
SYS_DeleteSystem(syshandle);