- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.cfa
r797a193 rac5816d 5 5 #include <stdlib.hfa> 6 6 7 /////////////////////////////////////////////////////////////////// 8 //// info_thread 9 /////////////////////////////////////////////////////////////////// 10 7 //----------------------------------------------------------------------------- 8 // info_thread 11 9 forall(dtype L | is_blocking_lock(L)) { 12 void ?{}( info_thread(L) & this, $thread * t ) { 13 ((Seqable &) this){}; 14 this.t = t; 15 this.lock = 0p; 16 } 17 18 void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) { 10 struct info_thread { 11 // used to put info_thread on a dl queue (aka sequence) 12 inline Seqable; 13 14 // waiting thread 15 struct $thread * t; 16 17 // shadow field 18 uintptr_t info; 19 20 // lock that is passed to wait() (if one is passed) 21 L * lock; 22 23 // true when signalled and false when timeout wakes thread 24 bool signalled; 25 }; 26 27 void ?{}( info_thread(L) & this, $thread * t, uintptr_t info, L * l ) { 19 28 ((Seqable &) this){}; 20 29 this.t = t; 21 30 this.info = info; 22 this.lock = 0p;23 } 24 25 void ^?{}( info_thread(L) & this ) {}31 this.lock = l; 32 } 33 34 void ^?{}( info_thread(L) & this ) {} 26 35 27 36 info_thread(L) *& Back( info_thread(L) * this ) { … … 34 43 } 35 44 36 /////////////////////////////////////////////////////////////////// 37 //// Blocking Locks 38 /////////////////////////////////////////////////////////////////// 39 45 //----------------------------------------------------------------------------- 46 // Blocking Locks 40 47 void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) { 41 48 this.lock{}; … … 49 56 50 57 void ^?{}( blocking_lock & this ) {} 51 void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}58 void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };} 52 59 void ^?{}( single_acquisition_lock & this ) {} 53 void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}60 void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };} 54 61 void ^?{}( owner_lock & this ) {} 55 void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}62 void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };} 56 63 void ^?{}( multiple_acquisition_lock & this ) {} 57 64 58 65 void lock( blocking_lock & this ) with( this ) { 59 66 lock( lock __cfaabi_dbg_ctx2 ); 60 if ( owner == active_thread() && !multi_acquisition) { // single acquisition lock is held by current thread 61 abort("A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); 62 } else if ( owner != 0p && owner != active_thread() ) { // lock is held by some other thread 63 addTail( blocked_threads, *active_thread() ); 67 $thread * thrd = active_thread(); 68 69 // single acquisition lock is held by current thread 70 /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this ); 71 72 // lock is held by some other thread 73 if ( owner != 0p && owner != thrd ) { 74 addTail( blocked_threads, *thrd ); 64 75 wait_count++; 65 76 unlock( lock ); 66 77 park( ); 67 } else if ( owner == active_thread() && multi_acquisition ) { // multi acquisition lock is held by current thread 78 } 79 // multi acquisition lock is held by current thread 80 else if ( owner == thrd && multi_acquisition ) { 68 81 recursion_count++; 69 82 unlock( lock ); 70 } else { // lock isn't held 71 owner = active_thread(); 83 } 84 // lock isn't held 85 else { 86 owner = thrd; 72 87 recursion_count = 1; 73 88 unlock( lock ); … … 78 93 bool ret = false; 79 94 lock( lock __cfaabi_dbg_ctx2 ); 80 if ( owner == 0p ) { // lock isn't held 95 96 // lock isn't held 97 if ( owner == 0p ) { 81 98 owner = active_thread(); 82 99 recursion_count = 1; 83 100 ret = true; 84 } else if ( owner == active_thread() && multi_acquisition ) { // multi acquisition lock is held by current thread 101 } 102 // multi acquisition lock is held by current thread 103 else if ( owner == active_thread() && multi_acquisition ) { 85 104 recursion_count++; 86 105 ret = true; 87 106 } 107 88 108 unlock( lock ); 89 109 return ret; 90 }91 92 void unlock_error_check( blocking_lock & this ) with( this ) {93 if ( owner == 0p ){ // lock isn't held94 abort( "There was an attempt to release a lock that isn't held" );95 } else if ( strict_owner && owner != active_thread() ) {96 abort( "A thread other than the owner attempted to release an owner lock" );97 }98 110 } 99 111 … … 108 120 void unlock( blocking_lock & this ) with( this ) { 109 121 lock( lock __cfaabi_dbg_ctx2 ); 110 unlock_error_check( this ); 122 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 123 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 124 125 // if recursion count is zero release lock and set new owner if one is waiting 111 126 recursion_count--; 112 if ( recursion_count == 0 ) { // if recursion count is zero release lock and set new owner if one is waiting127 if ( recursion_count == 0 ) { 113 128 pop_and_set_new_owner( this ); 114 129 } … … 129 144 130 145 void on_notify( blocking_lock & this, $thread * t ) with( this ) { 131 lock( lock __cfaabi_dbg_ctx2 ); 132 if ( owner != 0p ) { // lock held 146 lock( lock __cfaabi_dbg_ctx2 ); 147 // lock held 148 if ( owner != 0p ) { 133 149 addTail( blocked_threads, *t ); 134 150 wait_count++; 135 151 unlock( lock ); 136 } else { // lock not held 152 } 153 // lock not held 154 else { 137 155 owner = t; 138 156 recursion_count = 1; … … 143 161 144 162 void on_wait( blocking_lock & this ) with( this ) { 145 lock( lock __cfaabi_dbg_ctx2 ); 146 unlock_error_check( this ); 163 lock( lock __cfaabi_dbg_ctx2 ); 164 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 165 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 166 147 167 pop_and_set_new_owner( this ); 148 168 unlock( lock ); 149 169 } 150 170 151 /////////////////////////////////////////////////////////////////// 152 //// Overloaded routines for traits 153 /////////////////////////////////////////////////////////////////// 154 171 //----------------------------------------------------------------------------- 172 // Overloaded routines for traits 155 173 // These routines are temporary until an inheritance bug is fixed 156 157 void lock( single_acquisition_lock & this ){ lock( (blocking_lock &)this ); } 158 void unlock( single_acquisition_lock & this ){ unlock( (blocking_lock &)this ); } 159 void on_notify( single_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 160 void on_wait( single_acquisition_lock & this ){ on_wait( (blocking_lock &)this ); } 161 void set_recursion_count( single_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } 162 size_t get_recursion_count( single_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } 163 164 void lock( owner_lock & this ){ lock( (blocking_lock &)this ); } 165 void unlock( owner_lock & this ){ unlock( (blocking_lock &)this ); } 166 void on_notify( owner_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 167 void on_wait( owner_lock & this ){ on_wait( (blocking_lock &)this ); } 168 void set_recursion_count( owner_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } 169 size_t get_recursion_count( owner_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } 170 171 void lock( multiple_acquisition_lock & this ){ lock( (blocking_lock &)this ); } 172 void unlock( multiple_acquisition_lock & this ){ unlock( (blocking_lock &)this ); } 173 void on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 174 void on_wait( multiple_acquisition_lock & this ){ on_wait( (blocking_lock &)this ); } 175 void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } 174 void lock ( single_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 175 void unlock ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 176 void on_wait ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); } 177 void on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 178 void set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); } 179 size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 180 181 void lock ( owner_lock & this ) { lock ( (blocking_lock &)this ); } 182 void unlock ( owner_lock & this ) { unlock ( (blocking_lock &)this ); } 183 void on_wait ( owner_lock & this ) { on_wait( (blocking_lock &)this ); } 184 void on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 185 void set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); } 186 size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 187 188 void lock ( multiple_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 189 void unlock ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 190 void on_wait ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); } 191 void on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 192 void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } 176 193 size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } 177 194 178 /////////////////////////////////////////////////////////////////// 179 //// condition variable 180 /////////////////////////////////////////////////////////////////// 181 195 //----------------------------------------------------------------------------- 196 // alarm node wrapper 182 197 forall(dtype L | is_blocking_lock(L)) { 198 struct alarm_node_wrap { 199 alarm_node_t alarm_node; 200 condition_variable(L) * cond; 201 info_thread(L) * i; 202 }; 203 204 void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) { 205 this.alarm_node{ callback, alarm, period }; 206 this.cond = c; 207 this.i = i; 208 } 209 210 void ^?{}( alarm_node_wrap(L) & this ) { } 183 211 184 212 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) { 185 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin. 186 lock( cond->lock __cfaabi_dbg_ctx2 ); 187 188 // this check is necessary to avoid a race condition since this timeout handler 189 // may still be called after a thread has been removed from the queue but 190 // before the alarm is unregistered 191 if ( listed(i) ) { // is thread on queue 192 i->signalled = false; 193 remove( cond->blocked_threads, *i ); // remove this thread O(1) 213 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin. 214 lock( cond->lock __cfaabi_dbg_ctx2 ); 215 216 // this check is necessary to avoid a race condition since this timeout handler 217 // may still be called after a thread has been removed from the queue but 218 // before the alarm is unregistered 219 if ( listed(i) ) { // is thread on queue 220 i->signalled = false; 221 // remove this thread O(1) 222 remove( cond->blocked_threads, *i ); 194 223 cond->count--; 195 224 if( i->lock ) { 196 on_notify(*i->lock, i->t); // call lock's on_notify if a lock was passed 197 } else { 198 unpark( i->t ); // otherwise wake thread 199 } 200 } 201 unlock( cond->lock ); 225 // call lock's on_notify if a lock was passed 226 on_notify(*i->lock, i->t); 227 } else { 228 // otherwise wake thread 229 unpark( i->t ); 230 } 231 } 232 unlock( cond->lock ); 202 233 } 203 234 204 235 // this casts the alarm node to our wrapped type since we used type erasure 205 236 void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); } 237 } 238 239 //----------------------------------------------------------------------------- 240 // condition variable 241 forall(dtype L | is_blocking_lock(L)) { 206 242 207 243 void ?{}( condition_variable(L) & this ){ … … 212 248 213 249 void ^?{}( condition_variable(L) & this ){ } 214 215 void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback ) {216 this.alarm_node{ callback, alarm, period };217 }218 219 void ^?{}( alarm_node_wrap(L) & this ) { }220 250 221 251 void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) { … … 224 254 count--; 225 255 if (popped.lock) { 226 on_notify(*popped.lock, popped.t); // if lock passed call on_notify 256 // if lock passed call on_notify 257 on_notify(*popped.lock, popped.t); 227 258 } else { 228 unpark(popped.t); // otherwise wake thread 259 // otherwise wake thread 260 unpark(popped.t); 229 261 } 230 262 } … … 258 290 259 291 size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) { 260 addTail( blocked_threads, *i ); // add info_thread to waiting queue 292 // add info_thread to waiting queue 293 addTail( blocked_threads, *i ); 261 294 count++; 262 295 size_t recursion_count = 0; 263 if (i->lock) { // if lock was passed get recursion count to reset to after waking thread 296 if (i->lock) { 297 // if lock was passed get recursion count to reset to after waking thread 264 298 recursion_count = get_recursion_count(*i->lock); 265 299 on_wait( *i->lock ); … … 273 307 size_t recursion_count = queue_and_get_recursion(this, &i); 274 308 unlock( lock ); 275 park( ); // blocks here 276 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking 277 } 309 310 // blocks here 311 park( ); 312 313 // resets recursion count here after waking 314 if (i.lock) set_recursion_count(*i.lock, recursion_count); 315 } 316 317 #define WAIT( u, l ) \ 318 info_thread( L ) i = { active_thread(), u, l }; \ 319 queue_info_thread( this, i ); 278 320 279 321 // helper for wait()'s' with a timeout … … 281 323 lock( lock __cfaabi_dbg_ctx2 ); 282 324 size_t recursion_count = queue_and_get_recursion(this, &info); 283 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast }; 284 node_wrap.cond = &this; 285 node_wrap.i = &info; 325 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast, &this, &info }; 286 326 register_self( &node_wrap.alarm_node ); 287 327 unlock( lock ); 328 329 // blocks here 288 330 park(); 289 unregister_self( &node_wrap.alarm_node ); // unregisters alarm so it doesn't go off if this happens first 290 if (info.lock) set_recursion_count(*info.lock, recursion_count); // resets recursion count here after waking 291 } 292 293 void wait( condition_variable(L) & this ) with(this) { 294 info_thread( L ) i = { active_thread() }; 295 queue_info_thread( this, i ); 296 } 297 298 void wait( condition_variable(L) & this, uintptr_t info ) with(this) { 299 info_thread( L ) i = { active_thread(), info }; 300 queue_info_thread( this, i ); 301 } 302 303 bool wait( condition_variable(L) & this, Duration duration ) with(this) { 304 info_thread( L ) i = { active_thread() }; 305 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 331 332 // unregisters alarm so it doesn't go off if this happens first 333 unregister_self( &node_wrap.alarm_node ); 334 335 // resets recursion count here after waking 336 if (info.lock) set_recursion_count(*info.lock, recursion_count); 337 } 338 339 #define WAIT_TIME( u, l, t ) \ 340 info_thread( L ) i = { active_thread(), u, l }; \ 341 queue_info_thread_timeout(this, i, t ); \ 306 342 return i.signalled; 307 } 308 309 bool wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) { 310 info_thread( L ) i = { active_thread(), info }; 311 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 312 return i.signalled; 313 } 314 315 bool wait( condition_variable(L) & this, Time time ) with(this) { 316 info_thread( L ) i = { active_thread() }; 317 queue_info_thread_timeout(this, i, time); 318 return i.signalled; 319 } 320 321 bool wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) { 322 info_thread( L ) i = { active_thread(), info }; 323 queue_info_thread_timeout(this, i, time); 324 return i.signalled; 325 } 326 327 void wait( condition_variable(L) & this, L & l ) with(this) { 328 info_thread(L) i = { active_thread() }; 329 i.lock = &l; 330 queue_info_thread( this, i ); 331 } 332 333 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { 334 info_thread(L) i = { active_thread(), info }; 335 i.lock = &l; 336 queue_info_thread( this, i ); 337 } 338 339 bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { 340 info_thread(L) i = { active_thread() }; 341 i.lock = &l; 342 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 343 return i.signalled; 344 } 345 346 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { 347 info_thread(L) i = { active_thread(), info }; 348 i.lock = &l; 349 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 350 return i.signalled; 351 } 352 353 bool wait( condition_variable(L) & this, L & l, Time time ) with(this) { 354 info_thread(L) i = { active_thread() }; 355 i.lock = &l; 356 queue_info_thread_timeout(this, i, time ); 357 return i.signalled; 358 } 359 360 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) { 361 info_thread(L) i = { active_thread(), info }; 362 i.lock = &l; 363 queue_info_thread_timeout(this, i, time ); 364 return i.signalled; 365 } 366 } 343 344 void wait( condition_variable(L) & this ) with(this) { WAIT( 0, 0p ) } 345 void wait( condition_variable(L) & this, uintptr_t info ) with(this) { WAIT( info, 0p ) } 346 void wait( condition_variable(L) & this, L & l ) with(this) { WAIT( 0, &l ) } 347 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { WAIT( info, &l ) } 348 349 bool wait( condition_variable(L) & this, Duration duration ) with(this) { WAIT_TIME( 0 , 0p , __kernel_get_time() + duration ) } 350 bool wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, 0p , __kernel_get_time() + duration ) } 351 bool wait( condition_variable(L) & this, Time time ) with(this) { WAIT_TIME( 0 , 0p , time ) } 352 bool wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) { WAIT_TIME( info, 0p , time ) } 353 bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { WAIT_TIME( 0 , &l , __kernel_get_time() + duration ) } 354 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , __kernel_get_time() + duration ) } 355 bool wait( condition_variable(L) & this, L & l, Time time ) with(this) { WAIT_TIME( 0 , &l , time ) } 356 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) { WAIT_TIME( info, &l , time ) } 357 }
Note: See TracChangeset
for help on using the changeset viewer.