- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.cfa
rac5816d r797a193 5 5 #include <stdlib.hfa> 6 6 7 //----------------------------------------------------------------------------- 8 // info_thread 7 /////////////////////////////////////////////////////////////////// 8 //// info_thread 9 /////////////////////////////////////////////////////////////////// 10 9 11 forall(dtype L | is_blocking_lock(L)) { 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 ) { 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 ) { 28 19 ((Seqable &) this){}; 29 20 this.t = t; 30 21 this.info = info; 31 this.lock = l;32 } 33 34 void ^?{}( info_thread(L) & this ) {}22 this.lock = 0p; 23 } 24 25 void ^?{}( info_thread(L) & this ){ } 35 26 36 27 info_thread(L) *& Back( info_thread(L) * this ) { … … 43 34 } 44 35 45 //----------------------------------------------------------------------------- 46 // Blocking Locks 36 /////////////////////////////////////////////////////////////////// 37 //// Blocking Locks 38 /////////////////////////////////////////////////////////////////// 39 47 40 void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) { 48 41 this.lock{}; … … 56 49 57 50 void ^?{}( blocking_lock & this ) {} 58 void 51 void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };} 59 52 void ^?{}( single_acquisition_lock & this ) {} 60 void 53 void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };} 61 54 void ^?{}( owner_lock & this ) {} 62 void 55 void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };} 63 56 void ^?{}( multiple_acquisition_lock & this ) {} 64 57 65 58 void lock( blocking_lock & this ) with( this ) { 66 59 lock( lock __cfaabi_dbg_ctx2 ); 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 ); 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() ); 75 64 wait_count++; 76 65 unlock( lock ); 77 66 park( ); 78 } 79 // multi acquisition lock is held by current thread 80 else if ( owner == thrd && multi_acquisition ) { 67 } else if ( owner == active_thread() && multi_acquisition ) { // multi acquisition lock is held by current thread 81 68 recursion_count++; 82 69 unlock( lock ); 83 } 84 // lock isn't held 85 else { 86 owner = thrd; 70 } else { // lock isn't held 71 owner = active_thread(); 87 72 recursion_count = 1; 88 73 unlock( lock ); … … 93 78 bool ret = false; 94 79 lock( lock __cfaabi_dbg_ctx2 ); 95 96 // lock isn't held 97 if ( owner == 0p ) { 80 if ( owner == 0p ) { // lock isn't held 98 81 owner = active_thread(); 99 82 recursion_count = 1; 100 83 ret = true; 101 } 102 // multi acquisition lock is held by current thread 103 else if ( owner == active_thread() && multi_acquisition ) { 84 } else if ( owner == active_thread() && multi_acquisition ) { // multi acquisition lock is held by current thread 104 85 recursion_count++; 105 86 ret = true; 106 87 } 107 108 88 unlock( lock ); 109 89 return ret; 90 } 91 92 void unlock_error_check( blocking_lock & this ) with( this ) { 93 if ( owner == 0p ){ // lock isn't held 94 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 } 110 98 } 111 99 … … 120 108 void unlock( blocking_lock & this ) with( this ) { 121 109 lock( lock __cfaabi_dbg_ctx2 ); 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 110 unlock_error_check( this ); 126 111 recursion_count--; 127 if ( recursion_count == 0 ) { 112 if ( recursion_count == 0 ) { // if recursion count is zero release lock and set new owner if one is waiting 128 113 pop_and_set_new_owner( this ); 129 114 } … … 144 129 145 130 void on_notify( blocking_lock & this, $thread * t ) with( this ) { 146 lock( lock __cfaabi_dbg_ctx2 ); 147 // lock held 148 if ( owner != 0p ) { 131 lock( lock __cfaabi_dbg_ctx2 ); 132 if ( owner != 0p ) { // lock held 149 133 addTail( blocked_threads, *t ); 150 134 wait_count++; 151 135 unlock( lock ); 152 } 153 // lock not held 154 else { 136 } else { // lock not held 155 137 owner = t; 156 138 recursion_count = 1; … … 161 143 162 144 void on_wait( blocking_lock & this ) with( 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 145 lock( lock __cfaabi_dbg_ctx2 ); 146 unlock_error_check( this ); 167 147 pop_and_set_new_owner( this ); 168 148 unlock( lock ); 169 149 } 170 150 171 //----------------------------------------------------------------------------- 172 // Overloaded routines for traits 151 /////////////////////////////////////////////////////////////////// 152 //// Overloaded routines for traits 153 /////////////////////////////////////////////////////////////////// 154 173 155 // These routines are temporary until an inheritance bug is fixed 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 ); } 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 ); } 193 176 size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } 194 177 195 //----------------------------------------------------------------------------- 196 // alarm node wrapper 178 /////////////////////////////////////////////////////////////////// 179 //// condition variable 180 /////////////////////////////////////////////////////////////////// 181 197 182 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 ) { }211 183 212 184 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) { 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 ); 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) 223 194 cond->count--; 224 195 if( i->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 ); 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 ); 233 202 } 234 203 235 204 // this casts the alarm node to our wrapped type since we used type erasure 236 205 void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); } 237 }238 239 //-----------------------------------------------------------------------------240 // condition variable241 forall(dtype L | is_blocking_lock(L)) {242 206 243 207 void ?{}( condition_variable(L) & this ){ … … 248 212 249 213 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 ) { } 250 220 251 221 void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) { … … 254 224 count--; 255 225 if (popped.lock) { 256 // if lock passed call on_notify 257 on_notify(*popped.lock, popped.t); 226 on_notify(*popped.lock, popped.t); // if lock passed call on_notify 258 227 } else { 259 // otherwise wake thread 260 unpark(popped.t); 228 unpark(popped.t); // otherwise wake thread 261 229 } 262 230 } … … 290 258 291 259 size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) { 292 // add info_thread to waiting queue 293 addTail( blocked_threads, *i ); 260 addTail( blocked_threads, *i ); // add info_thread to waiting queue 294 261 count++; 295 262 size_t recursion_count = 0; 296 if (i->lock) { 297 // if lock was passed get recursion count to reset to after waking thread 263 if (i->lock) { // if lock was passed get recursion count to reset to after waking thread 298 264 recursion_count = get_recursion_count(*i->lock); 299 265 on_wait( *i->lock ); … … 307 273 size_t recursion_count = queue_and_get_recursion(this, &i); 308 274 unlock( lock ); 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 ); 275 park( ); // blocks here 276 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking 277 } 320 278 321 279 // helper for wait()'s' with a timeout … … 323 281 lock( lock __cfaabi_dbg_ctx2 ); 324 282 size_t recursion_count = queue_and_get_recursion(this, &info); 325 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast, &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; 326 286 register_self( &node_wrap.alarm_node ); 327 287 unlock( lock ); 328 329 // blocks here330 288 park(); 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 ); \ 342 return i.signalled; 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 } 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 ); 306 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 }
Note: See TracChangeset
for help on using the changeset viewer.