Implement DQ unit test
[urcu.git] / tests / unit / test_urcu_dq.c
1 /*
2 * test_urcu_dq.c
3 *
4 * Userspace RCU library - double-ended queue unit test
5 *
6 * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include <urcu.h>
24 #include <urcu/rcudq.h>
25 #include <urcu/compiler.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #define err_printf(fmt, args...) \
31 fprintf(stderr, "[error in %s@%d:%s()] " fmt, __FILE__, __LINE__, __func__, ## args)
32
33 struct myobj {
34 int a;
35 int b;
36 struct cds_rcudq_head node;
37 struct rcu_head rcu_head;
38 };
39
40 static CDS_RCUDQ_HEAD(dq);
41
42 static
43 struct myobj *create_obj(int a, int b)
44 {
45 struct myobj *obj;
46
47 obj = malloc(sizeof(*obj));
48 if (!obj)
49 return NULL;
50 obj->a = a;
51 obj->b = b;
52 CDS_INIT_RCUDQ_HEAD(&obj->node);
53 return obj;
54 }
55
56 static
57 void poison_head(struct cds_rcudq_head *head)
58 {
59 memset(head, 42, sizeof(*head));
60 }
61
62 static
63 void print_obj(struct myobj *obj)
64 {
65 printf("(%d, %d) ", obj->a, obj->b);
66 }
67
68 static
69 void free_obj(struct rcu_head *rcu_head)
70 {
71 struct myobj *obj = caa_container_of(rcu_head, struct myobj, rcu_head);
72
73 free(obj);
74 }
75
76 int main(int argc, char **argv)
77 {
78 struct myobj *obj, *tmp;
79 struct cds_rcudq_head *pos, *p;
80 unsigned int i, j;
81
82 rcu_register_thread();
83
84 if (!cds_rcudq_empty(&dq)) {
85 err_printf("Queue is not empty as expected\n");
86 goto error;
87 }
88
89 poison_head(&dq);
90 CDS_INIT_RCUDQ_HEAD(&dq);
91 if (!cds_rcudq_empty(&dq)) {
92 err_printf("Queue is not empty as expected\n");
93 goto error;
94 }
95
96 /* Single updater */
97 for (i = 0; i < 4; i++) {
98 for (j = 0; j < 4; j++) {
99 obj = create_obj(i, j);
100 if (!obj)
101 goto error;
102 /* Add to tail */
103 cds_rcudq_add_tail(&obj->node, &dq);
104 }
105 }
106 for (i = 42; i < 46; i++) {
107 obj = create_obj(i, i);
108 if (!obj)
109 goto error;
110 /* Add to head */
111 cds_rcudq_add(&obj->node, &dq);
112 }
113
114 printf("cds_rcudq_first_entry()\n");
115 obj = cds_rcudq_first_entry(&dq, struct myobj, node);
116 print_obj(obj);
117 printf("\n");
118
119 printf("cds_rcudq_for_each()\n");
120 cds_rcudq_for_each(pos, &dq) {
121 obj = cds_rcudq_entry(pos, struct myobj, node);
122 print_obj(obj);
123 }
124 printf("\n");
125
126 printf("cds_rcudq_for_each_safe()\n");
127 cds_rcudq_for_each_safe(pos, p, &dq) {
128 obj = cds_rcudq_entry(pos, struct myobj, node);
129 print_obj(obj);
130 if (obj->a == 42) {
131 printf("(removing) ");
132 cds_rcudq_del(&obj->node);
133 call_rcu(&obj->rcu_head, free_obj);
134 }
135 }
136 printf("\n");
137
138 printf("cds_rcudq_for_each_entry()\n");
139 cds_rcudq_for_each_entry(obj, &dq, node) {
140 print_obj(obj);
141 }
142 printf("\n");
143
144 printf("cds_rcudq_for_each_entry_safe()\n");
145 cds_rcudq_for_each_entry_safe(obj, tmp, &dq, node) {
146 print_obj(obj);
147 if (obj->a == 43) {
148 printf("(removing) ");
149 cds_rcudq_del(&obj->node);
150 call_rcu(&obj->rcu_head, free_obj);
151 }
152 }
153 printf("\n");
154
155 printf("cds_rcudq_for_each_reverse()\n");
156 cds_rcudq_for_each_reverse(pos, &dq) {
157 obj = cds_rcudq_entry(pos, struct myobj, node);
158 print_obj(obj);
159 }
160 printf("\n");
161
162 printf("cds_rcudq_for_each_reverse_safe()\n");
163 cds_rcudq_for_each_reverse_safe(pos, p, &dq) {
164 obj = cds_rcudq_entry(pos, struct myobj, node);
165 print_obj(obj);
166 if (obj->a == 44) {
167 printf("(removing) ");
168 cds_rcudq_del(&obj->node);
169 call_rcu(&obj->rcu_head, free_obj);
170 }
171 }
172 printf("\n");
173
174 printf("cds_rcudq_for_each_entry_reverse()\n");
175 cds_rcudq_for_each_entry_reverse(obj, &dq, node) {
176 print_obj(obj);
177 }
178 printf("\n");
179
180 printf("cds_rcudq_for_each_entry_reverse_safe()\n");
181 cds_rcudq_for_each_entry_reverse_safe(obj, tmp, &dq, node) {
182 print_obj(obj);
183 if (obj->a == 45) {
184 printf("(removing) ");
185 cds_rcudq_del(&obj->node);
186 call_rcu(&obj->rcu_head, free_obj);
187 }
188 }
189 printf("\n");
190
191
192 rcu_read_lock();
193
194 printf("cds_rcudq_for_each_rcu()\n");
195 cds_rcudq_for_each_rcu(pos, &dq) {
196 obj = cds_rcudq_entry(pos, struct myobj, node);
197 print_obj(obj);
198 }
199 printf("\n");
200
201 printf("cds_rcudq_for_each_entry_rcu()\n");
202 cds_rcudq_for_each_entry_rcu(obj, &dq, node) {
203 print_obj(obj);
204 }
205 printf("\n");
206
207 printf("cds_rcudq_for_each_reverse_rcu()\n");
208 cds_rcudq_for_each_reverse_rcu(pos, &dq) {
209 obj = cds_rcudq_entry(pos, struct myobj, node);
210 print_obj(obj);
211 }
212 printf("\n");
213
214 printf("cds_rcudq_for_each_entry_reverse_rcu()\n");
215 cds_rcudq_for_each_entry_reverse_rcu(obj, &dq, node) {
216 print_obj(obj);
217 }
218 printf("\n");
219
220 rcu_read_unlock();
221
222 cds_rcudq_for_each_entry_safe(obj, tmp, &dq, node) {
223 cds_rcudq_del(&obj->node);
224 call_rcu(&obj->rcu_head, free_obj);
225 }
226
227 if (!cds_rcudq_empty(&dq)) {
228 err_printf("Queue is not empty as expected\n");
229 goto error;
230 }
231
232 /* Free memory (in flight call_rcu callback execution) before exiting */
233 rcu_barrier();
234
235 rcu_unregister_thread();
236
237 exit(EXIT_SUCCESS);
238
239 error:
240 exit(EXIT_FAILURE);
241 }
This page took 0.0342 seconds and 4 git commands to generate.