Blender V4.3
BLI_linklist_lockfree_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "MEM_guardedalloc.h"
8
10#include "BLI_task.h"
11#include "BLI_threads.h"
12#include "BLI_utildefines.h"
13
15{
18 EXPECT_EQ(list.head, &list.dummy_node);
19 EXPECT_EQ(list.tail, &list.dummy_node);
20 BLI_linklist_lockfree_free(&list, nullptr);
21}
22
23TEST(LockfreeLinkList, InsertSingle)
24{
28 BLI_linklist_lockfree_insert(&list, &node);
29 EXPECT_EQ(list.head, &list.dummy_node);
30 EXPECT_EQ(list.head->next, &node);
31 EXPECT_EQ(list.tail, &node);
32 BLI_linklist_lockfree_free(&list, nullptr);
33}
34
35TEST(LockfreeLinkList, InsertMultiple)
36{
37 static const int nodes_num = 128;
39 LockfreeLinkNode nodes[nodes_num];
41 /* Insert all the nodes. */
42 for (LockfreeLinkNode &node : nodes) {
43 BLI_linklist_lockfree_insert(&list, &node);
44 }
45 /* Check head and tail. */
46 EXPECT_EQ(list.head, &list.dummy_node);
47 EXPECT_EQ(list.tail, &nodes[nodes_num - 1]);
48 /* Check rest of the nodes. */
49 int node_index = 0;
50 for (LockfreeLinkNode *node = BLI_linklist_lockfree_begin(&list); node != nullptr;
51 node = node->next, ++node_index)
52 {
53 EXPECT_EQ(node, &nodes[node_index]);
54 if (node_index != nodes_num - 1) {
55 EXPECT_EQ(node->next, &nodes[node_index + 1]);
56 }
57 }
58 /* Free list. */
59 BLI_linklist_lockfree_free(&list, nullptr);
60}
61
62namespace {
63
64struct IndexedNode {
65 IndexedNode *next;
66 int index;
67};
68
69void concurrent_insert(TaskPool *__restrict pool, void *taskdata)
70{
72 CHECK_NOTNULL(list);
73 IndexedNode *node = (IndexedNode *)MEM_mallocN(sizeof(IndexedNode), "test node");
74 node->index = POINTER_AS_INT(taskdata);
76}
77
78} // namespace
79
80TEST(LockfreeLinkList, InsertMultipleConcurrent)
81{
82 static const int nodes_num = 655360;
83 /* Initialize list. */
86 /* Initialize task scheduler and pool. */
88 /* Push tasks to the pool. */
89 for (int i = 0; i < nodes_num; ++i) {
90 BLI_task_pool_push(pool, concurrent_insert, POINTER_FROM_INT(i), false, nullptr);
91 }
92 /* Run all the tasks. */
94 /* Verify we've got all the data properly inserted. */
95 EXPECT_EQ(list.head, &list.dummy_node);
96 bool *visited_nodes = (bool *)MEM_callocN(sizeof(bool) * nodes_num, "visited nodes");
97 /* First, we make sure that none of the nodes are added twice. */
98 for (LockfreeLinkNode *node_v = BLI_linklist_lockfree_begin(&list); node_v != nullptr;
99 node_v = node_v->next)
100 {
101 IndexedNode *node = (IndexedNode *)node_v;
102 EXPECT_GE(node->index, 0);
103 EXPECT_LT(node->index, nodes_num);
104 EXPECT_FALSE(visited_nodes[node->index]);
105 visited_nodes[node->index] = true;
106 }
107 /* Then we make sure node was added. */
108 for (int node_index = 0; node_index < nodes_num; ++node_index) {
109 EXPECT_TRUE(visited_nodes[node_index]);
110 }
111 MEM_freeN(visited_nodes);
112 /* Cleanup data. */
114 BLI_task_pool_free(pool);
115}
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:57
TaskPool * BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority)
Definition task_pool.cc:413
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:516
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:471
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:431
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:450
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
Read Guarded memory(de)allocation.
OperationNode * node
#define CHECK_NOTNULL(expression)
Definition log.h:40
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
struct LockfreeLinkNode * next