diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-04-16 11:19:03 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-04-16 11:19:03 +0300 |
commit | 8ad93dd0098d8b8356bfce27f716488f9afd653e (patch) | |
tree | ffe463a34c395cdac0d83df3a94e6593134a1b84 /source/blender | |
parent | 6ef5b422fce9deb1278b7092890ebe5e10227eae (diff) | |
parent | 6617818c7a1f5729763aa214866b5d7dc0358f36 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_icons.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/icons.c | 64 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_linklist_lockfree.h | 88 | ||||
-rw-r--r-- | source/blender/blenlib/CMakeLists.txt | 3 | ||||
-rw-r--r-- | source/blender/blenlib/intern/BLI_linklist_lockfree.c | 91 |
5 files changed, 244 insertions, 5 deletions
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 f3ff2c4425a..25a3675896b 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -49,7 +49,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 */ @@ -72,6 +74,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; @@ -91,6 +100,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 */ @@ -111,11 +121,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__); @@ -124,6 +138,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; @@ -133,6 +149,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) @@ -435,6 +467,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; @@ -462,6 +496,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__); @@ -556,6 +592,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)); @@ -570,6 +608,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)) { @@ -580,12 +620,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); } /** diff --git a/source/blender/blenlib/BLI_linklist_lockfree.h b/source/blender/blenlib/BLI_linklist_lockfree.h new file mode 100644 index 00000000000..7e7400361e3 --- /dev/null +++ b/source/blender/blenlib/BLI_linklist_lockfree.h @@ -0,0 +1,88 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_LINKLIST_LOCKFREE_H__ +#define __BLI_LINKLIST_LOCKFREE_H__ + +/** \file BLI_linklist_lockfree.h + * \ingroup bli + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LockfreeLinkNode { + struct LockfreeLinkNode *next; + /* NOTE: "Subclass" this structure to add custom-defined data. */ +} LockfreeLinkNode; + +typedef struct LockfreeLinkList { + /* We keep a dummy node at the beginning of the list all the time. + * This allows us to make sure head and tail pointers are always + * valid, and saves from annoying exception cases in insert(). + */ + LockfreeLinkNode dummy_node; + /* NOTE: This fields might point to a dummy node. */ + LockfreeLinkNode *head, *tail; +} LockfreeLinkList; + +typedef void (*LockfreeeLinkNodeFreeFP)(void *link); + +/* ************************************************************************** */ +/* NOTE: These functions are NOT safe for use from threads. */ +/* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */ + +/* Make list ready for lock-free access. */ +void BLI_linklist_lockfree_init(LockfreeLinkList *list); + +/* Completely free the whole list, it is NOT re-usable after this. */ +void BLI_linklist_lockfree_free(LockfreeLinkList *list, + LockfreeeLinkNodeFreeFP free_func); + +/* Remove all the elements from the list, keep it usable for further + * inserts. + */ +void BLI_linklist_lockfree_clear(LockfreeLinkList *list, + LockfreeeLinkNodeFreeFP free_func); + + +/* Begin iteration of lock-free linked list, starting with a + * first user=defined node. Will ignore the dummy node. + */ +LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list); + + +/* ************************************************************************** */ +/* NOTE: These functions are safe for use from threads. */ + +void BLI_linklist_lockfree_insert(LockfreeLinkList *list, + LockfreeLinkNode *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __BLI_LINKLIST_H__ */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 5bcf4303a84..80a8ef96eb3 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -50,6 +50,7 @@ set(SRC intern/BLI_kdopbvh.c intern/BLI_kdtree.c intern/BLI_linklist.c + intern/BLI_linklist_lockfree.c intern/BLI_memarena.c intern/BLI_memiter.c intern/BLI_mempool.c @@ -165,7 +166,7 @@ set(SRC BLI_kdtree.h BLI_lasso_2d.h BLI_link_utils.h - BLI_linklist.h + BLI_linklist_lockfree.h BLI_linklist_stack.h BLI_listbase.h BLI_math.h diff --git a/source/blender/blenlib/intern/BLI_linklist_lockfree.c b/source/blender/blenlib/intern/BLI_linklist_lockfree.c new file mode 100644 index 00000000000..c004ddb6b66 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_linklist_lockfree.c @@ -0,0 +1,91 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/BLI_linklist_lockfree.c + * \ingroup bli + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_linklist_lockfree.h" +#include "BLI_strict_flags.h" + +#include "atomic_ops.h" + +void BLI_linklist_lockfree_init(LockfreeLinkList *list) +{ + list->dummy_node.next = NULL; + list->head = list->tail = &list->dummy_node; +} + +void BLI_linklist_lockfree_free(LockfreeLinkList *list, + LockfreeeLinkNodeFreeFP free_func) +{ + if (free_func != NULL) { + /* NOTE: We start from a first user-added node. */ + LockfreeLinkNode *node = list->head->next; + while (node != NULL) { + LockfreeLinkNode *node_next = node->next; + free_func(node); + node = node_next; + } + } +} + +void BLI_linklist_lockfree_clear(LockfreeLinkList *list, + LockfreeeLinkNodeFreeFP free_func) +{ + BLI_linklist_lockfree_free(list, free_func); + BLI_linklist_lockfree_init(list); +} + +void BLI_linklist_lockfree_insert(LockfreeLinkList *list, + LockfreeLinkNode *node) +{ + /* Based on: + * + * John D. Valois + * Implementing Lock-Free Queues + * + * http://people.csail.mit.edu/bushl2/rpi/portfolio/lockfree-grape/documents/lock-free-linked-lists.pdf + */ + bool keep_working; + LockfreeLinkNode *tail_node; + node->next = NULL; + do { + tail_node = list->tail; + keep_working = + (atomic_cas_ptr((void**)&tail_node->next, NULL, node) != NULL); + if (keep_working) { + atomic_cas_ptr((void**)&list->tail, tail_node, tail_node->next); + } + } while (keep_working); + atomic_cas_ptr((void**)&list->tail, tail_node, node); +} + +LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list) +{ + return list->head->next; +} |