diff options
Diffstat (limited to 'tools/testing/radix-tree/rcupdate.c')
-rw-r--r-- | tools/testing/radix-tree/rcupdate.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/tools/testing/radix-tree/rcupdate.c b/tools/testing/radix-tree/rcupdate.c new file mode 100644 index 000000000000..31a2d14225d6 --- /dev/null +++ b/tools/testing/radix-tree/rcupdate.c | |||
@@ -0,0 +1,86 @@ | |||
1 | #include <linux/rcupdate.h> | ||
2 | #include <pthread.h> | ||
3 | #include <stdio.h> | ||
4 | #include <assert.h> | ||
5 | |||
6 | static pthread_mutex_t rculock = PTHREAD_MUTEX_INITIALIZER; | ||
7 | static struct rcu_head *rcuhead_global = NULL; | ||
8 | static __thread int nr_rcuhead = 0; | ||
9 | static __thread struct rcu_head *rcuhead = NULL; | ||
10 | static __thread struct rcu_head *rcutail = NULL; | ||
11 | |||
12 | static pthread_cond_t rcu_worker_cond = PTHREAD_COND_INITIALIZER; | ||
13 | |||
14 | /* switch to urcu implementation when it is merged. */ | ||
15 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head)) | ||
16 | { | ||
17 | head->func = func; | ||
18 | head->next = rcuhead; | ||
19 | rcuhead = head; | ||
20 | if (!rcutail) | ||
21 | rcutail = head; | ||
22 | nr_rcuhead++; | ||
23 | if (nr_rcuhead >= 1000) { | ||
24 | int signal = 0; | ||
25 | |||
26 | pthread_mutex_lock(&rculock); | ||
27 | if (!rcuhead_global) | ||
28 | signal = 1; | ||
29 | rcutail->next = rcuhead_global; | ||
30 | rcuhead_global = head; | ||
31 | pthread_mutex_unlock(&rculock); | ||
32 | |||
33 | nr_rcuhead = 0; | ||
34 | rcuhead = NULL; | ||
35 | rcutail = NULL; | ||
36 | |||
37 | if (signal) { | ||
38 | pthread_cond_signal(&rcu_worker_cond); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void *rcu_worker(void *arg) | ||
44 | { | ||
45 | struct rcu_head *r; | ||
46 | |||
47 | rcupdate_thread_init(); | ||
48 | |||
49 | while (1) { | ||
50 | pthread_mutex_lock(&rculock); | ||
51 | while (!rcuhead_global) { | ||
52 | pthread_cond_wait(&rcu_worker_cond, &rculock); | ||
53 | } | ||
54 | r = rcuhead_global; | ||
55 | rcuhead_global = NULL; | ||
56 | |||
57 | pthread_mutex_unlock(&rculock); | ||
58 | |||
59 | synchronize_rcu(); | ||
60 | |||
61 | while (r) { | ||
62 | struct rcu_head *tmp = r->next; | ||
63 | r->func(r); | ||
64 | r = tmp; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | rcupdate_thread_exit(); | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | static pthread_t worker_thread; | ||
74 | void rcupdate_init(void) | ||
75 | { | ||
76 | pthread_create(&worker_thread, NULL, rcu_worker, NULL); | ||
77 | } | ||
78 | |||
79 | void rcupdate_thread_init(void) | ||
80 | { | ||
81 | rcu_register_thread(); | ||
82 | } | ||
83 | void rcupdate_thread_exit(void) | ||
84 | { | ||
85 | rcu_unregister_thread(); | ||
86 | } | ||