Changeset 1b7eec9 in mainline
- Timestamp:
- 2012-12-04T03:48:21Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9a3b469
- Parents:
- cb10bc9
- Location:
- uspace/lib
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/include/futex.h
rcb10bc9 r1b7eec9 40 40 #include <libc.h> 41 41 42 43 #define FUTEX_INITIALIZER {{1}}42 #define FUTEX_INITIALIZE(val) {{(val)}} 43 #define FUTEX_INITIALIZER FUTEX_INITIALIZE(1) 44 44 45 45 typedef struct futex { -
uspace/lib/c/include/sys/time.h
rcb10bc9 r1b7eec9 79 79 80 80 extern void udelay(useconds_t); 81 extern int usleep(useconds_t); 81 82 82 83 extern time_t mktime(struct tm *tm); -
uspace/lib/urcu/rcu.c
rcb10bc9 r1b7eec9 78 78 #include <smp_memory_barrier.h> 79 79 #include <assert.h> 80 #include <time.h> 80 81 81 82 … … 99 100 /** Process global RCU data. */ 100 101 typedef struct rcu_data { 101 fibril_mutex_t mtx;102 102 size_t cur_gp; 103 103 size_t reader_group; 104 104 futex_t list_futex; 105 105 list_t fibrils_list; 106 struct { 107 futex_t futex; 108 bool locked; 109 list_t blocked_fibrils; 110 size_t blocked_thread_cnt; 111 futex_t futex_blocking_threads; 112 } sync_lock; 106 113 } rcu_data_t; 114 115 typedef struct blocked_fibril { 116 fid_t id; 117 link_t link; 118 bool is_ready; 119 } blocked_fibril_t; 107 120 108 121 … … 119 132 /** Process global RCU data. */ 120 133 static rcu_data_t rcu = { 121 .mtx = FIBRIL_MUTEX_INITIALIZER(rcu.mtx),122 134 .cur_gp = 0, 123 135 .reader_group = RCU_GROUP_A, 124 136 .list_futex = FUTEX_INITIALIZER, 125 137 .fibrils_list = LIST_INITIALIZER(rcu.fibrils_list), 138 .sync_lock = { 139 .futex = FUTEX_INITIALIZER, 140 .locked = false, 141 .blocked_fibrils = LIST_INITIALIZER(rcu.sync_lock.blocked_fibrils), 142 .blocked_thread_cnt = 0, 143 .futex_blocking_threads = FUTEX_INITIALIZE(0), 144 }, 126 145 }; 127 146 128 147 129 static void wait_for_readers(size_t reader_group );148 static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode); 130 149 static void force_mb_in_all_threads(void); 131 150 static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group); 151 152 static void lock_sync(blocking_mode_t blocking_mode); 153 static void unlock_sync(void); 154 static void sync_sleep(blocking_mode_t blocking_mode); 132 155 133 156 static bool is_in_group(size_t nesting_cnt, size_t group); … … 145 168 assert(!fibril_rcu.registered); 146 169 147 futex_down(&rcu.list_futex);170 _futex_down(&rcu.list_futex); 148 171 list_append(&fibril_rcu.link, &rcu.fibrils_list); 149 futex_up(&rcu.list_futex);172 _futex_up(&rcu.list_futex); 150 173 151 174 fibril_rcu.registered = true; … … 170 193 fibril_rcu.nesting_cnt = 0; 171 194 172 futex_down(&rcu.list_futex);195 _futex_down(&rcu.list_futex); 173 196 list_remove(&fibril_rcu.link); 174 futex_up(&rcu.list_futex);197 _futex_up(&rcu.list_futex); 175 198 176 199 fibril_rcu.registered = false; … … 214 237 215 238 /** Blocks until all preexisting readers exit their critical sections. */ 216 void rcu_synchronize(void)239 void _rcu_synchronize(blocking_mode_t blocking_mode) 217 240 { 218 241 assert(!rcu_read_locked()); … … 224 247 size_t gp_in_progress = ACCESS_ONCE(rcu.cur_gp); 225 248 226 /* todo: early exit for batched sync()s */ 227 fibril_mutex_lock(&rcu.mtx); 249 lock_sync(blocking_mode); 228 250 229 251 /* … … 236 258 /* rcu.cur_gp >= gp_in_progress + 2, but tolerates overflows. */ 237 259 if (rcu.cur_gp != gp_in_progress && rcu.cur_gp + 1 != gp_in_progress) { 238 fibril_mutex_unlock(&rcu.mtx);260 unlock_sync(); 239 261 return; 240 262 } … … 273 295 274 296 size_t new_reader_group = get_other_group(rcu.reader_group); 275 wait_for_readers(new_reader_group );297 wait_for_readers(new_reader_group, blocking_mode); 276 298 277 299 /* Separates waiting for readers in new_reader_group from group flip. */ … … 285 307 memory_barrier(); 286 308 287 wait_for_readers(old_reader_group );309 wait_for_readers(old_reader_group, blocking_mode); 288 310 289 311 /* MB_FORCE_U */ 290 312 force_mb_in_all_threads(); /* MB_FORCE_U */ 291 313 292 fibril_mutex_unlock(&rcu.mtx);314 unlock_sync(); 293 315 } 294 316 … … 305 327 306 328 /** Waits for readers of reader_group to exit their readers sections. */ 307 static void wait_for_readers(size_t reader_group )308 { 309 futex_down(&rcu.list_futex);329 static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode) 330 { 331 _futex_down(&rcu.list_futex); 310 332 311 333 list_t quiescent_fibrils; … … 318 340 319 341 if (is_preexisting_reader(fib, reader_group)) { 320 futex_up(&rcu.list_futex); 321 async_usleep(RCU_SLEEP_MS * 1000); 322 futex_down(&rcu.list_futex); 342 _futex_up(&rcu.list_futex); 343 sync_sleep(blocking_mode); 344 _futex_down(&rcu.list_futex); 345 /* Break to while loop. */ 323 346 break; 324 347 } else { … … 330 353 331 354 list_concat(&rcu.fibrils_list, &quiescent_fibrils); 332 futex_up(&rcu.list_futex); 333 } 355 _futex_up(&rcu.list_futex); 356 } 357 358 static void lock_sync(blocking_mode_t blocking_mode) 359 { 360 _futex_down(&rcu.sync_lock.futex); 361 if (rcu.sync_lock.locked) { 362 if (blocking_mode == BM_BLOCK_FIBRIL) { 363 blocked_fibril_t blocked_fib; 364 blocked_fib.id = fibril_get_id(); 365 366 list_append(&blocked_fib.link, &rcu.sync_lock.blocked_fibrils); 367 368 do { 369 blocked_fib.is_ready = false; 370 _futex_up(&rcu.sync_lock.futex); 371 fibril_switch(FIBRIL_TO_MANAGER); 372 _futex_down(&rcu.sync_lock.futex); 373 } while (rcu.sync_lock.locked); 374 375 list_remove(&blocked_fib.link); 376 rcu.sync_lock.locked = true; 377 } else { 378 assert(blocking_mode == BM_BLOCK_THREAD); 379 rcu.sync_lock.blocked_thread_cnt++; 380 _futex_up(&rcu.sync_lock.futex); 381 _futex_down(&rcu.sync_lock.futex_blocking_threads); 382 } 383 } else { 384 rcu.sync_lock.locked = true; 385 } 386 } 387 388 static void unlock_sync(void) 389 { 390 assert(rcu.sync_lock.locked); 391 392 /* 393 * Blocked threads have a priority over fibrils when accessing sync(). 394 * Pass the lock onto a waiting thread. 395 */ 396 if (0 < rcu.sync_lock.blocked_thread_cnt) { 397 --rcu.sync_lock.blocked_thread_cnt; 398 _futex_up(&rcu.sync_lock.futex_blocking_threads); 399 } else { 400 /* Unlock but wake up any fibrils waiting for the lock. */ 401 402 if (!list_empty(&rcu.sync_lock.blocked_fibrils)) { 403 blocked_fibril_t *blocked_fib = member_to_inst( 404 list_first(&rcu.sync_lock.blocked_fibrils), blocked_fibril_t, link); 405 406 if (!blocked_fib->is_ready) { 407 blocked_fib->is_ready = true; 408 fibril_add_ready(blocked_fib->id); 409 } 410 } 411 412 rcu.sync_lock.locked = false; 413 _futex_up(&rcu.sync_lock.futex); 414 } 415 } 416 417 static void sync_sleep(blocking_mode_t blocking_mode) 418 { 419 assert(rcu.sync_lock.locked); 420 /* 421 * Release the futex to avoid deadlocks in singlethreaded apps 422 * but keep sync locked. 423 */ 424 _futex_up(&rcu.sync_lock.futex); 425 426 if (blocking_mode == BM_BLOCK_FIBRIL) { 427 async_usleep(RCU_SLEEP_MS * 1000); 428 } else { 429 usleep(RCU_SLEEP_MS * 1000); 430 } 431 432 _futex_down(&rcu.sync_lock.futex); 433 } 434 334 435 335 436 static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group) -
uspace/lib/urcu/rcu.h
rcb10bc9 r1b7eec9 92 92 #define rcu_access(ptr) ACCESS_ONCE(ptr) 93 93 94 typedef enum blocking_mode { 95 BM_BLOCK_FIBRIL, 96 BM_BLOCK_THREAD 97 } blocking_mode_t; 94 98 95 99 extern void rcu_register_fibril(void); … … 101 105 extern bool rcu_read_locked(void); 102 106 103 extern void rcu_synchronize(void); 107 #define rcu_synchronize() _rcu_synchronize(BM_BLOCK_FIBRIL) 108 109 extern void _rcu_synchronize(blocking_mode_t); 104 110 105 111 #endif
Note:
See TracChangeset
for help on using the changeset viewer.