Ignore:
File:
1 edited

Legend:

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

    r70a4ed5 r1ab773e0  
    3030#include "time.hfa"
    3131
    32 #include "select.hfa"
    33 
    3432#include <fstream.hfa>
     33
    3534
    3635// futex headers
     
    3938#include <unistd.h>
    4039
    41 typedef void (*__cfa_pre_park)( void * );
    42 
    43 static inline void pre_park_noop( void * ) {}
    44 
    45 //-----------------------------------------------------------------------------
    46 // is_blocking_lock
    47 forall( L & | sized(L) )
    48 trait is_blocking_lock {
    49         // For synchronization locks to use when acquiring
    50         void on_notify( L &, struct thread$ * );
    51 
    52         // For synchronization locks to use when releasing
    53         size_t on_wait( L &, __cfa_pre_park pp_fn, void * pp_datum );
    54 
    55         // to set recursion count after getting signalled;
    56         void on_wakeup( L &, size_t recursion );
    57 };
    58 
    59 static inline void pre_park_then_park( __cfa_pre_park pp_fn, void * pp_datum ) {
    60     pp_fn( pp_datum );
    61     park();
    62 }
    63 
    64 // macros for default routine impls for is_blocking_lock trait that do not wait-morph
    65 
    66 #define DEFAULT_ON_NOTIFY( lock_type ) \
    67     static inline void on_notify( lock_type & this, thread$ * t ){ unpark(t); }
    68 
    69 #define DEFAULT_ON_WAIT( lock_type ) \
    70     static inline size_t on_wait( lock_type & this, __cfa_pre_park pp_fn, void * pp_datum ) { \
    71         unlock( this ); \
    72         pre_park_then_park( pp_fn, pp_datum ); \
    73         return 0; \
    74     }
    75 
    76 // on_wakeup impl if lock should be reacquired after waking up
    77 #define DEFAULT_ON_WAKEUP_REACQ( lock_type ) \
    78     static inline void on_wakeup( lock_type & this, size_t recursion ) { lock( this ); }
    79 
    80 // on_wakeup impl if lock will not be reacquired after waking up
    81 #define DEFAULT_ON_WAKEUP_NO_REACQ( lock_type ) \
    82     static inline void on_wakeup( lock_type & this, size_t recursion ) {}
    83 
    84 
     40// undef to make a number of the locks not reacquire upon waking from a condlock
     41#define REACQ 1
    8542
    8643//-----------------------------------------------------------------------------
     
    10966static inline bool   try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
    11067static inline void   unlock   ( single_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
    111 static inline size_t on_wait  ( single_acquisition_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) { return on_wait ( (blocking_lock &)this, pp_fn, pp_datum ); }
     68static inline size_t on_wait  ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
    11269static inline void   on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    11370static inline void   on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    114 static inline bool   register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    115 static inline bool   unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    116 static inline void   on_selected( single_acquisition_lock & this, select_node & node ) { on_selected( (blocking_lock &)this, node ); }
    11771
    11872//----------
     
    12680static inline bool   try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); }
    12781static inline void   unlock   ( owner_lock & this ) { unlock  ( (blocking_lock &)this ); }
    128 static inline size_t on_wait  ( owner_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) { return on_wait ( (blocking_lock &)this, pp_fn, pp_datum ); }
     82static inline size_t on_wait  ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); }
    12983static inline void   on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    13084static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    131 static inline bool   register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    132 static inline bool   unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    133 static inline void   on_selected( owner_lock & this, select_node & node ) { on_selected( (blocking_lock &)this, node ); }
    13485
    13586//-----------------------------------------------------------------------------
     
    176127static inline void ?{}(mcs_spin_node & this) { this.next = 0p; this.locked = true; }
    177128
     129static inline mcs_spin_node * volatile & ?`next ( mcs_spin_node * node ) {
     130        return node->next;
     131}
     132
    178133struct mcs_spin_lock {
    179134        mcs_spin_queue queue;
     
    181136
    182137static inline void lock(mcs_spin_lock & l, mcs_spin_node & n) {
    183     n.locked = true;
    184138        mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST);
    185         if( prev == 0p ) return;
     139        n.locked = true;
     140        if(prev == 0p) return;
    186141        prev->next = &n;
    187         while( __atomic_load_n(&n.locked, __ATOMIC_RELAXED) ) Pause();
     142        while(__atomic_load_n(&n.locked, __ATOMIC_RELAXED)) Pause();
    188143}
    189144
     
    191146        mcs_spin_node * n_ptr = &n;
    192147        if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return;
    193         while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) Pause();
     148        while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) {}
    194149        n.next->locked = false;
    195150}
     
    198153// futex_mutex
    199154
     155// - No cond var support
    200156// - Kernel thd blocking alternative to the spinlock
    201157// - No ownership (will deadlock on reacq)
    202 // - no reacq on wakeup
    203158struct futex_mutex {
    204159        // lock state any state other than UNLOCKED is locked
     
    214169}
    215170
    216 static inline void ?{}( futex_mutex & this ) with(this) { val = 0; }
    217 
    218 static inline bool internal_try_lock( futex_mutex & this, int & compare_val) with(this) {
     171static inline void  ?{}( futex_mutex & this ) with(this) { val = 0; }
     172
     173static inline bool internal_try_lock(futex_mutex & this, int & compare_val) with(this) {
    219174        return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
    220175}
    221176
    222 static inline int internal_exchange( futex_mutex & this ) with(this) {
     177static inline int internal_exchange(futex_mutex & this) with(this) {
    223178        return __atomic_exchange_n((int*)&val, 2, __ATOMIC_ACQUIRE);
    224179}
    225180
    226181// if this is called recursively IT WILL DEADLOCK!!!!!
    227 static inline void lock( futex_mutex & this ) with(this) {
     182static inline void lock(futex_mutex & this) with(this) {
    228183        int state;
    229184
    230         for( int spin = 4; spin < 1024; spin += spin) {
    231                 state = 0;
    232                 // if unlocked, lock and return
    233                 if (internal_try_lock(this, state)) return;
    234                 if (2 == state) break;
    235                 for (int i = 0; i < spin; i++) Pause();
    236         }
     185       
     186        // // linear backoff omitted for now
     187        // for( int spin = 4; spin < 1024; spin += spin) {
     188        //      state = 0;
     189        //      // if unlocked, lock and return
     190        //      if (internal_try_lock(this, state)) return;
     191        //      if (2 == state) break;
     192        //      for (int i = 0; i < spin; i++) Pause();
     193        // }
     194
     195        // no contention try to acquire
     196        if (internal_try_lock(this, state)) return;
    237197       
    238198        // if not in contended state, set to be in contended state
     
    247207
    248208static inline void unlock(futex_mutex & this) with(this) {
    249         // if uncontended do atomic unlock and then return
    250     if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
     209        // if uncontended do atomice unlock and then return
     210        if (__atomic_fetch_sub(&val, 1, __ATOMIC_RELEASE) == 1) return; // TODO: try acq/rel
    251211       
    252212        // otherwise threads are blocked so we must wake one
     213        __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);
    253214        futex((int *)&val, FUTEX_WAKE, 1);
    254215}
    255216
    256 DEFAULT_ON_NOTIFY( futex_mutex )
    257 DEFAULT_ON_WAIT( futex_mutex )
    258 DEFAULT_ON_WAKEUP_NO_REACQ( futex_mutex )
    259 
    260 //-----------------------------------------------------------------------------
    261 // go_mutex
    262 
    263 // - Kernel thd blocking alternative to the spinlock
    264 // - No ownership (will deadlock on reacq)
    265 // - Golang's flavour of mutex
    266 // - Impl taken from Golang: src/runtime/lock_futex.go
    267 struct go_mutex {
    268         // lock state any state other than UNLOCKED is locked
    269         // enum LockState { UNLOCKED = 0, LOCKED = 1, SLEEPING = 2 };
    270        
    271         // stores a lock state
    272         int val;
    273 };
    274 static inline void  ?{}( go_mutex & this ) with(this) { val = 0; }
    275 // static inline void ?{}( go_mutex & this, go_mutex this2 ) = void; // these don't compile correctly at the moment so they should be omitted
    276 // static inline void ?=?( go_mutex & this, go_mutex this2 ) = void;
    277 
    278 static inline bool internal_try_lock(go_mutex & this, int & compare_val, int new_val ) with(this) {
    279         return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, new_val, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
    280 }
    281 
    282 static inline int internal_exchange(go_mutex & this, int swap ) with(this) {
    283         return __atomic_exchange_n((int*)&val, swap, __ATOMIC_ACQUIRE);
    284 }
    285 
    286 // if this is called recursively IT WILL DEADLOCK!!!!!
    287 static inline void lock( go_mutex & this ) with( this ) {
    288         int state, init_state;
    289 
    290     // speculative grab
    291     state = internal_exchange(this, 1);
    292     if ( !state ) return; // state == 0
    293     init_state = state;
    294     for (;;) {
    295         for( int i = 0; i < 4; i++ ) {
    296             while( !val ) { // lock unlocked
    297                 state = 0;
    298                 if ( internal_try_lock( this, state, init_state ) ) return;
    299             }
    300             for (int i = 0; i < 30; i++) Pause();
    301         }
    302 
    303         while( !val ) { // lock unlocked
    304             state = 0;
    305             if ( internal_try_lock( this, state, init_state ) ) return;
    306         }
    307         sched_yield();
    308        
    309         // if not in contended state, set to be in contended state
    310         state = internal_exchange( this, 2 );
    311         if ( !state ) return; // state == 0
    312         init_state = 2;
    313         futex( (int*)&val, FUTEX_WAIT, 2 ); // if val is not 2 this returns with EWOULDBLOCK
    314     }
    315 }
    316 
    317 static inline void unlock( go_mutex & this ) with(this) {
    318         // if uncontended do atomic unlock and then return
    319     if ( __atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1 ) return;
    320        
    321         // otherwise threads are blocked so we must wake one
    322         futex( (int *)&val, FUTEX_WAKE, 1 );
    323 }
    324 
    325 DEFAULT_ON_NOTIFY( go_mutex )
    326 DEFAULT_ON_WAIT( go_mutex )
    327 DEFAULT_ON_WAKEUP_NO_REACQ( go_mutex )
    328 
    329 //-----------------------------------------------------------------------------
    330 // Exponential backoff then block lock
    331 struct exp_backoff_then_block_lock {
     217static inline void on_notify( futex_mutex & f, thread$ * t){ unpark(t); }
     218static inline size_t on_wait( futex_mutex & f ) {unlock(f); return 0;}
     219
     220// to set recursion count after getting signalled;
     221static inline void on_wakeup( futex_mutex & f, size_t recursion ) {}
     222
     223//-----------------------------------------------------------------------------
     224// CLH Spinlock
     225// - No recursive acquisition
     226// - Needs to be released by owner
     227
     228struct clh_lock {
     229        volatile bool * volatile tail;
     230};
     231
     232static inline void  ?{}( clh_lock & this ) { this.tail = malloc(); *this.tail = true; }
     233static inline void ^?{}( clh_lock & this ) { free(this.tail); }
     234
     235static inline void lock(clh_lock & l) {
     236        thread$ * curr_thd = active_thread();
     237        *(curr_thd->clh_node) = false;
     238        volatile bool * prev = __atomic_exchange_n((bool **)(&l.tail), (bool *)(curr_thd->clh_node), __ATOMIC_SEQ_CST);
     239        while(!__atomic_load_n(prev, __ATOMIC_ACQUIRE)) Pause();
     240        curr_thd->clh_prev = prev;
     241}
     242
     243static inline void unlock(clh_lock & l) {
     244        thread$ * curr_thd = active_thread();
     245        __atomic_store_n(curr_thd->clh_node, true, __ATOMIC_RELEASE);
     246        curr_thd->clh_node = curr_thd->clh_prev;
     247}
     248
     249static inline void on_notify(clh_lock & this, struct thread$ * t ) { unpark(t); }
     250static inline size_t on_wait(clh_lock & this) { unlock(this); return 0; }
     251static inline void on_wakeup(clh_lock & this, size_t recursion ) {
     252        #ifdef REACQ
     253        lock(this);
     254        #endif
     255}
     256
     257
     258//-----------------------------------------------------------------------------
     259// Linear backoff Spinlock
     260struct linear_backoff_then_block_lock {
    332261        // Spin lock used for mutual exclusion
    333262        __spinlock_t spinlock;
     
    340269};
    341270
    342 static inline void  ?{}( exp_backoff_then_block_lock & this ) {
     271static inline void  ?{}( linear_backoff_then_block_lock & this ) {
    343272        this.spinlock{};
    344273        this.blocked_threads{};
    345274        this.lock_value = 0;
    346275}
    347 static inline void ?{}( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void;
    348 static inline void ?=?( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void;
    349 
    350 static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
    351 
    352 static inline bool internal_try_lock( exp_backoff_then_block_lock & this, size_t & compare_val ) with(this) {
    353         return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
    354 }
    355 
    356 static inline bool try_lock( exp_backoff_then_block_lock & this ) { size_t compare_val = 0; return internal_try_lock( this, compare_val ); }
    357 
    358 static inline bool try_lock_contention( exp_backoff_then_block_lock & this ) with(this) {
    359         return !__atomic_exchange_n( &lock_value, 2, __ATOMIC_ACQUIRE );
    360 }
    361 
    362 static inline bool block( exp_backoff_then_block_lock & this ) with(this) {
    363     lock( spinlock __cfaabi_dbg_ctx2 );
    364     if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) {
    365         unlock( spinlock );
    366         return true;
    367     }
    368     insert_last( blocked_threads, *active_thread() );
    369     unlock( spinlock );
     276static inline void ^?{}( linear_backoff_then_block_lock & this ) {}
     277// static inline void ?{}( linear_backoff_then_block_lock & this, linear_backoff_then_block_lock this2 ) = void;
     278// static inline void ?=?( linear_backoff_then_block_lock & this, linear_backoff_then_block_lock this2 ) = void;
     279
     280static inline bool internal_try_lock(linear_backoff_then_block_lock & this, size_t & compare_val) with(this) {
     281        if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
     282                return true;
     283        }
     284        return false;
     285}
     286
     287static inline bool try_lock(linear_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); }
     288
     289static inline bool try_lock_contention(linear_backoff_then_block_lock & this) with(this) {
     290        if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) {
     291                return true;
     292        }
     293        return false;
     294}
     295
     296static inline bool block(linear_backoff_then_block_lock & this) with(this) {
     297        lock( spinlock __cfaabi_dbg_ctx2 ); // TODO change to lockfree queue (MPSC)
     298        if (lock_value != 2) {
     299                unlock( spinlock );
     300                return true;
     301        }
     302        insert_last( blocked_threads, *active_thread() );
     303        unlock( spinlock );
    370304        park( );
    371305        return true;
    372306}
    373307
    374 static inline void lock( exp_backoff_then_block_lock & this ) with(this) {
     308static inline void lock(linear_backoff_then_block_lock & this) with(this) {
    375309        size_t compare_val = 0;
    376310        int spin = 4;
    377 
    378311        // linear backoff
    379312        for( ;; ) {
     
    391324}
    392325
    393 static inline void unlock( exp_backoff_then_block_lock & this ) with(this) {
     326static inline void unlock(linear_backoff_then_block_lock & this) with(this) {
    394327    if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return;
    395     lock( spinlock __cfaabi_dbg_ctx2 );
    396     thread$ * t = &try_pop_front( blocked_threads );
    397     unlock( spinlock );
    398     unpark( t );
    399 }
    400 
    401 DEFAULT_ON_NOTIFY( exp_backoff_then_block_lock )
    402 DEFAULT_ON_WAIT( exp_backoff_then_block_lock )
    403 DEFAULT_ON_WAKEUP_REACQ( exp_backoff_then_block_lock )
     328        lock( spinlock __cfaabi_dbg_ctx2 );
     329        thread$ * t = &try_pop_front( blocked_threads );
     330        unlock( spinlock );
     331        unpark( t );
     332}
     333
     334static inline void on_notify(linear_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); }
     335static inline size_t on_wait(linear_backoff_then_block_lock & this) { unlock(this); return 0; }
     336static inline void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) {
     337        #ifdef REACQ
     338        lock(this);
     339        #endif
     340}
    404341
    405342//-----------------------------------------------------------------------------
     
    431368
    432369// if this is called recursively IT WILL DEADLOCK!!!!!
    433 static inline void lock( fast_block_lock & this ) with(this) {
     370static inline void lock(fast_block_lock & this) with(this) {
    434371        lock( lock __cfaabi_dbg_ctx2 );
    435372        if ( held ) {
     
    443380}
    444381
    445 static inline void unlock( fast_block_lock & this ) with(this) {
     382static inline void unlock(fast_block_lock & this) with(this) {
    446383        lock( lock __cfaabi_dbg_ctx2 );
    447384        /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );
     
    452389}
    453390
    454 static inline void on_notify( fast_block_lock & this, struct thread$ * t ) with(this) {
    455     lock( lock __cfaabi_dbg_ctx2 );
    456     insert_last( blocked_threads, *t );
    457     unlock( lock );
    458 }
    459 DEFAULT_ON_WAIT( fast_block_lock )
    460 DEFAULT_ON_WAKEUP_NO_REACQ( fast_block_lock )
     391static inline void on_notify(fast_block_lock & this, struct thread$ * t ) with(this) {
     392        #ifdef REACQ
     393                lock( lock __cfaabi_dbg_ctx2 );
     394                insert_last( blocked_threads, *t );
     395                unlock( lock );
     396        #else
     397                unpark(t);
     398        #endif
     399}
     400static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }
     401static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }
    461402
    462403//-----------------------------------------------------------------------------
     
    469410struct simple_owner_lock {
    470411        // List of blocked threads
    471         dlist( select_node ) blocked_threads;
     412        dlist( thread$ ) blocked_threads;
    472413
    473414        // Spin lock used for mutual exclusion
     
    490431static inline void ?=?( simple_owner_lock & this, simple_owner_lock this2 ) = void;
    491432
    492 static inline void lock( simple_owner_lock & this ) with(this) {
    493         if ( owner == active_thread() ) {
     433static inline void lock(simple_owner_lock & this) with(this) {
     434        if (owner == active_thread()) {
    494435                recursion_count++;
    495436                return;
     
    497438        lock( lock __cfaabi_dbg_ctx2 );
    498439
    499         if ( owner != 0p ) {
    500         select_node node;
    501                 insert_last( blocked_threads, node );
     440        if (owner != 0p) {
     441                insert_last( blocked_threads, *active_thread() );
    502442                unlock( lock );
    503443                park( );
     
    509449}
    510450
    511 static inline void pop_node( simple_owner_lock & this ) with(this) {
    512     __handle_waituntil_OR( blocked_threads );
    513     select_node * node = &try_pop_front( blocked_threads );
    514     if ( node ) {
    515         owner = node->blocked_thread;
    516         recursion_count = 1;
    517         // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread );
    518         wake_one( blocked_threads, *node );
    519     } else {
    520         owner = 0p;
    521         recursion_count = 0;
    522     }
    523 }
    524 
    525 static inline void unlock( simple_owner_lock & this ) with(this) {
     451// TODO: fix duplicate def issue and bring this back
     452// void pop_and_set_new_owner( simple_owner_lock & this ) with( this ) {
     453        // thread$ * t = &try_pop_front( blocked_threads );
     454        // owner = t;
     455        // recursion_count = ( t ? 1 : 0 );
     456        // unpark( t );
     457// }
     458
     459static inline void unlock(simple_owner_lock & this) with(this) {
    526460        lock( lock __cfaabi_dbg_ctx2 );
    527461        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    530464        recursion_count--;
    531465        if ( recursion_count == 0 ) {
    532                 pop_node( this );
     466                // pop_and_set_new_owner( this );
     467                thread$ * t = &try_pop_front( blocked_threads );
     468                owner = t;
     469                recursion_count = ( t ? 1 : 0 );
     470                unpark( t );
    533471        }
    534472        unlock( lock );
    535473}
    536474
    537 static inline void on_notify( simple_owner_lock & this, thread$ * t ) with(this) {
     475static inline void on_notify(simple_owner_lock & this, struct thread$ * t ) with(this) {
    538476        lock( lock __cfaabi_dbg_ctx2 );
    539477        // lock held
    540478        if ( owner != 0p ) {
    541                 insert_last( blocked_threads, *(select_node *)t->link_node );
     479                insert_last( blocked_threads, *t );
    542480        }
    543481        // lock not held
     
    550488}
    551489
    552 static inline size_t on_wait( simple_owner_lock & this, __cfa_pre_park pp_fn, void * pp_datum ) with(this) {
     490static inline size_t on_wait(simple_owner_lock & this) with(this) {
    553491        lock( lock __cfaabi_dbg_ctx2 );
    554492        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    557495        size_t ret = recursion_count;
    558496
    559         pop_node( this );
    560 
    561     select_node node;
    562     active_thread()->link_node = (void *)&node;
     497        // pop_and_set_new_owner( this );
     498
     499        thread$ * t = &try_pop_front( blocked_threads );
     500        owner = t;
     501        recursion_count = ( t ? 1 : 0 );
     502        unpark( t );
     503
    563504        unlock( lock );
    564 
    565     pre_park_then_park( pp_fn, pp_datum );
    566 
    567505        return ret;
    568506}
    569507
    570 static inline void on_wakeup( simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; }
    571 
    572 // waituntil() support
    573 static inline bool register_select( simple_owner_lock & this, select_node & node ) with(this) {
    574     lock( lock __cfaabi_dbg_ctx2 );
    575 
    576     // check if we can complete operation. If so race to establish winner in special OR case
    577     if ( !node.park_counter && ( owner == active_thread() || owner == 0p ) ) {
    578         if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
    579            unlock( lock );
    580            return false;
    581         }
    582     }
    583 
    584     if ( owner == active_thread() ) {
    585                 recursion_count++;
    586         if ( node.park_counter ) __make_select_node_available( node );
    587         unlock( lock );
    588                 return true;
    589         }
    590 
    591     if ( owner != 0p ) {
    592                 insert_last( blocked_threads, node );
    593                 unlock( lock );
    594                 return false;
    595         }
    596    
    597         owner = active_thread();
    598         recursion_count = 1;
    599 
    600     if ( node.park_counter ) __make_select_node_available( node );
    601     unlock( lock );
    602     return true;
    603 }
    604 
    605 static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with(this) {
    606     lock( lock __cfaabi_dbg_ctx2 );
    607     if ( node`isListed ) {
    608         remove( node );
    609         unlock( lock );
    610         return false;
    611     }
    612 
    613     if ( owner == active_thread() ) {
    614         recursion_count--;
    615         if ( recursion_count == 0 ) {
    616             pop_node( this );
    617         }
    618     }
    619     unlock( lock );
    620     return false;
    621 }
    622 
    623 static inline void on_selected( simple_owner_lock & this, select_node & node ) {}
    624 
     508static inline void on_wakeup(simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; }
    625509
    626510//-----------------------------------------------------------------------------
     
    637521        // flag showing if lock is held
    638522        volatile bool held;
     523
     524        #ifdef __CFA_DEBUG__
     525        // for deadlock detection
     526        struct thread$ * owner;
     527        #endif
    639528};
    640529
     
    647536static inline void ?=?( spin_queue_lock & this, spin_queue_lock this2 ) = void;
    648537
    649 // if this is called recursively IT WILL DEADLOCK!
    650 static inline void lock( spin_queue_lock & this ) with(this) {
     538// if this is called recursively IT WILL DEADLOCK!!!!!
     539static inline void lock(spin_queue_lock & this) with(this) {
    651540        mcs_spin_node node;
    652541        lock( lock, node );
     
    656545}
    657546
    658 static inline void unlock( spin_queue_lock & this ) with(this) {
     547static inline void unlock(spin_queue_lock & this) with(this) {
    659548        __atomic_store_n(&held, false, __ATOMIC_RELEASE);
    660549}
    661550
    662 DEFAULT_ON_NOTIFY( spin_queue_lock )
    663 DEFAULT_ON_WAIT( spin_queue_lock )
    664 DEFAULT_ON_WAKEUP_REACQ( spin_queue_lock )
     551static inline void on_notify(spin_queue_lock & this, struct thread$ * t ) {
     552        unpark(t);
     553}
     554static inline size_t on_wait(spin_queue_lock & this) { unlock(this); return 0; }
     555static inline void on_wakeup(spin_queue_lock & this, size_t recursion ) {
     556        #ifdef REACQ
     557        lock(this);
     558        #endif
     559}
     560
    665561
    666562//-----------------------------------------------------------------------------
     
    688584
    689585// if this is called recursively IT WILL DEADLOCK!!!!!
    690 static inline void lock( mcs_block_spin_lock & this ) with(this) {
     586static inline void lock(mcs_block_spin_lock & this) with(this) {
    691587        mcs_node node;
    692588        lock( lock, node );
     
    700596}
    701597
    702 DEFAULT_ON_NOTIFY( mcs_block_spin_lock )
    703 DEFAULT_ON_WAIT( mcs_block_spin_lock )
    704 DEFAULT_ON_WAKEUP_REACQ( mcs_block_spin_lock )
     598static inline void on_notify(mcs_block_spin_lock & this, struct thread$ * t ) { unpark(t); }
     599static inline size_t on_wait(mcs_block_spin_lock & this) { unlock(this); return 0; }
     600static inline void on_wakeup(mcs_block_spin_lock & this, size_t recursion ) {
     601        #ifdef REACQ
     602        lock(this);
     603        #endif
     604}
    705605
    706606//-----------------------------------------------------------------------------
     
    728628
    729629// if this is called recursively IT WILL DEADLOCK!!!!!
    730 static inline void lock( block_spin_lock & this ) with(this) {
     630static inline void lock(block_spin_lock & this) with(this) {
    731631        lock( lock );
    732632        while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause();
     
    735635}
    736636
    737 static inline void unlock( block_spin_lock & this ) with(this) {
     637static inline void unlock(block_spin_lock & this) with(this) {
    738638        __atomic_store_n(&held, false, __ATOMIC_RELEASE);
    739639}
    740640
    741 static inline void on_notify( block_spin_lock & this, struct thread$ * t ) with(this.lock) {
     641static inline void on_notify(block_spin_lock & this, struct thread$ * t ) with(this.lock) {
     642  #ifdef REACQ
    742643        // first we acquire internal fast_block_lock
    743644        lock( lock __cfaabi_dbg_ctx2 );
     
    751652        unlock( lock );
    752653
     654  #endif
    753655        unpark(t);
    754 }
    755 DEFAULT_ON_WAIT( block_spin_lock )
    756 static inline void on_wakeup( block_spin_lock & this, size_t recursion ) with(this) {
     656       
     657}
     658static inline size_t on_wait(block_spin_lock & this) { unlock(this); return 0; }
     659static inline void on_wakeup(block_spin_lock & this, size_t recursion ) with(this) {
     660  #ifdef REACQ
    757661        // now we acquire the entire block_spin_lock upon waking up
    758662        while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause();
    759663        __atomic_store_n(&held, true, __ATOMIC_RELEASE);
    760664        unlock( lock ); // Now we release the internal fast_spin_lock
    761 }
     665  #endif
     666}
     667
     668//-----------------------------------------------------------------------------
     669// is_blocking_lock
     670trait is_blocking_lock(L & | sized(L)) {
     671        // For synchronization locks to use when acquiring
     672        void on_notify( L &, struct thread$ * );
     673
     674        // For synchronization locks to use when releasing
     675        size_t on_wait( L & );
     676
     677        // to set recursion count after getting signalled;
     678        void on_wakeup( L &, size_t recursion );
     679};
    762680
    763681//-----------------------------------------------------------------------------
     
    767685forall(L & | is_blocking_lock(L)) {
    768686        struct info_thread;
     687
     688        // // for use by sequence
     689        // info_thread(L) *& Back( info_thread(L) * this );
     690        // info_thread(L) *& Next( info_thread(L) * this );
    769691}
    770692
Note: See TracChangeset for help on using the changeset viewer.