Ignore:
File:
1 edited

Legend:

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

    rac5816d r4aeaee5  
    11#include "locks.hfa"
    22#include "kernel_private.hfa"
     3#include <stdlib.h>
     4#include <stdio.h>
    35
    46#include <kernel.hfa>
    57#include <stdlib.hfa>
    6 
    7 //-----------------------------------------------------------------------------
    8 // info_thread
     8#include <thread.hfa>
     9
     10///////////////////////////////////////////////////////////////////
     11//// info_thread
     12///////////////////////////////////////////////////////////////////
     13
    914forall(dtype L | is_blocking_lock(L)) {
    10         struct info_thread {
    11                 // used to put info_thread on a dl queue (aka sequence)
    12                 inline Seqable;
    13 
    14                 // waiting thread
    15                 struct $thread * t;
    16 
    17                 // shadow field
    18                 uintptr_t info;
    19 
    20                 // lock that is passed to wait() (if one is passed)
    21                 L * lock;
    22 
    23                 // true when signalled and false when timeout wakes thread
    24                 bool signalled;
    25         };
    26 
    27         void ?{}( info_thread(L) & this, $thread * t, uintptr_t info, L * l ) {
     15        void ?{}( info_thread(L) & this, $thread * t ) {
     16                ((Seqable &) this){};
     17                this.t = t;
     18                this.lock = 0p;
     19                this.listed = false;
     20        }
     21
     22        void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) {
    2823                ((Seqable &) this){};
    2924                this.t = t;
    3025                this.info = info;
    31                 this.lock = l;
    32         }
    33 
    34         void ^?{}( info_thread(L) & this ) {}
    35 
    36         info_thread(L) *& Back( info_thread(L) * this ) {
    37                 return (info_thread(L) *)Back( (Seqable *)this );
    38         }
    39 
    40         info_thread(L) *& Next( info_thread(L) * this ) {
    41                 return (info_thread(L) *)Next( (Colable *)this );
    42         }
    43 }
    44 
    45 //-----------------------------------------------------------------------------
    46 // Blocking Locks
     26                this.lock = 0p;
     27                this.listed = false;
     28        }
     29
     30        void ^?{}( info_thread(L) & this ){ }
     31}
     32
     33///////////////////////////////////////////////////////////////////
     34//// Blocking Locks
     35///////////////////////////////////////////////////////////////////
     36
    4737void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {
    4838        this.lock{};
     
    5646
    5747void ^?{}( blocking_lock & this ) {}
    58 void  ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
     48void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
    5949void ^?{}( single_acquisition_lock & this ) {}
    60 void  ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
     50void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
    6151void ^?{}( owner_lock & this ) {}
    62 void  ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
     52void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
    6353void ^?{}( multiple_acquisition_lock & this ) {}
    6454
    6555void lock( blocking_lock & this ) with( this ) {
    6656        lock( lock __cfaabi_dbg_ctx2 );
    67         $thread * thrd = active_thread();
    68 
    69         // single acquisition lock is held by current thread
    70         /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this );
    71 
    72         // lock is held by some other thread
    73         if ( owner != 0p && owner != thrd ) {
    74                 addTail( blocked_threads, *thrd );
     57        if ( owner == active_thread() && !multi_acquisition) {
     58                abort("A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock.");
     59        } else if ( owner != 0p && owner != active_thread() ) {
     60                append( blocked_threads, active_thread() );
    7561                wait_count++;
    7662                unlock( lock );
    7763                park( );
    78         }
    79         // multi acquisition lock is held by current thread
    80         else if ( owner == thrd && multi_acquisition ) {
     64        } else if ( owner == active_thread() && multi_acquisition ) {
    8165                recursion_count++;
    8266                unlock( lock );
    83         }
    84         // lock isn't held
    85         else {
    86                 owner = thrd;
     67        } else {
     68                owner = active_thread();
    8769                recursion_count = 1;
    8870                unlock( lock );
     
    9375        bool ret = false;
    9476        lock( lock __cfaabi_dbg_ctx2 );
    95 
    96         // lock isn't held
    9777        if ( owner == 0p ) {
    9878                owner = active_thread();
    9979                recursion_count = 1;
    10080                ret = true;
    101         }
    102         // multi acquisition lock is held by current thread
    103         else if ( owner == active_thread() && multi_acquisition ) {
     81        } else if ( owner == active_thread() && multi_acquisition ) {
    10482                recursion_count++;
    10583                ret = true;
    10684        }
    107 
    10885        unlock( lock );
    10986        return ret;
    11087}
    11188
     89void unlock_error_check( blocking_lock & this ) with( this ) {
     90        if ( owner == 0p ){ // no owner implies lock isn't held
     91                abort( "There was an attempt to release a lock that isn't held" );
     92        } else if ( strict_owner && owner != active_thread() ) {
     93                abort( "A thread other than the owner attempted to release an owner lock" );
     94        }
     95}
     96
    11297void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
    113         $thread * t = &dropHead( blocked_threads );
     98        $thread * t = pop_head( blocked_threads );
    11499        owner = t;
    115100        recursion_count = ( t ? 1 : 0 );
     
    120105void unlock( blocking_lock & this ) with( this ) {
    121106        lock( lock __cfaabi_dbg_ctx2 );
    122         /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    123         /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    124 
    125         // if recursion count is zero release lock and set new owner if one is waiting
     107        unlock_error_check( this );
    126108        recursion_count--;
    127109        if ( recursion_count == 0 ) {
     
    143125}
    144126
    145 void on_notify( blocking_lock & this, $thread * t ) with( this ) {
    146         lock( lock __cfaabi_dbg_ctx2 );
    147         // lock held
     127void add_( blocking_lock & this, $thread * t ) with( this ) {
     128    lock( lock __cfaabi_dbg_ctx2 );
    148129        if ( owner != 0p ) {
    149                 addTail( blocked_threads, *t );
     130                append( blocked_threads, t );
    150131                wait_count++;
    151132                unlock( lock );
    152         }
    153         // lock not held
    154         else {
     133        } else {
    155134                owner = t;
    156135                recursion_count = 1;
     
    160139}
    161140
    162 void on_wait( blocking_lock & this ) with( this ) {
    163         lock( lock __cfaabi_dbg_ctx2 );
    164         /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    165         /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    166 
     141void remove_( blocking_lock & this ) with( this ) {
     142    lock( lock __cfaabi_dbg_ctx2 );
     143        unlock_error_check( this );
    167144        pop_and_set_new_owner( this );
    168145        unlock( lock );
    169146}
    170147
    171 //-----------------------------------------------------------------------------
    172 // Overloaded routines for traits
    173 // These routines are temporary until an inheritance bug is fixed
    174 void   lock      ( single_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
    175 void   unlock    ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
    176 void   on_wait   ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
    177 void   on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    178 void   set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
    179 size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
    180 
    181 void   lock     ( owner_lock & this ) { lock   ( (blocking_lock &)this ); }
    182 void   unlock   ( owner_lock & this ) { unlock ( (blocking_lock &)this ); }
    183 void   on_wait  ( owner_lock & this ) { on_wait( (blocking_lock &)this ); }
    184 void   on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    185 void   set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
    186 size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
    187 
    188 void   lock     ( multiple_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
    189 void   unlock   ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
    190 void   on_wait  ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
    191 void   on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); }
    192 void   set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
     148///////////////////////////////////////////////////////////////////
     149//// Overloaded routines for traits
     150///////////////////////////////////////////////////////////////////
     151
     152// This is temporary until an inheritance bug is fixed
     153
     154void lock( single_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
     155void unlock( single_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
     156void add_( single_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
     157void remove_( single_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
     158void set_recursion_count( single_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
     159size_t get_recursion_count( single_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
     160
     161void lock( owner_lock & this ){ lock( (blocking_lock &)this ); }
     162void unlock( owner_lock & this ){ unlock( (blocking_lock &)this ); }
     163void add_( owner_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
     164void remove_( owner_lock & this ){ remove_( (blocking_lock &)this ); }
     165void set_recursion_count( owner_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
     166size_t get_recursion_count( owner_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
     167
     168void lock( multiple_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
     169void unlock( multiple_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
     170void add_( multiple_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
     171void remove_( multiple_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
     172void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
    193173size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
    194174
    195 //-----------------------------------------------------------------------------
    196 // alarm node wrapper
     175///////////////////////////////////////////////////////////////////
     176//// condition variable
     177///////////////////////////////////////////////////////////////////
     178
    197179forall(dtype L | is_blocking_lock(L)) {
    198         struct alarm_node_wrap {
    199                 alarm_node_t alarm_node;
    200                 condition_variable(L) * cond;
    201                 info_thread(L) * i;
    202         };
    203 
    204         void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) {
    205                 this.alarm_node{ callback, alarm, period };
    206                 this.cond = c;
    207                 this.i = i;
    208         }
    209 
    210         void ^?{}( alarm_node_wrap(L) & this ) { }
    211180
    212181        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
    213                 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
    214                 lock( cond->lock __cfaabi_dbg_ctx2 );
    215 
    216                 // this check is necessary to avoid a race condition since this timeout handler
    217                 //      may still be called after a thread has been removed from the queue but
    218                 //      before the alarm is unregistered
    219                 if ( listed(i) ) {      // is thread on queue
    220                         i->signalled = false;
    221                         // remove this thread O(1)
    222                         remove( cond->blocked_threads, *i );
     182        // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
     183            lock( cond->lock __cfaabi_dbg_ctx2 );
     184           
     185            if ( i->listed ) {                  // is thread on queue
     186                cond->last_thread = i;          // REMOVE THIS AFTER DEBUG
     187                        remove( cond->blocked_threads, *i );             //remove this thread O(1)
    223188                        cond->count--;
    224                         if( i->lock ) {
    225                                 // call lock's on_notify if a lock was passed
    226                                 on_notify(*i->lock, i->t);
    227                         } else {
    228                                 // otherwise wake thread
     189                        if( !i->lock ) {
    229190                                unpark( i->t );
    230                         }
    231                 }
    232                 unlock( cond->lock );
    233         }
    234 
    235         // this casts the alarm node to our wrapped type since we used type erasure
     191                } else {
     192                        add_(*i->lock, i->t);                   // call lock's add_
     193                }
     194            }
     195            unlock( cond->lock );
     196        }
     197
    236198        void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
    237 }
    238 
    239 //-----------------------------------------------------------------------------
    240 // condition variable
    241 forall(dtype L | is_blocking_lock(L)) {
    242199
    243200        void ?{}( condition_variable(L) & this ){
     
    245202                this.blocked_threads{};
    246203                this.count = 0;
     204                this.last_thread = 0p; // REMOVE AFTER DEBUG
    247205        }
    248206
    249207        void ^?{}( condition_variable(L) & this ){ }
     208
     209        void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback ) {
     210                this.alarm_node{ callback, alarm, period };
     211        }
     212
     213        void ^?{}( alarm_node_wrap(L) & this ) { }
    250214
    251215        void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
    252216                if(&popped != 0p) {
    253                         popped.signalled = true;
     217                        popped.listed = false;
    254218                        count--;
    255219                        if (popped.lock) {
    256                                 // if lock passed call on_notify
    257                                 on_notify(*popped.lock, popped.t);
     220                                add_(*popped.lock, popped.t);
    258221                        } else {
    259                                 // otherwise wake thread
    260222                                unpark(popped.t);
    261223                        }
     
    290252
    291253        size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    292                 // add info_thread to waiting queue
    293254                addTail( blocked_threads, *i );
    294255                count++;
     256                i->listed = true;
    295257                size_t recursion_count = 0;
    296258                if (i->lock) {
    297                         // if lock was passed get recursion count to reset to after waking thread
     259                        i->t->link.next = 1p;
    298260                        recursion_count = get_recursion_count(*i->lock);
    299                         on_wait( *i->lock );
     261                        remove_( *i->lock );
    300262                }
    301263                return recursion_count;
     
    307269                size_t recursion_count = queue_and_get_recursion(this, &i);
    308270                unlock( lock );
    309 
    310                 // blocks here
    311                 park( );
    312 
    313                 // resets recursion count here after waking
    314                 if (i.lock) set_recursion_count(*i.lock, recursion_count);
    315         }
    316 
    317         #define WAIT( u, l ) \
    318                 info_thread( L ) i = { active_thread(), u, l }; \
    319                 queue_info_thread( this, i );
     271                park( ); // blocks here
     272                if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
     273        }
    320274
    321275        // helper for wait()'s' with a timeout
     
    323277                lock( lock __cfaabi_dbg_ctx2 );
    324278                size_t recursion_count = queue_and_get_recursion(this, &info);
    325                 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast, &this, &info };
     279                alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast };
     280                node_wrap.cond = &this;
     281                node_wrap.i = &info;
    326282                register_self( &node_wrap.alarm_node );
    327283                unlock( lock );
    328 
    329                 // blocks here
    330284                park();
    331 
    332                 // unregisters alarm so it doesn't go off if this happens first
    333285                unregister_self( &node_wrap.alarm_node );
    334 
    335                 // resets recursion count here after waking
    336286                if (info.lock) set_recursion_count(*info.lock, recursion_count);
    337287        }
    338288
    339         #define WAIT_TIME( u, l, t ) \
    340                 info_thread( L ) i = { active_thread(), u, l }; \
    341                 queue_info_thread_timeout(this, i, t ); \
    342                 return i.signalled;
    343 
    344         void wait( condition_variable(L) & this                        ) with(this) { WAIT( 0, 0p    ) }
    345         void wait( condition_variable(L) & this, uintptr_t info        ) with(this) { WAIT( info, 0p ) }
    346         void wait( condition_variable(L) & this, L & l                 ) with(this) { WAIT( 0, &l    ) }
    347         void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { WAIT( info, &l ) }
    348 
    349         bool wait( condition_variable(L) & this, Duration duration                        ) with(this) { WAIT_TIME( 0   , 0p , __kernel_get_time() + duration ) }
    350         bool wait( condition_variable(L) & this, uintptr_t info, Duration duration        ) with(this) { WAIT_TIME( info, 0p , __kernel_get_time() + duration ) }
    351         bool wait( condition_variable(L) & this, Time time                                ) with(this) { WAIT_TIME( 0   , 0p , time ) }
    352         bool wait( condition_variable(L) & this, uintptr_t info, Time time                ) with(this) { WAIT_TIME( info, 0p , time ) }
    353         bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , __kernel_get_time() + duration ) }
    354         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , __kernel_get_time() + duration ) }
    355         bool wait( condition_variable(L) & this, L & l, Time time                         ) with(this) { WAIT_TIME( 0   , &l , time ) }
    356         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time         ) with(this) { WAIT_TIME( info, &l , time ) }
    357 }
     289        void wait( condition_variable(L) & this ) with(this) {
     290                info_thread( L ) i = { active_thread() };
     291                queue_info_thread( this, i );
     292        }
     293
     294        void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
     295                info_thread( L ) i = { active_thread(), info };
     296                queue_info_thread( this, i );
     297        }
     298       
     299        void wait( condition_variable(L) & this, Duration duration ) with(this) {
     300                info_thread( L ) i = { active_thread() };
     301                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     302        }
     303
     304        void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
     305                info_thread( L ) i = { active_thread(), info };
     306                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     307        }
     308
     309        void wait( condition_variable(L) & this, Time time ) with(this) {
     310                info_thread( L ) i = { active_thread() };
     311                queue_info_thread_timeout(this, i, time);
     312        }
     313
     314        void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
     315                info_thread( L ) i = { active_thread(), info };
     316                queue_info_thread_timeout(this, i, time);
     317        }
     318
     319        void wait( condition_variable(L) & this, L & l ) with(this) {
     320                info_thread(L) i = { active_thread() };
     321                i.lock = &l;
     322                queue_info_thread( this, i );
     323        }
     324
     325        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
     326                info_thread(L) i = { active_thread(), info };
     327                i.lock = &l;
     328                queue_info_thread( this, i );
     329        }
     330       
     331        void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
     332                info_thread(L) i = { active_thread() };
     333                i.lock = &l;
     334                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     335        }
     336       
     337        void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
     338                info_thread(L) i = { active_thread(), info };
     339                i.lock = &l;
     340                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     341        }
     342       
     343        void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
     344                info_thread(L) i = { active_thread() };
     345                i.lock = &l;
     346                queue_info_thread_timeout(this, i, time );
     347        }
     348       
     349        void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
     350                info_thread(L) i = { active_thread(), info };
     351                i.lock = &l;
     352                queue_info_thread_timeout(this, i, time );
     353        }
     354}
Note: See TracChangeset for help on using the changeset viewer.