Ignore:
File:
1 edited

Legend:

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

    ra45e21c rd30e3eb  
    3232#include <fstream.hfa>
    3333
     34
    3435// futex headers
    3536#include <linux/futex.h>      /* Definition of FUTEX_* constants */
     
    154155// futex_mutex
    155156
     157// - No cond var support
    156158// - Kernel thd blocking alternative to the spinlock
    157159// - No ownership (will deadlock on reacq)
     
    183185        int state;
    184186
    185         for( int spin = 4; spin < 1024; spin += spin) {
    186                 state = 0;
    187                 // if unlocked, lock and return
    188                 if (internal_try_lock(this, state)) return;
    189                 if (2 == state) break;
    190                 for (int i = 0; i < spin; i++) Pause();
    191         }
    192 
    193         // // no contention try to acquire
    194         // if (internal_try_lock(this, state)) return;
     187       
     188        // // linear backoff omitted for now
     189        // for( int spin = 4; spin < 1024; spin += spin) {
     190        //      state = 0;
     191        //      // if unlocked, lock and return
     192        //      if (internal_try_lock(this, state)) return;
     193        //      if (2 == state) break;
     194        //      for (int i = 0; i < spin; i++) Pause();
     195        // }
     196
     197        // no contention try to acquire
     198        if (internal_try_lock(this, state)) return;
    195199       
    196200        // if not in contended state, set to be in contended state
     
    205209
    206210static inline void unlock(futex_mutex & this) with(this) {
    207         // if uncontended do atomic unlock and then return
    208     if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
     211        // if uncontended do atomice unlock and then return
     212        if (__atomic_fetch_sub(&val, 1, __ATOMIC_RELEASE) == 1) return; // TODO: try acq/rel
    209213       
    210214        // otherwise threads are blocked so we must wake one
     215        __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);
    211216        futex((int *)&val, FUTEX_WAKE, 1);
    212217}
     
    217222// to set recursion count after getting signalled;
    218223static inline void on_wakeup( futex_mutex & f, size_t recursion ) {}
    219 
    220 //-----------------------------------------------------------------------------
    221 // go_mutex
    222 
    223 // - Kernel thd blocking alternative to the spinlock
    224 // - No ownership (will deadlock on reacq)
    225 // - Golang's flavour of mutex
    226 // - Impl taken from Golang: src/runtime/lock_futex.go
    227 struct go_mutex {
    228         // lock state any state other than UNLOCKED is locked
    229         // enum LockState { UNLOCKED = 0, LOCKED = 1, SLEEPING = 2 };
    230        
    231         // stores a lock state
    232         int val;
    233 };
    234 
    235 static inline void  ?{}( go_mutex & this ) with(this) { val = 0; }
    236 
    237 static inline bool internal_try_lock(go_mutex & this, int & compare_val, int new_val ) with(this) {
    238         return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, new_val, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
    239 }
    240 
    241 static inline int internal_exchange(go_mutex & this, int swap ) with(this) {
    242         return __atomic_exchange_n((int*)&val, swap, __ATOMIC_ACQUIRE);
    243 }
    244 
    245 const int __go_mtx_spins = 4;
    246 const int __go_mtx_pauses = 30;
    247 // if this is called recursively IT WILL DEADLOCK!!!!!
    248 static inline void lock(go_mutex & this) with(this) {
    249         int state, init_state;
    250 
    251     // speculative grab
    252     state = internal_exchange(this, 1);
    253     if ( !state ) return; // state == 0
    254     init_state = state;
    255     for (;;) {
    256         for( int i = 0; i < __go_mtx_spins; i++ ) {
    257             while( !val ) { // lock unlocked
    258                 state = 0;
    259                 if (internal_try_lock(this, state, init_state)) return;
    260             }
    261             for (int i = 0; i < __go_mtx_pauses; i++) Pause();
    262         }
    263 
    264         while( !val ) { // lock unlocked
    265             state = 0;
    266             if (internal_try_lock(this, state, init_state)) return;
    267         }
    268         sched_yield();
    269        
    270         // if not in contended state, set to be in contended state
    271         state = internal_exchange(this, 2);
    272         if ( !state ) return; // state == 0
    273         init_state = 2;
    274         futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK
    275     }
    276 }
    277 
    278 static inline void unlock( go_mutex & this ) with(this) {
    279         // if uncontended do atomic unlock and then return
    280     if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
    281        
    282         // otherwise threads are blocked so we must wake one
    283         futex((int *)&val, FUTEX_WAKE, 1);
    284 }
    285 
    286 static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); }
    287 static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;}
    288 static inline void on_wakeup( go_mutex & f, size_t recursion ) {}
    289224
    290225//-----------------------------------------------------------------------------
     
    336271        this.lock_value = 0;
    337272}
    338 
    339 static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
    340273
    341274static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) {
Note: See TracChangeset for help on using the changeset viewer.