[Bf-blender-cvs] [6617818c7a1] master: Make ID icons safe for deletion from threads

Sergey Sharybin noreply at git.blender.org
Mon Apr 16 10:18:49 CEST 2018


Commit: 6617818c7a1f5729763aa214866b5d7dc0358f36
Author: Sergey Sharybin
Date:   Fri Apr 13 13:52:37 2018 +0200
Branches: master
https://developer.blender.org/rB6617818c7a1f5729763aa214866b5d7dc0358f36

Make ID icons safe for deletion from threads

Added a lock-free deferred queue for deletion. Now if ID icon
is requested to be freed from non-main thread, it will be added
to the deferred list. Actual deletion will happen later from main
thread.

Currently actual deletion only happens next time BKE_icon_id_delete()
is called, which might not be enough. But it's easy to enforce
deferred deletion.

Icons for preview images are not covered by deferred deletion yet.

Reviewers: mont29

Differential Revision: https://developer.blender.org/D3146

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

M	source/blender/blenkernel/BKE_icons.h
M	source/blender/blenkernel/intern/icons.c

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

diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index a9ca5cc8bbb..c3f5d7bf7c2 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -75,6 +75,9 @@ void BKE_icon_changed(const int icon_id);
 /* free all icons */
 void BKE_icons_free(void);
 
+/* free all icons marked for deferred deletion */
+void BKE_icons_deferred_free(void);
+
 /* free the preview image for use in list */
 void BKE_previewimg_freefunc(void *link);
 
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 7302d62d20f..6aa00b2c97d 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -48,7 +48,9 @@
 
 #include "BLI_utildefines.h"
 #include "BLI_ghash.h"
+#include "BLI_linklist_lockfree.h"
 #include "BLI_string.h"
+#include "BLI_threads.h"
 
 #include "BKE_icons.h"
 #include "BKE_global.h" /* only for G.background test */
@@ -71,6 +73,13 @@ static int gFirstIconId = 1;
 
 static GHash *gCachedPreviews = NULL;
 
+/* Queue of icons for deferred deletion. */
+typedef struct DeferredIconDeleteNode {
+	struct DeferredIconDeleteNode *next;
+	int icon_id;
+} DeferredIconDeleteNode;
+static LockfreeLinkList g_icon_delete_queue;
+
 static void icon_free(void *val)
 {
 	Icon *icon = val;
@@ -90,6 +99,7 @@ static void icon_free(void *val)
  * after the integer number range is used up */
 static int get_next_free_id(void)
 {
+	BLI_assert(BLI_thread_is_main());
 	int startId = gFirstIconId;
 
 	/* if we haven't used up the int number range, we just return the next int */
@@ -110,11 +120,15 @@ static int get_next_free_id(void)
 
 void BKE_icons_init(int first_dyn_id)
 {
+	BLI_assert(BLI_thread_is_main());
+
 	gNextIconId = first_dyn_id;
 	gFirstIconId = first_dyn_id;
 
-	if (!gIcons)
+	if (!gIcons) {
 		gIcons = BLI_ghash_int_new(__func__);
+		BLI_linklist_lockfree_init(&g_icon_delete_queue);
+	}
 
 	if (!gCachedPreviews) {
 		gCachedPreviews = BLI_ghash_str_new(__func__);
@@ -123,6 +137,8 @@ void BKE_icons_init(int first_dyn_id)
 
 void BKE_icons_free(void)
 {
+	BLI_assert(BLI_thread_is_main());
+
 	if (gIcons) {
 		BLI_ghash_free(gIcons, NULL, icon_free);
 		gIcons = NULL;
@@ -132,6 +148,22 @@ void BKE_icons_free(void)
 		BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
 		gCachedPreviews = NULL;
 	}
+
+	BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
+}
+
+void BKE_icons_deferred_free(void)
+{
+	BLI_assert(BLI_thread_is_main());
+
+	for (DeferredIconDeleteNode *node =
+	             (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
+	     node != NULL;
+	     node = node->next)
+	{
+		BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(node->icon_id), NULL, icon_free);
+	}
+	BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
 }
 
 static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
@@ -433,6 +465,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
 
 void BKE_icon_changed(const int icon_id)
 {
+	BLI_assert(BLI_thread_is_main());
+
 	Icon *icon = NULL;
 	
 	if (!icon_id || G.background) return;
@@ -460,6 +494,8 @@ void BKE_icon_changed(const int icon_id)
 
 static int icon_id_ensure_create_icon(struct ID *id)
 {
+	BLI_assert(BLI_thread_is_main());
+
 	Icon *new_icon = NULL;
 
 	new_icon = MEM_mallocN(sizeof(Icon), __func__);
@@ -554,6 +590,8 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
 
 Icon *BKE_icon_get(const int icon_id)
 {
+	BLI_assert(BLI_thread_is_main());
+
 	Icon *icon = NULL;
 
 	icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
@@ -568,6 +606,8 @@ Icon *BKE_icon_get(const int icon_id)
 
 void BKE_icon_set(const int icon_id, struct Icon *icon)
 {
+	BLI_assert(BLI_thread_is_main());
+
 	void **val_p;
 
 	if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) {
@@ -578,12 +618,28 @@ void BKE_icon_set(const int icon_id, struct Icon *icon)
 	*val_p = icon;
 }
 
-void BKE_icon_id_delete(struct ID *id)
+static void icon_add_to_deferred_delete_queue(int icon_id)
 {
-	if (!id->icon_id) return;  /* no icon defined for library object */
+	DeferredIconDeleteNode *node =
+	        MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
+	node->icon_id = icon_id;
+	BLI_linklist_lockfree_insert(&g_icon_delete_queue,
+	                             (LockfreeLinkNode *)node);
+}
 
-	BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free);
+void BKE_icon_id_delete(struct ID *id)
+{
+	const int icon_id = id->icon_id;
+	if (!icon_id) return;  /* no icon defined for library object */
 	id->icon_id = 0;
+
+	if (!BLI_thread_is_main()) {
+		icon_add_to_deferred_delete_queue(icon_id);
+		return;
+	}
+
+	BKE_icons_deferred_free();
+	BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(icon_id), NULL, icon_free);
 }
 
 /**



More information about the Bf-blender-cvs mailing list