Ignore:
File:
1 edited

Legend:

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

    r70a4ed5 r7d9598d8  
    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//
     
    1616
    1717#define __cforall_thread__
     18#define _GNU_SOURCE
    1819
    1920#include "locks.hfa"
     
    7980        // lock is held by some other thread
    8081        if ( owner != 0p && owner != thrd ) {
    81         select_node node;
    82                 insert_last( blocked_threads, node );
     82                insert_last( blocked_threads, *thrd );
    8383                wait_count++;
    8484                unlock( lock );
    8585                park( );
    86         return;
    87         } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
     86        }
     87        // multi acquisition lock is held by current thread
     88        else if ( owner == thrd && multi_acquisition ) {
    8889                recursion_count++;
    89         } else {  // lock isn't held
     90                unlock( lock );
     91        }
     92        // lock isn't held
     93        else {
    9094                owner = thrd;
    9195                recursion_count = 1;
    92         }
    93     unlock( lock );
     96                unlock( lock );
     97        }
    9498}
    9599
     
    114118}
    115119
    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     }
     120static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
     121        thread$ * t = &try_pop_front( blocked_threads );
     122        owner = t;
     123        recursion_count = ( t ? 1 : 0 );
     124        if ( t ) wait_count--;
     125        unpark( t );
    129126}
    130127
     
    138135        recursion_count--;
    139136        if ( recursion_count == 0 ) {
    140                 pop_node( this );
     137                pop_and_set_new_owner( this );
    141138        }
    142139        unlock( lock );
     
    151148        // lock held
    152149        if ( owner != 0p ) {
    153                 insert_last( blocked_threads, *(select_node *)t->link_node );
     150                insert_last( blocked_threads, *t );
    154151                wait_count++;
     152                unlock( lock );
    155153        }
    156154        // lock not held
     
    159157                recursion_count = 1;
    160158                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 ) {
     159                unlock( lock );
     160        }
     161}
     162
     163size_t on_wait( blocking_lock & this ) with( this ) {
    166164        lock( lock __cfaabi_dbg_ctx2 );
    167165        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    170168        size_t ret = recursion_count;
    171169
    172         pop_node( this );
    173 
    174     select_node node;
    175     active_thread()->link_node = (void *)&node;
     170        pop_and_set_new_owner( this );
    176171        unlock( lock );
    177 
    178     pre_park_then_park( pp_fn, pp_datum );
    179 
    180172        return ret;
    181173}
     
    184176        recursion_count = recursion;
    185177}
    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 void on_selected( blocking_lock & this, select_node & node ) {}
    242178
    243179//-----------------------------------------------------------------------------
     
    376312        int counter( condition_variable(L) & this ) with(this) { return count; }
    377313
    378         static void enqueue_thread( condition_variable(L) & this, info_thread(L) * i ) with(this) {
     314        static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    379315                // add info_thread to waiting queue
    380316                insert_last( blocked_threads, *i );
    381317                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 ); }
     318                size_t recursion_count = 0;
     319                if (i->lock) {
     320                        // if lock was passed get recursion count to reset to after waking thread
     321                        recursion_count = on_wait( *i->lock );
     322                }
     323                return recursion_count;
     324        }
    393325
    394326        // helper for wait()'s' with no timeout
    395327        static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
    396328                lock( lock __cfaabi_dbg_ctx2 );
    397         enqueue_thread( this, &i );
     329                size_t recursion_count = queue_and_get_recursion(this, &i);
    398330                unlock( lock );
    399331
    400332                // blocks here
    401         size_t recursion_count = block_and_get_recursion( i );
     333                park( );
    402334
    403335                // resets recursion count here after waking
    404                 if ( i.lock ) on_wakeup( *i.lock, recursion_count );
     336                if (i.lock) on_wakeup(*i.lock, recursion_count);
    405337        }
    406338
     
    409341                queue_info_thread( this, i );
    410342
    411     static void cond_alarm_register( void * node_ptr ) { register_self( (alarm_node_t *)node_ptr ); }
    412 
    413343        // helper for wait()'s' with a timeout
    414344        static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    415345                lock( lock __cfaabi_dbg_ctx2 );
    416         enqueue_thread( this, &info );
     346                size_t recursion_count = queue_and_get_recursion(this, &info);
    417347                alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    418348                unlock( lock );
    419349
    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();
     350                // registers alarm outside cond lock to avoid deadlock
     351                register_self( &node_wrap.alarm_node );
     352
     353                // blocks here
     354                park();
    423355
    424356                // unregisters alarm so it doesn't go off if this happens first
     
    426358
    427359                // resets recursion count here after waking
    428                 if ( info.lock ) on_wakeup( *info.lock, recursion_count );
     360                if (info.lock) on_wakeup(*info.lock, recursion_count);
    429361        }
    430362
     
    486418                info_thread( L ) i = { active_thread(), info, &l };
    487419                insert_last( blocked_threads, i );
    488                 size_t recursion_count = on_wait( *i.lock, pre_park_noop, 0p ); // blocks here
    489                 // park( );
     420                size_t recursion_count = on_wait( *i.lock );
     421                park( );
    490422                on_wakeup(*i.lock, recursion_count);
    491423        }
     
    528460        bool empty ( pthread_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
    529461
     462        static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) {
     463                // add info_thread to waiting queue
     464                insert_last( blocked_threads, *i );
     465                size_t recursion_count = 0;
     466                recursion_count = on_wait( *i->lock );
     467                return recursion_count;
     468        }
     469       
    530470        static void queue_info_thread_timeout( pthread_cond_var(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    531471                lock( lock __cfaabi_dbg_ctx2 );
    532         insert_last( blocked_threads, info );
     472                size_t recursion_count = queue_and_get_recursion(this, &info);
    533473                pthread_alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    534474                unlock( lock );
    535475
    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
     476                // registers alarm outside cond lock to avoid deadlock
     477                register_self( &node_wrap.alarm_node );
     478
     479                // blocks here
     480                park();
     481
     482                // unregisters alarm so it doesn't go off if this happens first
    540483                unregister_self( &node_wrap.alarm_node );
    541484
    542485                // resets recursion count here after waking
    543                 if ( info.lock ) on_wakeup( *info.lock, recursion_count );
     486                if (info.lock) on_wakeup(*info.lock, recursion_count);
    544487        }
    545488
     
    551494                lock( lock __cfaabi_dbg_ctx2 );
    552495                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 );
     496                size_t recursion_count = queue_and_get_recursion(this, &i);
     497                unlock( lock );
     498                park( );
     499                on_wakeup(*i.lock, recursion_count);
    560500        }
    561501
     
    645585        return thrd != 0p;
    646586}
    647 
Note: See TracChangeset for help on using the changeset viewer.