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
This commit is contained in:
parent
5bfe6126f8
commit
6617818c7a
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
static void icon_add_to_deferred_delete_queue(int icon_id)
|
||||
{
|
||||
DeferredIconDeleteNode *node =
|
||||
MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
|
||||
node->icon_id = icon_id;
|
||||
BLI_linklist_lockfree_insert(&g_icon_delete_queue,
|
||||
(LockfreeLinkNode *)node);
|
||||
}
|
||||
|
||||
void BKE_icon_id_delete(struct ID *id)
|
||||
{
|
||||
if (!id->icon_id) return; /* no icon defined for library object */
|
||||
|
||||
BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue