#include "locks.hfa" #include "kernel_private.hfa" #include #include #include #include #include /////////////////////////////////////////////////////////////////// //// info_thread /////////////////////////////////////////////////////////////////// forall(dtype L | is_blocking_lock(L)) { void ?{}( info_thread(L) & this, $thread * t ) { this.t = t; this.lock = 0p; } void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) { this.t = t; this.info = info; this.lock = 0p; } void ^?{}( info_thread(L) & this ){ // default } info_thread(L) *& get_next( info_thread(L) & this ) { return this.next; } } /////////////////////////////////////////////////////////////////// //// Blocking Locks /////////////////////////////////////////////////////////////////// void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) { this.lock{}; this.blocked_threads{}; this.wait_count = 0; this.multi_acquisition = multi_acquisition; this.strict_owner = strict_owner; this.owner = 0p; this.recursion_count = 0; } void ^?{}( blocking_lock & this ) { // default } void ?{}( mutex_lock & this ) { ((blocking_lock &)this){ false, false }; } void ^?{}( mutex_lock & this ) { // default } void ?{}( owner_lock & this ) { ((blocking_lock &)this){ true, true }; } void ^?{}( owner_lock & this ) { // default } void ?{}( recursive_mutex_lock & this ) { ((blocking_lock &)this){ true, false }; } void ^?{}( recursive_mutex_lock & this ) { // default } void lock( blocking_lock & this ) with( this ) { lock( lock __cfaabi_dbg_ctx2 ); if ( owner == kernelTLS.this_thread && !multi_acquisition) { fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead exit(EXIT_FAILURE); } else if ( owner != 0p && owner != kernelTLS.this_thread ) { append( blocked_threads, kernelTLS.this_thread ); wait_count++; unlock( lock ); park( __cfaabi_dbg_ctx ); } else if ( owner == kernelTLS.this_thread && multi_acquisition ) { recursion_count++; unlock( lock ); } else { owner = kernelTLS.this_thread; recursion_count = 1; unlock( lock ); } } bool try_lock( blocking_lock & this ) with( this ) { bool ret = false; lock( lock __cfaabi_dbg_ctx2 ); if ( owner == 0p ) { owner = kernelTLS.this_thread; if ( multi_acquisition ) recursion_count = 1; ret = true; } else if ( owner == kernelTLS.this_thread && multi_acquisition ) { recursion_count++; ret = true; } unlock( lock ); return ret; } void unlock( blocking_lock & this ) with( this ) { lock( lock __cfaabi_dbg_ctx2 ); if ( owner == 0p ){ // no owner implies lock isn't held fprintf( stderr, "There was an attempt to release a lock that isn't held" ); return; } else if ( strict_owner && owner != kernelTLS.this_thread ) { fprintf( stderr, "A thread other than the owner attempted to release an owner lock" ); return; } recursion_count--; if ( recursion_count == 0 ) { $thread * thrd = pop_head( blocked_threads ); owner = thrd; recursion_count = ( thrd && multi_acquisition ? 1 : 0 ); wait_count--; unpark( thrd __cfaabi_dbg_ctx2 ); } unlock( lock ); } size_t wait_count( blocking_lock & this ) with( this ) { return wait_count; } void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) { recursion_count = recursion; } size_t get_recursion_count( blocking_lock & this ) with( this ) { return recursion_count; } void add_( blocking_lock & this, $thread * t ) with( this ) { lock( lock __cfaabi_dbg_ctx2 ); if ( owner != 0p ) { append( blocked_threads, t ); wait_count++; unlock( lock ); } else { owner = t; if ( multi_acquisition ) recursion_count = 1; unpark( t __cfaabi_dbg_ctx2 ); unlock( lock ); } } void remove_( blocking_lock & this ) with( this ) { lock( lock __cfaabi_dbg_ctx2 ); if ( owner == 0p ){ // no owner implies lock isn't held fprintf( stderr, "A lock that is not held was passed to a synchronization lock" ); } else if ( strict_owner && owner != kernelTLS.this_thread ) { fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" ); } else { $thread * thrd = pop_head( blocked_threads ); owner = thrd; recursion_count = ( thrd && multi_acquisition ? 1 : 0 ); wait_count--; unpark( thrd __cfaabi_dbg_ctx2 ); } unlock( lock ); } /////////////////////////////////////////////////////////////////// //// Overloaded routines for traits /////////////////////////////////////////////////////////////////// // In an ideal world this may not be necessary // Is it possible for nominal inheritance to inherit traits?? // If that occurs we would avoid all this extra code void lock( mutex_lock & this ){ lock( (blocking_lock &)this ); } void unlock( mutex_lock & this ){ unlock( (blocking_lock &)this ); } void add_( mutex_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); } void remove_( mutex_lock & this ){ remove_( (blocking_lock &)this ); } void set_recursion_count( mutex_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } size_t get_recursion_count( mutex_lock & this ){ get_recursion_count( (blocking_lock &)this ); } void lock( recursive_mutex_lock & this ){ lock( (blocking_lock &)this ); } void unlock( recursive_mutex_lock & this ){ unlock( (blocking_lock &)this ); } void add_( recursive_mutex_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); } void remove_( recursive_mutex_lock & this ){ remove_( (blocking_lock &)this ); } void set_recursion_count( recursive_mutex_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } size_t get_recursion_count( recursive_mutex_lock & this ){ get_recursion_count( (blocking_lock &)this ); } /////////////////////////////////////////////////////////////////// //// Synchronization Locks /////////////////////////////////////////////////////////////////// forall(dtype L | is_blocking_lock(L)) { void ?{}( synchronization_lock(L) & this, bool reacquire_after_signal ){ this.lock{}; this.blocked_threads{}; this.count = 0; this.reacquire_after_signal = reacquire_after_signal; } void ^?{}( synchronization_lock(L) & this ){ // default } void ?{}( condition_variable(L) & this ){ ((synchronization_lock(L) &)this){ true }; } void ^?{}( condition_variable(L) & this ){ // default } void ?{}( thread_queue(L) & this ){ ((synchronization_lock(L) &)this){ false }; } void ^?{}( thread_queue(L) & this ){ // default } bool notify_one( synchronization_lock(L) & this ) with( this ) { lock( lock __cfaabi_dbg_ctx2 ); bool ret = !!blocked_threads; info_thread(L) * popped = pop_head( blocked_threads ); if(popped != 0p) { if( reacquire_after_signal ){ add_(*popped->lock, popped->t); } else { unpark( popped->t __cfaabi_dbg_ctx2 ); } } unlock( lock ); return ret; } bool notify_all( synchronization_lock(L) & this ) with(this) { lock( lock __cfaabi_dbg_ctx2 ); bool ret = blocked_threads ? true : false; while( blocked_threads ) { info_thread(L) * popped = pop_head( blocked_threads ); if(popped != 0p){ if( reacquire_after_signal ){ add_(*popped->lock, popped->t); } else { unpark( popped->t __cfaabi_dbg_ctx2 ); } } } unlock( lock ); return ret; } uintptr_t front( synchronization_lock(L) & this ) with(this) { return (*peek(blocked_threads)).info; } bool empty( synchronization_lock(L) & this ) with(this) { return blocked_threads ? false : true; } int counter( synchronization_lock(L) & this ) with(this) { return count; } void queue_info_thread( synchronization_lock(L) & this, info_thread(L) & i ) with(this) { lock( lock __cfaabi_dbg_ctx2 ); append( blocked_threads, &i ); count++; unlock( lock ); park( __cfaabi_dbg_ctx ); } void wait( synchronization_lock(L) & this ) with(this) { info_thread( L ) i = { kernelTLS.this_thread }; queue_info_thread( this, i ); } void wait( synchronization_lock(L) & this, uintptr_t info ) with(this) { info_thread( L ) i = { kernelTLS.this_thread, info }; queue_info_thread( this, i ); } // I still need to implement the time delay wait routines bool wait( synchronization_lock(L) & this, Duration duration ) with(this) { timeval tv = { time(0) }; Time t = { tv }; return wait( this, t + duration ); } bool wait( synchronization_lock(L) & this, uintptr_t info, Duration duration ) with(this) { // TODO: ADD INFO return wait( this, duration ); } bool wait( synchronization_lock(L) & this, Time time ) with(this) { return false; //default } bool wait( synchronization_lock(L) & this, uintptr_t info, Time time ) with(this) { // TODO: ADD INFO return wait( this, time ); } void queue_info_thread_unlock( synchronization_lock(L) & this, L & l, info_thread(L) & i ) with(this) { lock( lock __cfaabi_dbg_ctx2 ); append( this.blocked_threads, &i ); count++; i.lock = &l; size_t recursion_count = get_recursion_count(l); remove_( l ); unlock( lock ); park( __cfaabi_dbg_ctx ); // blocks here set_recursion_count(l, recursion_count); // resets recursion count here after waking } void wait( synchronization_lock(L) & this, L & l ) with(this) { info_thread(L) i = { kernelTLS.this_thread }; queue_info_thread_unlock( this, l, i ); } void wait( synchronization_lock(L) & this, L & l, uintptr_t info ) with(this) { info_thread(L) i = { kernelTLS.this_thread, info }; queue_info_thread_unlock( this, l, i ); } bool wait( synchronization_lock(L) & this, L & l, Duration duration ) with(this) { timeval tv = { time(0) }; Time t = { tv }; return wait( this, l, t + duration ); } bool wait( synchronization_lock(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { // TODO: ADD INFO return wait( this, l, duration ); } bool wait( synchronization_lock(L) & this, L & l, Time time ) with(this) { return false; //default } bool wait( synchronization_lock(L) & this, L & l, uintptr_t info, Time time ) with(this) { // TODO: ADD INFO return wait( this, l, time ); } } /////////////////////////////////////////////////////////////////// //// condition lock alternative approach /////////////////////////////////////////////////////////////////// // the solution below is less efficient but does not require the lock to have a specific add/remove routine /////////////////////////////////////////////////////////////////// //// is_simple_lock /////////////////////////////////////////////////////////////////// forall(dtype L | is_simple_lock(L)) { void ?{}( condition_lock(L) & this ){ // default } void ^?{}( condition_lock(L) & this ){ // default } bool notify_one( condition_lock(L) & this ) with(this) { return notify_one( c_var ); } bool notify_all( condition_lock(L) & this ) with(this) { return notify_all( c_var ); } void wait( condition_lock(L) & this, L & l ) with(this) { lock( m_lock ); size_t recursion = get_recursion_count( l ); unlock( l ); wait( c_var, m_lock ); lock( l ); set_recursion_count( l , recursion ); unlock( m_lock ); } }