Changes in / [d02e547:660665f]
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/bits/defs.hfa
rd02e547 r660665f 31 31 #ifdef __cforall 32 32 #define __cfa_anonymous_object(x) inline struct x 33 #define __cfa_dlink(x) inline dlink(x) 33 34 #else 34 35 #define __cfa_anonymous_object(x) struct x __cfa_anonymous_object 36 #define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute 35 37 #endif 36 38 -
libcfa/src/bits/weakso_locks.hfa
rd02e547 r660665f 21 21 #include "bits/sequence.hfa" 22 22 #include "bits/containers.hfa" 23 #include "containers/list.hfa" 23 24 24 25 struct $thread; … … 31 32 32 33 // List of blocked threads 33 Sequence( $thread ) blocked_threads;34 dlist( $thread ) blocked_threads; 34 35 35 36 // Count of current blocked threads -
libcfa/src/concurrency/invoke.h
rd02e547 r660665f 20 20 21 21 #ifdef __cforall 22 #include "containers/list.hfa" 22 23 extern "C" { 23 24 #endif … … 198 199 } seqable; 199 200 201 // used to put threads on dlist data structure 202 __cfa_dlink($thread); 203 200 204 struct { 201 205 struct $thread * next; … … 209 213 #endif 210 214 }; 215 #ifdef __cforall 216 P9_EMBEDDED( $thread, dlink($thread) ) 217 #endif 211 218 // Wrapper for gdb 212 219 struct cfathread_thread_t { struct $thread debug; }; … … 238 245 239 246 static inline $thread *& Next( $thread * this ) __attribute__((const)) { 240 return this->seqable.next;247 return this->seqable.next; 241 248 } 242 249 -
libcfa/src/concurrency/locks.cfa
rd02e547 r660665f 28 28 forall(L & | is_blocking_lock(L)) { 29 29 struct info_thread { 30 // used to put info_thread on a dl queue (aka sequence)31 inline Seqable;30 // used to put info_thread on a dl queue 31 inline dlink(info_thread(L)); 32 32 33 33 // waiting thread … … 43 43 bool signalled; 44 44 }; 45 P9_EMBEDDED( info_thread(L), dlink(info_thread(L)) ) 45 46 46 47 void ?{}( info_thread(L) & this, $thread * t, uintptr_t info, L * l ) { 47 ((Seqable &) this){};48 48 this.t = t; 49 49 this.info = info; … … 52 52 53 53 void ^?{}( info_thread(L) & this ) {} 54 55 info_thread(L) *& Back( info_thread(L) * this ) {56 return (info_thread(L) *)Back( (Seqable *)this );57 }58 59 info_thread(L) *& Next( info_thread(L) * this ) {60 return (info_thread(L) *)Next( (Colable *)this );61 }62 54 } 63 55 … … 86 78 // lock is held by some other thread 87 79 if ( owner != 0p && owner != thrd ) { 88 addTail( blocked_threads, *thrd );80 insert_last( blocked_threads, *thrd ); 89 81 wait_count++; 90 82 unlock( lock ); … … 125 117 126 118 void pop_and_set_new_owner( blocking_lock & this ) with( this ) { 127 $thread * t = & dropHead( blocked_threads );119 $thread * t = &try_pop_front( blocked_threads ); 128 120 owner = t; 129 121 recursion_count = ( t ? 1 : 0 ); … … 154 146 // lock held 155 147 if ( owner != 0p ) { 156 addTail( blocked_threads, *t );148 insert_last( blocked_threads, *t ); 157 149 wait_count++; 158 150 unlock( lock ); … … 207 199 // may still be called after a thread has been removed from the queue but 208 200 // before the alarm is unregistered 209 if ( listed(info_thd)) { // is thread on queue201 if ( (*info_thd)`isListed ) { // is thread on queue 210 202 info_thd->signalled = false; 211 203 // remove this thread O(1) 212 remove( cond->blocked_threads,*info_thd );204 remove( *info_thd ); 213 205 cond->count--; 214 206 if( info_thd->lock ) { … … 255 247 bool notify_one( condition_variable(L) & this ) with( this ) { 256 248 lock( lock __cfaabi_dbg_ctx2 ); 257 bool ret = ! empty(blocked_threads);258 process_popped(this, dropHead( blocked_threads ));249 bool ret = ! blocked_threads`isEmpty; 250 process_popped(this, try_pop_front( blocked_threads )); 259 251 unlock( lock ); 260 252 return ret; … … 263 255 bool notify_all( condition_variable(L) & this ) with(this) { 264 256 lock( lock __cfaabi_dbg_ctx2 ); 265 bool ret = ! empty(blocked_threads);266 while( ! empty(blocked_threads)) {267 process_popped(this, dropHead( blocked_threads ));257 bool ret = ! blocked_threads`isEmpty; 258 while( ! blocked_threads`isEmpty ) { 259 process_popped(this, try_pop_front( blocked_threads )); 268 260 } 269 261 unlock( lock ); … … 272 264 273 265 uintptr_t front( condition_variable(L) & this ) with(this) { 274 return empty(blocked_threads) ? NULL : head(blocked_threads).info;266 return blocked_threads`isEmpty ? NULL : blocked_threads`first.info; 275 267 } 276 268 277 269 bool empty( condition_variable(L) & this ) with(this) { 278 270 lock( lock __cfaabi_dbg_ctx2 ); 279 bool ret = empty(blocked_threads);271 bool ret = blocked_threads`isEmpty; 280 272 unlock( lock ); 281 273 return ret; … … 286 278 size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) { 287 279 // add info_thread to waiting queue 288 addTail( blocked_threads, *i );280 insert_last( blocked_threads, *i ); 289 281 count++; 290 282 size_t recursion_count = 0; -
libcfa/src/concurrency/locks.hfa
rd02e547 r660665f 18 18 19 19 #include <stdbool.h> 20 #include <stdio.h> 20 21 21 22 #include "bits/weakso_locks.hfa" 22 23 #include "containers/queueLockFree.hfa" 24 #include "containers/list.hfa" 25 23 26 #include "limits.hfa" 24 27 #include "thread.hfa" … … 40 43 41 44 static inline bool P(Semaphore0nary & this, $thread * thrd) { 42 /* paranoid */ verify(! (thrd->seqable.next));43 /* paranoid */ verify(!( thrd`next));45 /* paranoid */ verify(!thrd`next); 46 /* paranoid */ verify(!(&(*thrd)`next)); 44 47 45 48 push(this.queue, thrd); … … 240 243 } 241 244 245 struct linear_backoff_then_block_lock { 246 // Spin lock used for mutual exclusion 247 __spinlock_t spinlock; 248 249 // Current thread owning the lock 250 struct $thread * owner; 251 252 // List of blocked threads 253 dlist( $thread ) blocked_threads; 254 255 // Used for comparing and exchanging 256 volatile size_t lock_value; 257 258 // used for linear backoff spinning 259 int spin_start; 260 int spin_end; 261 int spin_count; 262 263 // after unsuccessful linear backoff yield this many times 264 int yield_count; 265 }; 266 267 static inline void ?{}( linear_backoff_then_block_lock & this, int spin_start, int spin_end, int spin_count, int yield_count ) { 268 this.spinlock{}; 269 this.blocked_threads{}; 270 this.lock_value = 0; 271 this.spin_start = spin_start; 272 this.spin_end = spin_end; 273 this.spin_count = spin_count; 274 this.yield_count = yield_count; 275 } 276 static inline void ?{}( linear_backoff_then_block_lock & this ) { this{4, 1024, 16, 0}; } 277 static inline void ^?{}( linear_backoff_then_block_lock & this ) {} 278 279 static inline bool internal_try_lock(linear_backoff_then_block_lock & this, size_t & compare_val) with(this) { 280 if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 281 owner = active_thread(); 282 return true; 283 } 284 return false; 285 } 286 287 static inline bool try_lock(linear_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); } 288 289 static inline bool try_lock_contention(linear_backoff_then_block_lock & this) with(this) { 290 if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) { 291 owner = active_thread(); 292 return true; 293 } 294 return false; 295 } 296 297 static inline bool block(linear_backoff_then_block_lock & this) with(this) { 298 lock( spinlock __cfaabi_dbg_ctx2 ); 299 if (lock_value != 2) { 300 unlock( spinlock ); 301 return true; 302 } 303 insert_last( blocked_threads, *active_thread() ); 304 unlock( spinlock ); 305 park( ); 306 return true; 307 } 308 309 static inline bool lock(linear_backoff_then_block_lock & this) with(this) { 310 // if owner just return 311 if (active_thread() == owner) return true; 312 size_t compare_val = 0; 313 int spin = spin_start; 314 // linear backoff 315 for( ;; ) { 316 compare_val = 0; 317 if (internal_try_lock(this, compare_val)) return true; 318 if (2 == compare_val) break; 319 for (int i = 0; i < spin; i++) Pause(); 320 if (spin >= spin_end) break; 321 spin += spin; 322 } 323 324 // linear backoff bounded by spin_count 325 spin = spin_start; 326 int spin_counter = 0; 327 int yield_counter = 0; 328 for ( ;; ) { 329 if(try_lock_contention(this)) return true; 330 if(spin_counter < spin_count) { 331 for (int i = 0; i < spin; i++) Pause(); 332 if (spin < spin_end) spin += spin; 333 else spin_counter++; 334 } else if (yield_counter < yield_count) { 335 // after linear backoff yield yield_count times 336 yield_counter++; 337 yield(); 338 } else { break; } 339 } 340 341 // block until signalled 342 while (block(this)) if(try_lock_contention(this)) return true; 343 344 // this should never be reached as block(this) always returns true 345 return false; 346 } 347 348 static inline void unlock(linear_backoff_then_block_lock & this) with(this) { 349 verify(lock_value > 0); 350 owner = 0p; 351 if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return; 352 lock( spinlock __cfaabi_dbg_ctx2 ); 353 $thread * t = &try_pop_front( blocked_threads ); 354 unlock( spinlock ); 355 unpark( t ); 356 } 357 358 359 void on_notify(linear_backoff_then_block_lock & this, struct $thread * t ) { unpark(t); } 360 size_t on_wait(linear_backoff_then_block_lock & this) { unlock(this); return 0; } 361 void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) { lock(this); } 362 242 363 //----------------------------------------------------------------------------- 243 364 // is_blocking_lock … … 254 375 255 376 //----------------------------------------------------------------------------- 256 // info_thread257 // the info thread is a wrapper around a thread used258 // to store extra data for use in the condition variable377 // // info_thread 378 // // the info thread is a wrapper around a thread used 379 // // to store extra data for use in the condition variable 259 380 forall(L & | is_blocking_lock(L)) { 260 381 struct info_thread; 261 382 262 // for use by sequence263 info_thread(L) *& Back( info_thread(L) * this );264 info_thread(L) *& Next( info_thread(L) * this );383 // // for use by sequence 384 // info_thread(L) *& Back( info_thread(L) * this ); 385 // info_thread(L) *& Next( info_thread(L) * this ); 265 386 } 266 387 … … 273 394 274 395 // List of blocked threads 275 Sequence( info_thread(L) ) blocked_threads;396 dlist( info_thread(L) ) blocked_threads; 276 397 277 398 // Count of current blocked threads 278 399 int count; 279 400 }; 401 280 402 281 403 void ?{}( condition_variable(L) & this ); -
tests/unified_locking/.expect/locks.txt
rd02e547 r660665f 15 15 Start Test 8: fast lock and condition variable 3 wait/notify all 16 16 Done Test 8 17 Start Test 9: multi acquisiton lock and condition variable multiple acquire andwait/notify17 Start Test 9: linear backoff lock and condition variable single wait/notify 18 18 Done Test 9 19 Start Test 10: owner lock and condition variable multiple acquire and wait/notify19 Start Test 10: linear backoff lock and condition variable 3 wait/notify all 20 20 Done Test 10 21 Start Test 11: no lock condition variablewait/notify21 Start Test 11: multi acquisiton lock and condition variable multiple acquire and wait/notify 22 22 Done Test 11 23 Start Test 12: locked condition variable wait/notify with front()23 Start Test 12: owner lock and condition variable multiple acquire and wait/notify 24 24 Done Test 12 25 Start Test 13: no lock condition variable wait/notify 26 Done Test 13 27 Start Test 14: locked condition variable wait/notify with front() 28 Done Test 14 -
tests/unified_locking/locks.cfa
rd02e547 r660665f 18 18 condition_variable( fast_lock ) c_f; 19 19 20 linear_backoff_then_block_lock l; 21 condition_variable( linear_backoff_then_block_lock ) c_l; 22 20 23 thread T_C_M_WS1 {}; 21 24 … … 99 102 } 100 103 unlock(f); 104 } 105 } 106 107 thread T_C_L_WS1 {}; 108 109 void main( T_C_L_WS1 & this ) { 110 for (unsigned int i = 0; i < num_times; i++) { 111 lock(l); 112 if(empty(c_l) && i != num_times - 1) { 113 wait(c_l,l); 114 }else{ 115 notify_one(c_l); 116 } 117 unlock(l); 118 } 119 } 120 121 thread T_C_L_WB1 {}; 122 123 void main( T_C_L_WB1 & this ) { 124 for (unsigned int i = 0; i < num_times; i++) { 125 lock(l); 126 if(counter(c_l) == 3 || i == num_times - 1) { 127 notify_all(c_l); 128 }else{ 129 wait(c_l,l); 130 } 131 unlock(l); 101 132 } 102 133 } … … 298 329 printf("Done Test 8\n"); 299 330 300 printf("Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 331 printf("Start Test 9: linear backoff lock and condition variable single wait/notify\n"); 332 { 333 T_C_L_WS1 t1[2]; 334 } 335 printf("Done Test 9\n"); 336 337 printf("Start Test 10: linear backoff lock and condition variable 3 wait/notify all\n"); 338 { 339 T_C_L_WB1 t1[4]; 340 } 341 printf("Done Test 10\n"); 342 343 printf("Start Test 11: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 301 344 { 302 345 T_C_M_WS2 t1[2]; 303 346 } 304 printf("Done Test 9\n");305 306 printf("Start Test 1 0: owner lock and condition variable multiple acquire and wait/notify\n");347 printf("Done Test 11\n"); 348 349 printf("Start Test 12: owner lock and condition variable multiple acquire and wait/notify\n"); 307 350 { 308 351 T_C_O_WS2 t1[2]; 309 352 } 310 printf("Done Test 1 0\n");311 312 printf("Start Test 1 1: no lock condition variable wait/notify\n");353 printf("Done Test 12\n"); 354 355 printf("Start Test 13: no lock condition variable wait/notify\n"); 313 356 { 314 357 T_C_NLW t1; 315 358 T_C_NLS t2; 316 359 } 317 printf("Done Test 1 1\n");318 319 printf("Start Test 1 2: locked condition variable wait/notify with front()\n");360 printf("Done Test 13\n"); 361 362 printf("Start Test 14: locked condition variable wait/notify with front()\n"); 320 363 { 321 364 T_C_S_WNF t1[2]; 322 365 } 323 printf("Done Test 12\n"); 324 325 // removed to limit test duration. Full test is in long run tests 326 // printf("Start Test 11: unlocked condition variable delay wait\n"); 327 // { 328 // T_C_NLWD t1; 329 // T_C_WDS t2; 330 // } 331 // printf("Done Test 11\n"); 332 333 // printf("Start Test 12: locked condition variable delay wait with unlocked signal\n"); 334 // { 335 // T_C_LWD t1; 336 // T_C_WDS t2; 337 // } 338 // printf("Done Test 12\n"); 339 340 // printf("Start Test 13: locked condition variable delay wait with locked signal\n"); 341 // { 342 // T_C_LWD t1; 343 // T_C_LWDS t2; 344 // } 345 // printf("Done Test 13\n"); 346 } 366 printf("Done Test 14\n"); 367 }
Note: See TracChangeset
for help on using the changeset viewer.