Changeset 139775e for libcfa/src/concurrency/locks.cfa
- Timestamp:
- Nov 6, 2020, 4:48:52 PM (4 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 75baaa3
- Parents:
- 55acc3a (diff), 836c9925 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.cfa
r55acc3a r139775e 15 15 this.t = t; 16 16 this.lock = 0p; 17 this.listed = false; 17 18 } 18 19 … … 21 22 this.info = info; 22 23 this.lock = 0p; 24 this.listed = false; 23 25 } 24 26 … … 74 76 75 77 void lock( blocking_lock & this ) with( this ) { 78 $thread * thrd = active_thread(); 76 79 lock( lock __cfaabi_dbg_ctx2 ); 77 if ( owner == kernelTLS.this_thread && !multi_acquisition) {80 if ( owner == thrd && !multi_acquisition) { 78 81 fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead 79 80 } else if ( owner != 0p && owner != kernelTLS.this_thread ) {81 append( blocked_threads, kernelTLS.this_thread );82 exit(EXIT_FAILURE); 83 } else if ( owner != 0p && owner != thrd ) { 84 append( blocked_threads, thrd ); 82 85 wait_count++; 83 86 unlock( lock ); 84 park( __cfaabi_dbg_ctx);85 } else if ( owner == kernelTLS.this_thread && multi_acquisition ) {87 park( ); 88 } else if ( owner == thrd && multi_acquisition ) { 86 89 recursion_count++; 87 90 unlock( lock ); 88 91 } else { 89 owner = kernelTLS.this_thread;92 owner = thrd; 90 93 recursion_count = 1; 91 94 unlock( lock ); … … 94 97 95 98 bool try_lock( blocking_lock & this ) with( this ) { 99 $thread * thrd = active_thread(); 96 100 bool ret = false; 97 101 lock( lock __cfaabi_dbg_ctx2 ); 98 102 if ( owner == 0p ) { 99 owner = kernelTLS.this_thread;103 owner = thrd; 100 104 if ( multi_acquisition ) recursion_count = 1; 101 105 ret = true; 102 } else if ( owner == kernelTLS.this_thread && multi_acquisition ) {106 } else if ( owner == thrd && multi_acquisition ) { 103 107 recursion_count++; 104 108 ret = true; … … 113 117 fprintf( stderr, "There was an attempt to release a lock that isn't held" ); 114 118 return; 115 } else if ( strict_owner && owner != kernelTLS.this_thread) {119 } else if ( strict_owner && active_thread() ) { 116 120 fprintf( stderr, "A thread other than the owner attempted to release an owner lock" ); 117 121 return; … … 123 127 recursion_count = ( thrd && multi_acquisition ? 1 : 0 ); 124 128 wait_count--; 125 unpark( thrd __cfaabi_dbg_ctx2);129 unpark( thrd ); 126 130 } 127 131 unlock( lock ); … … 150 154 owner = t; 151 155 if ( multi_acquisition ) recursion_count = 1; 152 unpark( t __cfaabi_dbg_ctx2 ); 156 #if !defined( __CFA_NO_STATISTICS__ ) 157 kernelTLS.this_stats = t->curr_cluster->stats; 158 #endif 159 unpark( t ); 153 160 unlock( lock ); 154 161 } … … 159 166 if ( owner == 0p ){ // no owner implies lock isn't held 160 167 fprintf( stderr, "A lock that is not held was passed to a synchronization lock" ); 161 } else if ( strict_owner && owner != kernelTLS.this_thread) {168 } else if ( strict_owner && active_thread() ) { 162 169 fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" ); 163 170 } else { … … 166 173 recursion_count = ( thrd && multi_acquisition ? 1 : 0 ); 167 174 wait_count--; 168 unpark( thrd __cfaabi_dbg_ctx2);175 unpark( thrd ); 169 176 } 170 177 unlock( lock ); … … 175 182 /////////////////////////////////////////////////////////////////// 176 183 177 // In an ideal world this may not be necessary 178 // Is it possible for nominal inheritance to inherit traits?? 179 // If that occurs we would avoid all this extra code 184 // This is temporary until an inheritance bug is fixed 180 185 181 186 void lock( mutex_lock & this ){ … … 228 233 229 234 /////////////////////////////////////////////////////////////////// 230 //// Synchronization Locks235 //// condition variable 231 236 /////////////////////////////////////////////////////////////////// 232 237 233 238 forall(dtype L | is_blocking_lock(L)) { 234 void ?{}( synchronization_lock(L) & this, bool reacquire_after_signal ){ 239 240 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) { 241 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin. 242 lock( cond->lock __cfaabi_dbg_ctx2 ); 243 if ( (*i)->listed ) { // is thread on queue 244 info_thread(L) * copy = *i; 245 remove( cond->blocked_threads, i ); //remove this thread O(1) 246 cond->wait_count--; 247 if( !copy->lock ) { 248 unlock( cond->lock ); 249 #if !defined( __CFA_NO_STATISTICS__ ) 250 #warning unprotected access to tls TODO discuss this 251 kernelTLS.this_stats = copy->t->curr_cluster->stats; 252 #endif 253 unpark( copy->t ); 254 } else { 255 add_(*copy->lock, copy->t); // call lock's add_ 256 } 257 } 258 unlock( cond->lock ); 259 } 260 261 void alarm_node_wrap_cast( alarm_node_t & a ) { 262 timeout_handler( (alarm_node_wrap(L) &)a ); 263 } 264 265 void ?{}( condition_variable(L) & this ){ 235 266 this.lock{}; 236 267 this.blocked_threads{}; 237 268 this.count = 0; 238 this.reacquire_after_signal = reacquire_after_signal;239 }240 241 void ^?{}( synchronization_lock(L) & this ){242 // default243 }244 245 void ?{}( condition_variable(L) & this ){246 ((synchronization_lock(L) &)this){ true };247 269 } 248 270 … … 251 273 } 252 274 253 void ?{}( thread_queue(L) & this ){254 ((synchronization_lock(L) &)this){ false};255 } 256 257 void ^?{}( thread_queue(L) & this ){275 void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) { 276 this.alarm_node{ thrd, alarm, period, callback }; 277 } 278 279 void ^?{}( alarm_node_wrap(L) & this ) { 258 280 // default 259 281 } 260 282 261 bool notify_one( synchronization_lock(L) & this ) with( this ) {283 bool notify_one( condition_variable(L) & this ) with( this ) { 262 284 lock( lock __cfaabi_dbg_ctx2 ); 263 285 bool ret = !!blocked_threads; 264 286 info_thread(L) * popped = pop_head( blocked_threads ); 287 popped->listed = false; 265 288 if(popped != 0p) { 266 if( reacquire_after_signal ){ 289 count--; 290 if (popped->lock) { 267 291 add_(*popped->lock, popped->t); 268 292 } else { 269 unpark( 270 popped->t __cfaabi_dbg_ctx2 271 ); 293 unpark(popped->t); 272 294 } 273 295 } … … 276 298 } 277 299 278 bool notify_all( synchronization_lock(L) & this ) with(this) {300 bool notify_all( condition_variable(L) & this ) with(this) { 279 301 lock( lock __cfaabi_dbg_ctx2 ); 280 302 bool ret = blocked_threads ? true : false; 281 303 while( blocked_threads ) { 282 304 info_thread(L) * popped = pop_head( blocked_threads ); 305 popped->listed = false; 283 306 if(popped != 0p){ 284 if( reacquire_after_signal ){ 307 count--; 308 if (popped->lock) { 285 309 add_(*popped->lock, popped->t); 286 310 } else { 287 unpark( 288 popped->t __cfaabi_dbg_ctx2 289 ); 311 unpark(popped->t); 290 312 } 291 313 } … … 295 317 } 296 318 297 uintptr_t front( synchronization_lock(L) & this ) with(this) { 298 return (*peek(blocked_threads)).info; 299 } 300 301 bool empty( synchronization_lock(L) & this ) with(this) { 319 uintptr_t front( condition_variable(L) & this ) with(this) { 320 if(!blocked_threads) return NULL; 321 return peek(blocked_threads)->info; 322 } 323 324 bool empty( condition_variable(L) & this ) with(this) { 302 325 return blocked_threads ? false : true; 303 326 } 304 327 305 int counter( synchronization_lock(L) & this ) with(this) {328 int counter( condition_variable(L) & this ) with(this) { 306 329 return count; 307 330 } 308 331 309 void queue_info_thread( synchronization_lock(L) & this, info_thread(L) & i ) with(this) { 310 lock( lock __cfaabi_dbg_ctx2 ); 311 append( blocked_threads, &i ); 312 count++; 313 unlock( lock ); 314 park( __cfaabi_dbg_ctx ); 315 } 316 317 318 void wait( synchronization_lock(L) & this ) with(this) { 319 info_thread( L ) i = { kernelTLS.this_thread }; 320 queue_info_thread( this, i ); 321 } 322 323 void wait( synchronization_lock(L) & this, uintptr_t info ) with(this) { 324 info_thread( L ) i = { kernelTLS.this_thread, info }; 325 queue_info_thread( this, i ); 326 } 327 // I still need to implement the time delay wait routines 328 bool wait( synchronization_lock(L) & this, Duration duration ) with(this) { 329 timeval tv = { time(0) }; 330 Time t = { tv }; 331 return wait( this, t + duration ); 332 } 333 334 bool wait( synchronization_lock(L) & this, uintptr_t info, Duration duration ) with(this) { 335 // TODO: ADD INFO 336 return wait( this, duration ); 337 } 338 339 bool wait( synchronization_lock(L) & this, Time time ) with(this) { 340 return false; //default 341 } 342 343 bool wait( synchronization_lock(L) & this, uintptr_t info, Time time ) with(this) { 344 // TODO: ADD INFO 345 return wait( this, time ); 346 } 347 348 void queue_info_thread_unlock( synchronization_lock(L) & this, L & l, info_thread(L) & i ) with(this) { 332 // helper for wait()'s' without a timeout 333 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) { 349 334 lock( lock __cfaabi_dbg_ctx2 ); 350 335 append( this.blocked_threads, &i ); 351 336 count++; 352 i.lock = &l; 353 size_t recursion_count = get_recursion_count(l); 354 remove_( l ); 355 unlock( lock ); 356 park( __cfaabi_dbg_ctx ); // blocks here 357 358 set_recursion_count(l, recursion_count); // resets recursion count here after waking 359 } 360 361 void wait( synchronization_lock(L) & this, L & l ) with(this) { 362 info_thread(L) i = { kernelTLS.this_thread }; 363 queue_info_thread_unlock( this, l, i ); 364 } 365 366 void wait( synchronization_lock(L) & this, L & l, uintptr_t info ) with(this) { 367 info_thread(L) i = { kernelTLS.this_thread, info }; 368 queue_info_thread_unlock( this, l, i ); 369 } 370 371 bool wait( synchronization_lock(L) & this, L & l, Duration duration ) with(this) { 372 timeval tv = { time(0) }; 373 Time t = { tv }; 374 return wait( this, l, t + duration ); 375 } 376 377 bool wait( synchronization_lock(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { 378 // TODO: ADD INFO 379 return wait( this, l, duration ); 380 } 381 382 bool wait( synchronization_lock(L) & this, L & l, Time time ) with(this) { 383 return false; //default 384 } 385 386 bool wait( synchronization_lock(L) & this, L & l, uintptr_t info, Time time ) with(this) { 387 // TODO: ADD INFO 388 return wait( this, l, time ); 389 } 390 } 391 392 /////////////////////////////////////////////////////////////////// 393 //// condition lock alternative approach 394 /////////////////////////////////////////////////////////////////// 395 396 // the solution below is less efficient but does not require the lock to have a specific add/remove routine 397 398 /////////////////////////////////////////////////////////////////// 399 //// is_simple_lock 400 /////////////////////////////////////////////////////////////////// 401 402 forall(dtype L | is_simple_lock(L)) { 403 void ?{}( condition_lock(L) & this ){ 404 // default 405 } 406 407 void ^?{}( condition_lock(L) & this ){ 408 // default 409 } 410 411 bool notify_one( condition_lock(L) & this ) with(this) { 412 return notify_one( c_var ); 413 } 414 415 bool notify_all( condition_lock(L) & this ) with(this) { 416 return notify_all( c_var ); 417 } 418 419 void wait( condition_lock(L) & this, L & l ) with(this) { 420 lock( m_lock ); 421 size_t recursion = get_recursion_count( l ); 422 unlock( l ); 423 wait( c_var, m_lock ); 424 lock( l ); 425 set_recursion_count( l , recursion ); 426 unlock( m_lock ); 427 } 428 } 337 i.listed = true; 338 size_t recursion_count; 339 if (i.lock) { 340 recursion_count = get_recursion_count(*i.lock); 341 remove_( *i.lock ); 342 } 343 344 unlock( lock ); 345 park( ); // blocks here 346 347 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking 348 } 349 350 // helper for wait()'s' with a timeout 351 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) { 352 lock( lock __cfaabi_dbg_ctx2 ); 353 354 info_thread(L) * queue_ptr = &info; 355 356 alarm_node_wrap(L) node_wrap = { info.t, t, 0`s, alarm_node_wrap_cast }; 357 node_wrap.cond = &this; 358 node_wrap.i = &queue_ptr; 359 360 register_self( &node_wrap.alarm_node ); 361 362 append( blocked_threads, queue_ptr ); 363 info.listed = true; 364 count++; 365 366 size_t recursion_count; 367 if (info.lock) { 368 recursion_count = get_recursion_count(*info.lock); 369 remove_( *info.lock ); 370 } 371 372 unlock( lock ); 373 park(); 374 375 if (info.lock) set_recursion_count(*info.lock, recursion_count); 376 } 377 378 void wait( condition_variable(L) & this ) with(this) { 379 info_thread( L ) i = { active_thread() }; 380 queue_info_thread( this, i ); 381 } 382 383 void wait( condition_variable(L) & this, uintptr_t info ) with(this) { 384 info_thread( L ) i = { active_thread(), info }; 385 queue_info_thread( this, i ); 386 } 387 388 void wait( condition_variable(L) & this, Duration duration ) with(this) { 389 info_thread( L ) i = { active_thread() }; 390 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 391 } 392 393 void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) { 394 info_thread( L ) i = { active_thread(), info }; 395 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 396 } 397 398 void wait( condition_variable(L) & this, Time time ) with(this) { 399 info_thread( L ) i = { active_thread() }; 400 queue_info_thread_timeout(this, i, time); 401 } 402 403 void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) { 404 info_thread( L ) i = { active_thread(), info }; 405 queue_info_thread_timeout(this, i, time); 406 } 407 408 void wait( condition_variable(L) & this, L & l ) with(this) { 409 info_thread(L) i = { active_thread() }; 410 i.lock = &l; 411 queue_info_thread( this, i ); 412 } 413 414 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { 415 info_thread(L) i = { active_thread(), info }; 416 i.lock = &l; 417 queue_info_thread( this, i ); 418 } 419 420 void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { 421 info_thread(L) i = { active_thread() }; 422 i.lock = &l; 423 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 424 } 425 426 void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { 427 info_thread(L) i = { active_thread(), info }; 428 i.lock = &l; 429 queue_info_thread_timeout(this, i, __kernel_get_time() + duration ); 430 } 431 432 void wait( condition_variable(L) & this, L & l, Time time ) with(this) { 433 info_thread(L) i = { active_thread() }; 434 i.lock = &l; 435 queue_info_thread_timeout(this, i, time ); 436 } 437 438 void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) { 439 info_thread(L) i = { active_thread(), info }; 440 i.lock = &l; 441 queue_info_thread_timeout(this, i, time ); 442 } 443 }
Note: See TracChangeset
for help on using the changeset viewer.