examples: use SPDX identifiers
[urcu.git] / doc / examples / urcu-flavors / signal.c
CommitLineData
1c87adb3
MJ
1// SPDX-FileCopyrightText: 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
1fe327be
MD
4
5#include <unistd.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <stdint.h>
9#include <inttypes.h>
10
b9050d91 11#include <urcu/urcu-signal.h> /* Signal-based RCU flavor */
1fe327be
MD
12#include <urcu/rculist.h> /* List example */
13#include <urcu/compiler.h> /* For CAA_ARRAY_SIZE */
14
15/*
16 * Example showing how to use the signal-based Userspace RCU flavor.
17 *
18 * This is a mock-up example where updates and RCU traversals are
19 * performed by the same thread to keep things simple on purpose.
20 */
21
22static CDS_LIST_HEAD(mylist);
23
24struct mynode {
25 uint64_t value;
26 struct cds_list_head node; /* linked-list chaining */
27 struct rcu_head rcu_head; /* for call_rcu() */
28};
29
30static
31int add_node(uint64_t v)
32{
33 struct mynode *node;
34
35 node = calloc(sizeof(*node), 1);
36 if (!node)
37 return -1;
38 node->value = v;
39 cds_list_add_rcu(&node->node, &mylist);
40 return 0;
41}
42
43static
44void rcu_free_node(struct rcu_head *rh)
45{
46 struct mynode *node = caa_container_of(rh, struct mynode, rcu_head);
47
48 free(node);
49}
50
70469b43 51int main(void)
1fe327be
MD
52{
53 uint64_t values[] = { 42, 36, 24, };
54 unsigned int i;
55 int ret;
56 struct mynode *node, *n;
57
58 /*
59 * Each thread need using RCU read-side need to be explicitly
60 * registered.
61 */
b9050d91 62 urcu_signal_register_thread();
1fe327be
MD
63
64 /*
65 * Adding nodes to the linked-list. Safe against concurrent
66 * RCU traversals, require mutual exclusion with list updates.
67 */
68 for (i = 0; i < CAA_ARRAY_SIZE(values); i++) {
69 ret = add_node(values[i]);
70 if (ret)
71 goto end;
72 }
73
74 /*
75 * We need to explicitly mark RCU read-side critical sections
76 * with rcu_read_lock() and rcu_read_unlock(). They can be
77 * nested. Those are no-ops for the QSBR flavor.
78 */
b9050d91 79 urcu_signal_read_lock();
1fe327be
MD
80
81 /*
82 * RCU traversal of the linked list.
83 */
84 cds_list_for_each_entry_rcu(node, &mylist, node) {
85 printf("Value: %" PRIu64 "\n", node->value);
86 }
b9050d91 87 urcu_signal_read_unlock();
1fe327be
MD
88
89 /*
90 * Removing nodes from linked list. Safe against concurrent RCU
91 * traversals, require mutual exclusion with list updates.
92 */
93 cds_list_for_each_entry_safe(node, n, &mylist, node) {
94 cds_list_del_rcu(&node->node);
238eb13d
MD
95 /*
96 * call_rcu() will ensure that the handler
97 * "rcu_free_node" is executed after a grace period.
98 * call_rcu() can be called from RCU read-side critical
99 * sections.
100 */
b9050d91 101 urcu_signal_call_rcu(&node->rcu_head, rcu_free_node);
1fe327be
MD
102 }
103
d7818a6f
MD
104 /*
105 * We can also wait for a quiescent state by calling
106 * synchronize_rcu() rather than using call_rcu(). It is usually
107 * a slower approach than call_rcu(), because the latter can
108 * batch work. Moreover, call_rcu() can be called from a RCU
109 * read-side critical section, but synchronize_rcu() should not.
110 */
b9050d91 111 urcu_signal_synchronize_rcu();
d7818a6f 112
1fe327be
MD
113 sleep(1);
114
115 /*
116 * Waiting for previously called call_rcu handlers to complete
117 * before program exits, or in library destructors, is a good
118 * practice.
119 */
b9050d91 120 urcu_signal_barrier();
1fe327be
MD
121
122end:
b9050d91 123 urcu_signal_unregister_thread();
1fe327be
MD
124 return ret;
125}
This page took 0.040222 seconds and 4 git commands to generate.