Changeset 7f958c4


Ignore:
Timestamp:
May 4, 2022, 3:28:00 PM (3 months ago)
Author:
caparsons <caparson@…>
Branches:
master, pthread-emulation
Children:
ec57856
Parents:
f6737ae1
Message:

added fast lock/cond var

Location:
libcfa/src/concurrency
Files:
2 edited

Legend:

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

    rf6737ae1 r7f958c4  
    220220
    221221//-----------------------------------------------------------------------------
    222 // condition variable
     222// Synchronization Locks
    223223forall(L & | is_blocking_lock(L)) {
    224224
     225        //-----------------------------------------------------------------------------
     226        // condition variable
    225227        void ?{}( condition_variable(L) & this ){
    226228                this.lock{};
     
    337339        bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , duration ) }
    338340        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , duration ) }
     341
     342        //-----------------------------------------------------------------------------
     343        // fast_cond_var
     344        void  ?{}( fast_cond_var(L) & this ){
     345                this.blocked_threads{};
     346                #ifdef __CFA_DEBUG__
     347                this.lock_used = 0p;
     348                #endif
     349        }
     350        void ^?{}( fast_cond_var(L) & this ){ }
     351
     352        bool notify_one( fast_cond_var(L) & this ) with(this) {
     353                bool ret = ! blocked_threads`isEmpty;
     354                if ( ret ) {
     355                        info_thread(L) & popped = try_pop_front( blocked_threads );
     356                        on_notify(*popped.lock, popped.t);
     357                }
     358                return ret;
     359        }
     360        bool notify_all( fast_cond_var(L) & this ) with(this) {
     361                bool ret = ! blocked_threads`isEmpty;
     362                while( ! blocked_threads`isEmpty ) {
     363                        info_thread(L) & popped = try_pop_front( blocked_threads );
     364                        on_notify(*popped.lock, popped.t);
     365                }
     366                return ret;
     367        }
     368
     369        uintptr_t front( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty ? NULL : blocked_threads`first.info; }
     370        bool empty ( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
     371
     372        void wait( fast_cond_var(L) & this, L & l ) {
     373                wait( this, l, 0 );
     374        }
     375
     376        void wait( fast_cond_var(L) & this, L & l, uintptr_t info ) with(this) {
     377                // brand cond lock with lock
     378                #ifdef __CFA_DEBUG__
     379                        if ( lock_used == 0p ) lock_used = &l;
     380                        else { assert(lock_used == &l); }
     381                #endif
     382                info_thread( L ) i = { active_thread(), info, &l };
     383                insert_last( blocked_threads, i );
     384                size_t recursion_count = on_wait( *i.lock );
     385                park( );
     386                on_wakeup(*i.lock, recursion_count);
     387        }
    339388}
    340389
  • libcfa/src/concurrency/locks.hfa

    rf6737ae1 r7f958c4  
    7373static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    7474
     75//-----------------------------------------------------------------------------
     76// MCS Lock
    7577struct mcs_node {
    7678        mcs_node * volatile next;
     
    98100}
    99101
     102//-----------------------------------------------------------------------------
     103// Linear backoff Spinlock
    100104struct linear_backoff_then_block_lock {
    101105        // Spin lock used for mutual exclusion
     
    199203
    200204//-----------------------------------------------------------------------------
     205// Fast Block Lock
     206
     207// High efficiency minimal blocking lock
     208// - No reacquire for cond var
     209// - No recursive acquisition
     210// - No ownership
     211struct fast_block_lock {
     212        // Spin lock used for mutual exclusion
     213        __spinlock_t lock;
     214
     215        // List of blocked threads
     216        dlist( thread$ ) blocked_threads;
     217
     218        bool held:1;
     219};
     220
     221static inline void  ?{}( fast_block_lock & this ) with(this) {
     222        lock{};
     223        blocked_threads{};
     224        held = false;
     225}
     226static inline void ^?{}( fast_block_lock & this ) {}
     227static inline void ?{}( fast_block_lock & this, fast_block_lock this2 ) = void;
     228static inline void ?=?( fast_block_lock & this, fast_block_lock this2 ) = void;
     229
     230// if this is called recursively IT WILL DEADLOCK!!!!!
     231static inline void lock(fast_block_lock & this) with(this) {
     232        lock( lock __cfaabi_dbg_ctx2 );
     233        if (held) {
     234                insert_last( blocked_threads, *active_thread() );
     235                unlock( lock );
     236                park( );
     237                return;
     238        }
     239        held = true;
     240        unlock( lock );
     241}
     242
     243static inline void unlock(fast_block_lock & this) with(this) {
     244        lock( lock __cfaabi_dbg_ctx2 );
     245        /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );
     246        thread$ * t = &try_pop_front( blocked_threads );
     247        held = ( t ? true : false );
     248        unpark( t );
     249        unlock( lock );
     250}
     251
     252static inline void on_notify(fast_block_lock & this, struct thread$ * t ) { unpark(t); }
     253static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }
     254static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }
     255
     256//-----------------------------------------------------------------------------
    201257// is_blocking_lock
    202258trait is_blocking_lock(L & | sized(L)) {
     
    226282// Synchronization Locks
    227283forall(L & | is_blocking_lock(L)) {
     284
     285        //-----------------------------------------------------------------------------
     286        // condition_variable
     287
     288        // The multi-tool condition variable
     289        // - can pass timeouts to wait for either a signal or timeout
     290        // - can wait without passing a lock
     291        // - can have waiters reacquire different locks while waiting on the same cond var
     292        // - has shadow queue
     293        // - can be signalled outside of critical sections with no locks held
    228294        struct condition_variable {
    229295                // Spin lock used for mutual exclusion
     
    258324        bool wait( condition_variable(L) & this, L & l, Duration duration );
    259325        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
    260 }
     326
     327        //-----------------------------------------------------------------------------
     328        // fast_cond_var
     329
     330        // The trimmed and slim condition variable
     331        // - no internal lock so you must hold a lock while using this cond var
     332        // - signalling without holding branded lock is UNSAFE!
     333        // - only allows usage of one lock, cond var is branded after usage
     334        struct fast_cond_var {
     335                // List of blocked threads
     336                dlist( info_thread(L) ) blocked_threads;
     337
     338                #ifdef __CFA_DEBUG__
     339                L * lock_used;
     340                #endif
     341        };
     342
     343
     344        void  ?{}( fast_cond_var(L) & this );
     345        void ^?{}( fast_cond_var(L) & this );
     346
     347        bool notify_one( fast_cond_var(L) & this );
     348        bool notify_all( fast_cond_var(L) & this );
     349
     350        uintptr_t front( fast_cond_var(L) & this );
     351
     352        bool empty  ( fast_cond_var(L) & this );
     353
     354        void wait( fast_cond_var(L) & this, L & l );
     355        void wait( fast_cond_var(L) & this, L & l, uintptr_t info );
     356}
Note: See TracChangeset for help on using the changeset viewer.