Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/locks.cfa

    r5a05946 rf5f2768  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // locks.cfa -- LIBCFATHREAD
     7// locks.hfa -- LIBCFATHREAD
    88// Runtime locks that used with the runtime thread system.
    99//
     
    7979        // lock is held by some other thread
    8080        if ( owner != 0p && owner != thrd ) {
    81         select_node node;
    82                 insert_last( blocked_threads, node );
     81                insert_last( blocked_threads, *thrd );
    8382                wait_count++;
    8483                unlock( lock );
    8584                park( );
    86         return;
    87         } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
     85        }
     86        // multi acquisition lock is held by current thread
     87        else if ( owner == thrd && multi_acquisition ) {
    8888                recursion_count++;
    89         } else {  // lock isn't held
     89                unlock( lock );
     90        }
     91        // lock isn't held
     92        else {
    9093                owner = thrd;
    9194                recursion_count = 1;
    92         }
    93     unlock( lock );
     95                unlock( lock );
     96        }
    9497}
    9598
     
    114117}
    115118
    116 static inline void pop_node( blocking_lock & this ) with( this ) {
    117     __handle_waituntil_OR( blocked_threads );
    118     select_node * node = &try_pop_front( blocked_threads );
    119     if ( node ) {
    120         wait_count--;
    121         owner = node->blocked_thread;
    122         recursion_count = 1;
    123         // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread );
    124         wake_one( blocked_threads, *node );
    125     } else {
    126         owner = 0p;
    127         recursion_count = 0;
    128     }
     119static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
     120        thread$ * t = &try_pop_front( blocked_threads );
     121        owner = t;
     122        recursion_count = ( t ? 1 : 0 );
     123        if ( t ) wait_count--;
     124        unpark( t );
    129125}
    130126
     
    138134        recursion_count--;
    139135        if ( recursion_count == 0 ) {
    140                 pop_node( this );
     136                pop_and_set_new_owner( this );
    141137        }
    142138        unlock( lock );
     
    151147        // lock held
    152148        if ( owner != 0p ) {
    153                 insert_last( blocked_threads, *(select_node *)t->link_node );
     149                insert_last( blocked_threads, *t );
    154150                wait_count++;
     151                unlock( lock );
    155152        }
    156153        // lock not held
     
    159156                recursion_count = 1;
    160157                unpark( t );
    161         }
    162     unlock( lock );
    163 }
    164 
    165 size_t on_wait( blocking_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) with( this ) {
     158                unlock( lock );
     159        }
     160}
     161
     162size_t on_wait( blocking_lock & this ) with( this ) {
    166163        lock( lock __cfaabi_dbg_ctx2 );
    167164        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    170167        size_t ret = recursion_count;
    171168
    172         pop_node( this );
    173 
    174     select_node node;
    175     active_thread()->link_node = (void *)&node;
     169        pop_and_set_new_owner( this );
    176170        unlock( lock );
    177 
    178     pre_park_then_park( pp_fn, pp_datum );
    179 
    180171        return ret;
    181172}
     
    184175        recursion_count = recursion;
    185176}
    186 
    187 // waituntil() support
    188 bool register_select( blocking_lock & this, select_node & node ) with(this) {
    189     lock( lock __cfaabi_dbg_ctx2 );
    190         thread$ * thrd = active_thread();
    191 
    192         // single acquisition lock is held by current thread
    193         /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this );
    194 
    195     if ( !node.park_counter && ( (owner == thrd && multi_acquisition) || owner == 0p ) ) { // OR special case
    196         if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
    197            unlock( lock );
    198            return false;
    199         }
    200     }
    201 
    202         // lock is held by some other thread
    203         if ( owner != 0p && owner != thrd ) {
    204                 insert_last( blocked_threads, node );
    205                 wait_count++;
    206                 unlock( lock );
    207         return false;
    208         } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
    209                 recursion_count++;
    210         } else {  // lock isn't held
    211                 owner = thrd;
    212                 recursion_count = 1;
    213         }
    214 
    215     if ( node.park_counter ) __make_select_node_available( node );
    216     unlock( lock );
    217     return true;
    218 }
    219 
    220 bool unregister_select( blocking_lock & this, select_node & node ) with(this) {
    221     lock( lock __cfaabi_dbg_ctx2 );
    222     if ( node`isListed ) {
    223         remove( node );
    224         wait_count--;
    225         unlock( lock );
    226         return false;
    227     }
    228    
    229     if ( owner == active_thread() ) {
    230         /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to unlock owner lock %p in waituntil unregister, which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count );
    231         // if recursion count is zero release lock and set new owner if one is waiting
    232         recursion_count--;
    233         if ( recursion_count == 0 ) {
    234             pop_node( this );
    235         }
    236     }
    237         unlock( lock );
    238     return false;
    239 }
    240 
    241 bool on_selected( blocking_lock & this, select_node & node ) { return true; }
    242177
    243178//-----------------------------------------------------------------------------
     
    376311        int counter( condition_variable(L) & this ) with(this) { return count; }
    377312
    378         static void enqueue_thread( condition_variable(L) & this, info_thread(L) * i ) with(this) {
     313        static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    379314                // add info_thread to waiting queue
    380315                insert_last( blocked_threads, *i );
    381316                count++;
    382         }
    383 
    384     static size_t block_and_get_recursion( info_thread(L) & i, __cfa_pre_park pp_fn, void * pp_datum ) {
    385         size_t recursion_count = 0;
    386                 if ( i.lock ) // if lock was passed get recursion count to reset to after waking thread
    387                         recursion_count = on_wait( *i.lock, pp_fn, pp_datum ); // this call blocks
    388                 else
    389             pre_park_then_park( pp_fn, pp_datum );
    390         return recursion_count;
    391     }
    392     static size_t block_and_get_recursion( info_thread(L) & i ) { return block_and_get_recursion( i, pre_park_noop, 0p ); }
     317                size_t recursion_count = 0;
     318                if (i->lock) {
     319                        // if lock was passed get recursion count to reset to after waking thread
     320                        recursion_count = on_wait( *i->lock );
     321                }
     322                return recursion_count;
     323        }
    393324
    394325        // helper for wait()'s' with no timeout
    395326        static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
    396327                lock( lock __cfaabi_dbg_ctx2 );
    397         enqueue_thread( this, &i );
     328                size_t recursion_count = queue_and_get_recursion(this, &i);
    398329                unlock( lock );
    399330
    400331                // blocks here
    401         size_t recursion_count = block_and_get_recursion( i );
     332                park( );
    402333
    403334                // resets recursion count here after waking
    404                 if ( i.lock ) on_wakeup( *i.lock, recursion_count );
     335                if (i.lock) on_wakeup(*i.lock, recursion_count);
    405336        }
    406337
     
    409340                queue_info_thread( this, i );
    410341
    411     static void cond_alarm_register( void * node_ptr ) { register_self( (alarm_node_t *)node_ptr ); }
    412 
    413342        // helper for wait()'s' with a timeout
    414343        static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    415344                lock( lock __cfaabi_dbg_ctx2 );
    416         enqueue_thread( this, &info );
     345                size_t recursion_count = queue_and_get_recursion(this, &info);
    417346                alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    418347                unlock( lock );
    419348
    420                 // blocks here and registers alarm node before blocking after releasing locks to avoid deadlock
    421         size_t recursion_count = block_and_get_recursion( info, cond_alarm_register, (void *)(&node_wrap.alarm_node) );
    422                 // park();
     349                // registers alarm outside cond lock to avoid deadlock
     350                register_self( &node_wrap.alarm_node );
     351
     352                // blocks here
     353                park();
    423354
    424355                // unregisters alarm so it doesn't go off if this happens first
     
    426357
    427358                // resets recursion count here after waking
    428                 if ( info.lock ) on_wakeup( *info.lock, recursion_count );
     359                if (info.lock) on_wakeup(*info.lock, recursion_count);
    429360        }
    430361
     
    486417                info_thread( L ) i = { active_thread(), info, &l };
    487418                insert_last( blocked_threads, i );
    488                 size_t recursion_count = on_wait( *i.lock, pre_park_noop, 0p ); // blocks here
    489                 // park( );
     419                size_t recursion_count = on_wait( *i.lock );
     420                park( );
    490421                on_wakeup(*i.lock, recursion_count);
    491422        }
     
    528459        bool empty ( pthread_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
    529460
     461        static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) {
     462                // add info_thread to waiting queue
     463                insert_last( blocked_threads, *i );
     464                size_t recursion_count = 0;
     465                recursion_count = on_wait( *i->lock );
     466                return recursion_count;
     467        }
     468       
    530469        static void queue_info_thread_timeout( pthread_cond_var(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    531470                lock( lock __cfaabi_dbg_ctx2 );
    532         insert_last( blocked_threads, info );
     471                size_t recursion_count = queue_and_get_recursion(this, &info);
    533472                pthread_alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    534473                unlock( lock );
    535474
    536                 // blocks here and registers alarm node before blocking after releasing locks to avoid deadlock
    537         size_t recursion_count = block_and_get_recursion( info, cond_alarm_register, (void *)(&node_wrap.alarm_node) );
    538 
    539                 // unregisters alarm so it doesn't go off if signal happens first
     475                // registers alarm outside cond lock to avoid deadlock
     476                register_self( &node_wrap.alarm_node );
     477
     478                // blocks here
     479                park();
     480
     481                // unregisters alarm so it doesn't go off if this happens first
    540482                unregister_self( &node_wrap.alarm_node );
    541483
    542484                // resets recursion count here after waking
    543                 if ( info.lock ) on_wakeup( *info.lock, recursion_count );
     485                if (info.lock) on_wakeup(*info.lock, recursion_count);
    544486        }
    545487
     
    551493                lock( lock __cfaabi_dbg_ctx2 );
    552494                info_thread( L ) i = { active_thread(), info, &l };
    553         insert_last( blocked_threads, i );
    554                 unlock( lock );
    555 
    556         // blocks here
    557                 size_t recursion_count = block_and_get_recursion( i );
    558 
    559                 on_wakeup( *i.lock, recursion_count );
     495                size_t recursion_count = queue_and_get_recursion(this, &i);
     496                unlock( lock );
     497                park( );
     498                on_wakeup(*i.lock, recursion_count);
    560499        }
    561500
     
    645584        return thrd != 0p;
    646585}
    647 
Note: See TracChangeset for help on using the changeset viewer.