Matthew Wilcox | 1366c37 | 2016-03-17 14:21:45 -0700 | [diff] [blame] | 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 | } |