Rev 2265 | Rev 2315 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2265 | Rev 2309 | ||
|---|---|---|---|
| Line 41... | Line 41... | ||
| 41 | #include <synch/spinlock.h> |
41 | #include <synch/spinlock.h> |
| 42 | #include <time/delay.h> |
42 | #include <time/delay.h> |
| 43 | #include <panic.h> |
43 | #include <panic.h> |
| 44 | #include <print.h> |
44 | #include <print.h> |
| 45 | 45 | ||
| 46 | typedef struct { |
- | |
| 47 | uint32_t current_batch; |
- | |
| 48 | uint32_t completed_batch; |
- | |
| 49 | bool next_batch_waiting; |
- | |
| 50 | } rcu_global_t; |
46 | SPINLOCK_INITIALIZE(rcu_global_lock); |
| 51 | 47 | ||
| 52 | typedef struct rcu_callback_list { |
48 | typedef struct rcu_callback_list { |
| 53 | struct rcu_callback_list* next; |
49 | struct rcu_callback_list* next; |
| 54 | void (*func)(void*); |
50 | void (*func)(void*); |
| 55 | void* data; |
51 | void* data; |
| 56 | bool* cpu_mask; |
- | |
| 57 | } rcu_callback_list_t; |
52 | } rcu_callback_list_t; |
| 58 | 53 | ||
| 59 | - | ||
| 60 | typedef struct { |
54 | typedef struct { |
| 61 | uint32_t current_batch_number; |
55 | #ifdef CONFIG_SMP |
| 62 | uint32_t QS_passed; |
56 | bool* cpu_mask; |
| 63 | bool QS_pending; |
57 | #endif |
| 64 | rcu_callback_list_t* next_batch, *current_batch, *done_batch; |
58 | rcu_callback_list_t* next_batch, *current_batch, *done_batch; |
| 65 | } rcu_percpu_t; |
59 | } rcu_global_t; |
| - | 60 | ||
| 66 | 61 | ||
| 67 | rcu_global_t _rcu_global; |
62 | rcu_global_t* _rcu_global; |
| 68 | rcu_percpu_t* _rcu_cpu_lists; |
63 | tasklet_descriptor_t* rcu_tasklet_desc; |
| 69 | 64 | ||
| 70 | void rcu_init(void) |
65 | void rcu_init(void) |
| 71 | { |
66 | { |
| - | 67 | #ifdef CONFIG_SMP |
|
| - | 68 | int i; |
|
| - | 69 | #endif |
|
| - | 70 | ||
| 72 | _rcu_cpu_lists = malloc(sizeof(rcu_percpu_t)*config.cpu_count,0); |
71 | _rcu_global = malloc(sizeof(rcu_global_t),0); |
| 73 | _rcu_global.completed_batch = -1; |
72 | _rcu_global->done_batch = NULL; |
| 74 | _rcu_global.current_batch = -1; |
73 | _rcu_global->current_batch = NULL; |
| 75 | _rcu_global.next_batch_waiting = -1; |
74 | _rcu_global->next_batch = NULL; |
| - | 75 | spinlock_initialize(&rcu_global_lock, "rcu_global_lock"); |
|
| - | 76 | ||
| - | 77 | rcu_tasklet_desc = tasklet_register(&rcu_tasklet, NULL); |
|
| - | 78 | tasklet_disable(rcu_tasklet_desc); |
|
| - | 79 | ||
| - | 80 | #ifdef CONFIG_SMP |
|
| - | 81 | _rcu_global->cpu_mask = malloc (sizeof(bool)*config.cpu_count,0); |
|
| - | 82 | for (i=0;i<config.cpu_count;i++) { |
|
| - | 83 | _rcu_global->cpu_mask[i]=false; |
|
| - | 84 | } |
|
| - | 85 | #else |
|
| - | 86 | tasklet_schedule(rcu_tasklet_desc); |
|
| - | 87 | ||
| - | 88 | #endif |
|
| - | 89 | tasklet_enable(rcu_tasklet_desc); |
|
| 76 | } |
90 | } |
| 77 | 91 | ||
| 78 | void rcu_synchronize(void) |
92 | void rcu_synchronize(void) |
| 79 | { |
93 | { |
| - | 94 | #ifdef CONFIG_SMP |
|
| 80 | waitq_t wq; |
95 | waitq_t *wq = malloc(sizeof(waitq_t),0); |
| 81 | waitq_initialize(&wq); |
96 | waitq_initialize(wq); |
| 82 | rcu_sync_callback(rcu_synchronize_callback_function, &wq); |
97 | rcu_sync_callback(&rcu_synchronize_callback_function, wq); |
| - | 98 | printf("going to sleep\n"); |
|
| 83 | waitq_sleep(&wq); |
99 | waitq_sleep(wq); |
| - | 100 | printf("woken up\n"); |
|
| - | 101 | #endif |
|
| 84 | } |
102 | } |
| 85 | 103 | ||
| - | 104 | #ifdef CONFIG_SMP |
|
| 86 | void rcu_synchronize_callback_function(void* waitq) |
105 | void rcu_synchronize_callback_function(void* waitq) |
| 87 | { |
106 | { |
| - | 107 | printf("waking up\n"); |
|
| 88 | waitq_wakeup(((waitq_t*)waitq), true); |
108 | waitq_wakeup(((waitq_t*)waitq), WAKEUP_ALL_INC_MISSED); |
| 89 | } |
109 | } |
| - | 110 | #endif |
|
| 90 | 111 | ||
| 91 | void rcu_sync_callback(void (*func)(void* data), void* data) |
112 | void rcu_sync_callback(void (*func)(void* data), void* data) |
| 92 | { |
113 | { |
| - | 114 | #ifndef CONFIG_SMP |
|
| - | 115 | func(data); |
|
| - | 116 | #else |
|
| 93 | int i; |
117 | int i; |
| 94 | rcu_callback_list_t *rd; |
118 | rcu_callback_list_t *rd; |
| 95 | rd = malloc(sizeof(rcu_callback_list_t), 0); |
119 | rd = malloc(sizeof(rcu_callback_list_t), 0); |
| 96 | rd->func = func; |
120 | rd->func = func; |
| 97 | rd->data = data; |
121 | rd->data = data; |
| 98 | rd->next = NULL; |
122 | rd->next = NULL; |
| - | 123 | printf("synccallback locking \n"); |
|
| - | 124 | spinlock_lock(&rcu_global_lock); |
|
| - | 125 | rd->next = _rcu_global->next_batch; |
|
| - | 126 | _rcu_global->next_batch = rd; |
|
| - | 127 | ||
| - | 128 | if (_rcu_global->current_batch == NULL) { |
|
| - | 129 | _rcu_global->current_batch = _rcu_global->next_batch; |
|
| - | 130 | _rcu_global->next_batch = NULL; |
|
| - | 131 | printf("setting callback %x as current\n",&rd->func); |
|
| - | 132 | for (i=0;i<config.cpu_count;i++) |
|
| - | 133 | _rcu_global->cpu_mask[i]=false; |
|
| 99 | 134 | ||
| 100 | rd->cpu_mask = malloc (sizeof(bool)*config.cpu_count,0); |
135 | //we've surely passed the quiescent point just by running this method |
| 101 | for (i=0;i<config.cpu_count;i++) |
- | |
| 102 | rd->cpu_mask[i]=false; |
136 | rcu_passQS(); |
| 103 | 137 | } |
|
| 104 | i = ++(_rcu_global.current_batch); |
- | |
| 105 | _rcu_global.next_batch_waiting = true; |
- | |
| 106 | - | ||
| 107 | rd->next = _rcu_cpu_lists[0].next_batch; |
- | |
| 108 | for (i=0;i<config.cpu_count;i++) { |
138 | for (i=0;i<config.cpu_count;i++) { |
| - | 139 | tasklet_schedule_SMP(rcu_tasklet_desc, i); |
|
| - | 140 | } |
|
| - | 141 | spinlock_unlock(&rcu_global_lock); |
|
| - | 142 | printf ("sync callback called,unlocking, state:%x \n",rcu_tasklet_desc->state); |
|
| - | 143 | #endif |
|
| - | 144 | } |
|
| - | 145 | ||
| - | 146 | //TODO: polishing, comments |
|
| - | 147 | ||
| - | 148 | void rcu_tasklet(void* data) |
|
| - | 149 | { |
|
| - | 150 | rcu_callback_list_t* rd; |
|
| - | 151 | bool passed_all_QS; |
|
| - | 152 | #ifdef CONFIG_SMP |
|
| - | 153 | int i; |
|
| - | 154 | #endif |
|
| - | 155 | rcu_passQS(); |
|
| - | 156 | passed_all_QS = true; |
|
| - | 157 | printf("tasklet locking \n"); |
|
| - | 158 | spinlock_lock(&rcu_global_lock); |
|
| - | 159 | #ifdef CONFIG_SMP |
|
| - | 160 | ||
| - | 161 | for (i = 0; i < config.cpu_active; i++) |
|
| - | 162 | passed_all_QS &= _rcu_global->cpu_mask[i]; |
|
| - | 163 | #endif |
|
| - | 164 | if (passed_all_QS) { |
|
| 109 | _rcu_cpu_lists[i].next_batch = rd; |
165 | if (_rcu_global->done_batch) { |
| - | 166 | rd = _rcu_global->done_batch; |
|
| - | 167 | while (rd->next) rd = rd->next; |
|
| - | 168 | ||
| - | 169 | //append the current list to done list |
|
| - | 170 | rd->next = _rcu_global->current_batch; |
|
| - | 171 | } else |
|
| - | 172 | _rcu_global->done_batch = _rcu_global->current_batch; |
|
| - | 173 | printf("setting callback %x as done\n",&_rcu_global->current_batch->func); |
|
| 110 | _rcu_cpu_lists[i].QS_pending = true; |
174 | _rcu_global->current_batch = NULL; |
| 111 | } |
175 | } |
| 112 | 176 | ||
| - | 177 | _rcu_global->current_batch = _rcu_global->next_batch; |
|
| - | 178 | _rcu_global->next_batch = NULL; |
|
| - | 179 | ||
| - | 180 | if (_rcu_global->current_batch == NULL) { |
|
| - | 181 | //there are no rcu callbacks registered, there is no need to monitor QS |
|
| - | 182 | printf("tasklet idle disabling \n"); |
|
| 113 | //TODO:tasklet, after_thread_ran, polishing |
183 | // tasklet_disable(rcu_tasklet_desc); |
| - | 184 | spinlock_unlock(&rcu_global_lock); |
|
| - | 185 | } else |
|
| - | 186 | spinlock_unlock(&rcu_global_lock); |
|
| - | 187 | printf("tasklet unlocking \n"); |
|
| 114 | } |
188 | } |
| 115 | 189 | ||
| - | 190 | inline void rcu_passQS(void) |
|
| - | 191 | { |
|
| - | 192 | #ifdef CONFIG_SMP |
|
| - | 193 | _rcu_global->cpu_mask[CPU->id] = true; |
|
| - | 194 | #endif |
|
| - | 195 | } |
|
| - | 196 | ||
| - | 197 | void rcu_run_callbacks(void) |
|
| - | 198 | { |
|
| - | 199 | rcu_callback_list_t* rd; |
|
| - | 200 | rcu_passQS(); |
|
| - | 201 | if (_rcu_global->done_batch) { |
|
| - | 202 | printf("."); |
|
| - | 203 | spinlock_lock(&rcu_global_lock); |
|
| - | 204 | for (rd = _rcu_global->done_batch; rd; rd=rd->next) { |
|
| - | 205 | printf("calling %x \n",&rd->func); |
|
| - | 206 | rd->func(&rd->data); |
|
| - | 207 | } |
|
| - | 208 | _rcu_global->done_batch = NULL; |
|
| - | 209 | spinlock_unlock(&rcu_global_lock); |
|
| - | 210 | printf(":"); |
|
| - | 211 | } |
|
| - | 212 | } |
|
| - | 213 | ||
| - | 214 | ||