source: libcfa/src/concurrency/locks.cfa @ aeb31b1

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since aeb31b1 was 6a8882c, checked in by Colby Alexander Parsons <caparsons@…>, 4 years ago

fixed some bugs

  • Property mode set to 100644
File size: 13.0 KB
RevLine 
[848439f]1#include "locks.hfa"
2#include "kernel_private.hfa"
3#include <stdlib.h>
4#include <stdio.h>
5
6#include <kernel.hfa>
7#include <stdlib.hfa>
8#include <thread.hfa>
9
10///////////////////////////////////////////////////////////////////
11//// info_thread
12///////////////////////////////////////////////////////////////////
13forall(dtype L | is_blocking_lock(L)) {
14        void ?{}( info_thread(L) & this, $thread * t ) {
15                this.t = t;
16                this.lock = 0p;
[eeb5023]17                this.listed = false;
[848439f]18        }
19
20        void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) {
21                this.t = t;
22                this.info = info;
23                this.lock = 0p;
[eeb5023]24                this.listed = false;
[848439f]25        }
26
27        void ^?{}( info_thread(L) & this ){
28                // default
29        }
30
31        info_thread(L) *& get_next( info_thread(L) & this ) {
32                return this.next;
33        }
34}
35///////////////////////////////////////////////////////////////////
36//// Blocking Locks
37///////////////////////////////////////////////////////////////////
38
39void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {
40        this.lock{};
41        this.blocked_threads{};
42        this.wait_count = 0;
43        this.multi_acquisition = multi_acquisition;
44        this.strict_owner = strict_owner;
45        this.owner = 0p;
46        this.recursion_count = 0;
47}
48
49void ^?{}( blocking_lock & this ) {
50        // default
51}
52
[6a8882c]53void ?{}( single_acquisition_lock & this ) {
[848439f]54        ((blocking_lock &)this){ false, false };
55}
56
[6a8882c]57void ^?{}( single_acquisition_lock & this ) {
[848439f]58        // default
59}
60
61void ?{}( owner_lock & this ) {
62        ((blocking_lock &)this){ true, true };
63}
64
65void ^?{}( owner_lock & this ) {
66        // default
67}
68
[6a8882c]69void ?{}( multiple_acquisition_lock & this ) {
[848439f]70        ((blocking_lock &)this){ true, false };
71}
72
[6a8882c]73void ^?{}( multiple_acquisition_lock & this ) {
[848439f]74        // default
75}
76
77void lock( blocking_lock & this ) with( this ) {
78        lock( lock __cfaabi_dbg_ctx2 );
[6a8882c]79        if ( owner == active_thread() && !multi_acquisition) {
[848439f]80                fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead
[eeb5023]81        exit(EXIT_FAILURE);
[6a8882c]82        } else if ( owner != 0p && owner != active_thread() ) {
83                append( blocked_threads, active_thread() );
[848439f]84                wait_count++;
85                unlock( lock );
[eeb5023]86                park( );
[6a8882c]87        } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]88                recursion_count++;
89                unlock( lock );
90        } else {
[6a8882c]91                owner = active_thread();
[848439f]92                recursion_count = 1;
93                unlock( lock );
94        }
95}
96
97bool try_lock( blocking_lock & this ) with( this ) {
98        bool ret = false;
99        lock( lock __cfaabi_dbg_ctx2 );
100        if ( owner == 0p ) {
[6a8882c]101                owner = active_thread();
102                recursion_count = 1;
[848439f]103                ret = true;
[6a8882c]104        } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]105                recursion_count++;
106                ret = true;
107        }
108        unlock( lock );
109        return ret;
110}
111
112void unlock( blocking_lock & this ) with( this ) {
113        lock( lock __cfaabi_dbg_ctx2 );
114        if ( owner == 0p ){ // no owner implies lock isn't held
[6a8882c]115                fprintf( stderr, "There was an attempt to release a lock that isn't held" );
[848439f]116                return;
[6a8882c]117        } else if ( strict_owner && owner != active_thread() ) {
118                fprintf( stderr, "A thread other than the owner attempted to release an owner lock" );
[848439f]119                return;
120        }
121        recursion_count--;
122        if ( recursion_count == 0 ) {
123                $thread * thrd = pop_head( blocked_threads );
124                owner = thrd;
[6a8882c]125                recursion_count = ( thrd ? 1 : 0 );
[848439f]126                wait_count--;
[eeb5023]127                unpark( thrd );
[848439f]128        }
129        unlock( lock );
130}
131
132size_t wait_count( blocking_lock & this ) with( this ) {
133        return wait_count;
134}
135
136
137void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {
138        recursion_count = recursion;
139}
140
141size_t get_recursion_count( blocking_lock & this ) with( this ) {
142        return recursion_count;
143}
144
145void add_( blocking_lock & this, $thread * t ) with( this ) {
146    lock( lock __cfaabi_dbg_ctx2 );
147        if ( owner != 0p ) {
148                append( blocked_threads, t );
149                wait_count++;
150                unlock( lock );
151        } else {
152                owner = t;
[6a8882c]153                recursion_count = 1;
[eeb5023]154                #if !defined( __CFA_NO_STATISTICS__ )
[6a8882c]155                        //kernelTLS.this_stats = t->curr_cluster->stats;
[eeb5023]156                #endif
157                unpark( t );
[848439f]158                unlock( lock );
159        }
160}
161
162void remove_( blocking_lock & this ) with( this ) {
163    lock( lock __cfaabi_dbg_ctx2 );
164        if ( owner == 0p ){ // no owner implies lock isn't held
[6a8882c]165                fprintf( stderr, "A lock that is not held was passed to a synchronization lock" );
166        } else if ( strict_owner && owner != active_thread() ) {
167                fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" );
[848439f]168        } else {
169                $thread * thrd = pop_head( blocked_threads );
170                owner = thrd;
[6a8882c]171                recursion_count = ( thrd ? 1 : 0 );
[848439f]172                wait_count--;
[eeb5023]173                unpark( thrd );
[848439f]174        }
175        unlock( lock );
176}
177
178///////////////////////////////////////////////////////////////////
179//// Overloaded routines for traits
180///////////////////////////////////////////////////////////////////
181
[eeb5023]182// This is temporary until an inheritance bug is fixed
[848439f]183
[6a8882c]184void lock( single_acquisition_lock & this ){
185        lock( (blocking_lock &)this );
186}
187
188void unlock( single_acquisition_lock & this ){
189        unlock( (blocking_lock &)this );
190}
191
192void add_( single_acquisition_lock & this, struct $thread * t ){
193        add_( (blocking_lock &)this, t );
194}
195
196void remove_( single_acquisition_lock & this ){
197        remove_( (blocking_lock &)this );
198}
199
200void set_recursion_count( single_acquisition_lock & this, size_t recursion ){
201        set_recursion_count( (blocking_lock &)this, recursion );
202}
203
204size_t get_recursion_count( single_acquisition_lock & this ){
205        return get_recursion_count( (blocking_lock &)this );
206}
207
208void lock( owner_lock & this ){
[848439f]209        lock( (blocking_lock &)this );
210}
211
[6a8882c]212void unlock( owner_lock & this ){
[848439f]213        unlock( (blocking_lock &)this );
214}
215
[6a8882c]216void add_( owner_lock & this, struct $thread * t ){
[848439f]217        add_( (blocking_lock &)this, t );
218}
219
[6a8882c]220void remove_( owner_lock & this ){
[848439f]221        remove_( (blocking_lock &)this );
222}
223
[6a8882c]224void set_recursion_count( owner_lock & this, size_t recursion ){
[848439f]225        set_recursion_count( (blocking_lock &)this, recursion );
226}
227
[6a8882c]228size_t get_recursion_count( owner_lock & this ){
229        return get_recursion_count( (blocking_lock &)this );
[848439f]230}
231
[6a8882c]232void lock( multiple_acquisition_lock & this ){
[848439f]233        lock( (blocking_lock &)this );
234}
235
[6a8882c]236void unlock( multiple_acquisition_lock & this ){
[848439f]237        unlock( (blocking_lock &)this );
238}
239
[6a8882c]240void add_( multiple_acquisition_lock & this, struct $thread * t ){
[848439f]241        add_( (blocking_lock &)this, t );
242}
243
[6a8882c]244void remove_( multiple_acquisition_lock & this ){
[848439f]245        remove_( (blocking_lock &)this );
246}
247
[6a8882c]248void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){
[848439f]249        set_recursion_count( (blocking_lock &)this, recursion );
250}
251
[6a8882c]252size_t get_recursion_count( multiple_acquisition_lock & this ){
253        return get_recursion_count( (blocking_lock &)this );
[848439f]254}
255
256///////////////////////////////////////////////////////////////////
[eeb5023]257//// condition variable
[848439f]258///////////////////////////////////////////////////////////////////
259
260forall(dtype L | is_blocking_lock(L)) {
261
[c5bbb9b]262        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
[eeb5023]263        // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
264            lock( cond->lock __cfaabi_dbg_ctx2 );
265            if ( (*i)->listed ) {                       // is thread on queue
266                info_thread(L) * copy = *i;
267                        remove( cond->blocked_threads, i );              //remove this thread O(1)
[6a8882c]268                        cond->count--;
[eeb5023]269                        if( !copy->lock ) {
270                                #if !defined( __CFA_NO_STATISTICS__ )
[6a8882c]271                                        //kernelTLS.this_stats = copy->t->curr_cluster->stats;
[eeb5023]272                                #endif
273                                unpark( copy->t );
274                } else {
275                        add_(*copy->lock, copy->t);                     // call lock's add_
276                }
277            }
278            unlock( cond->lock );
[848439f]279        }
280
[eeb5023]281        void alarm_node_wrap_cast( alarm_node_t & a ) {
[c5bbb9b]282                timeout_handler( (alarm_node_wrap(L) &)a );
[848439f]283        }
284
285        void ?{}( condition_variable(L) & this ){
[eeb5023]286                this.lock{};
287                this.blocked_threads{};
288                this.count = 0;
[848439f]289        }
290
291        void ^?{}( condition_variable(L) & this ){
292                // default
293        }
294
[eeb5023]295        void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
296                this.alarm_node{ thrd, alarm, period, callback };
[848439f]297        }
298
[eeb5023]299        void ^?{}( alarm_node_wrap(L) & this ) {
[848439f]300                // default
301        }
302
[eeb5023]303        bool notify_one( condition_variable(L) & this ) with( this ) {
[848439f]304                lock( lock __cfaabi_dbg_ctx2 );
305                bool ret = !!blocked_threads;
306                info_thread(L) * popped = pop_head( blocked_threads );
307                if(popped != 0p) {
[6a8882c]308                        popped->listed = false;
[eeb5023]309                        count--;
[c5bbb9b]310                        if (popped->lock) {
[848439f]311                                add_(*popped->lock, popped->t);
312                        } else {
[c5bbb9b]313                                unpark(popped->t);
[848439f]314                        }
315                }
316                unlock( lock );
317                return ret;
318        }
319
[eeb5023]320        bool notify_all( condition_variable(L) & this ) with(this) {
[848439f]321                lock( lock __cfaabi_dbg_ctx2 );
322                bool ret = blocked_threads ? true : false;
323                while( blocked_threads ) {
324                        info_thread(L) * popped = pop_head( blocked_threads );
325                        if(popped != 0p){
[6a8882c]326                                popped->listed = false;
[eeb5023]327                                count--;
[c5bbb9b]328                                if (popped->lock) {
[848439f]329                                        add_(*popped->lock, popped->t);
330                                } else {
[c5bbb9b]331                                        unpark(popped->t);
[848439f]332                                }
333                        }
334                }
335                unlock( lock );
336                return ret;
337        }
338
[eeb5023]339        uintptr_t front( condition_variable(L) & this ) with(this) {
340                if(!blocked_threads) return NULL;
341                return peek(blocked_threads)->info;
[848439f]342        }
343
[eeb5023]344        bool empty( condition_variable(L) & this ) with(this) {
[848439f]345                return blocked_threads ? false : true;
346        }
347
[eeb5023]348        int counter( condition_variable(L) & this ) with(this) {
[848439f]349                return count;
350        }
351
[eeb5023]352        // helper for wait()'s' without a timeout
353        void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
[848439f]354                lock( lock __cfaabi_dbg_ctx2 );
[eeb5023]355                append( this.blocked_threads, &i );
[848439f]356                count++;
[eeb5023]357                i.listed = true;
358                size_t recursion_count;
359                if (i.lock) {
360                        recursion_count = get_recursion_count(*i.lock);
361                        remove_( *i.lock );
362                }
[6a8882c]363               
[848439f]364                unlock( lock );
[eeb5023]365                park( ); // blocks here
[848439f]366
[eeb5023]367                if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
[848439f]368        }
369
[eeb5023]370        // helper for wait()'s' with a timeout
371        void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
372                lock( lock __cfaabi_dbg_ctx2 );
[848439f]373
[eeb5023]374                info_thread(L) * queue_ptr = &info;
[848439f]375
[eeb5023]376                alarm_node_wrap(L) node_wrap = { info.t, t, 0`s, alarm_node_wrap_cast };
377                node_wrap.cond = &this;
378                node_wrap.i = &queue_ptr;
[848439f]379
[eeb5023]380                register_self( &node_wrap.alarm_node );
[848439f]381
[eeb5023]382                append( blocked_threads, queue_ptr );
383                info.listed = true;
[848439f]384                count++;
[eeb5023]385
386                size_t recursion_count;
387                if (info.lock) {
388                        recursion_count = get_recursion_count(*info.lock);
389                        remove_( *info.lock );
390                }
391
[848439f]392                unlock( lock );
[eeb5023]393                park();
[848439f]394
[eeb5023]395                if (info.lock) set_recursion_count(*info.lock, recursion_count);
[848439f]396        }
397
[eeb5023]398        void wait( condition_variable(L) & this ) with(this) {
[3959595]399                info_thread( L ) i = { active_thread() };
[848439f]400                queue_info_thread( this, i );
401        }
402
[eeb5023]403        void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
[3959595]404                info_thread( L ) i = { active_thread(), info };
[848439f]405                queue_info_thread( this, i );
406        }
[6a8882c]407       
[eeb5023]408        void wait( condition_variable(L) & this, Duration duration ) with(this) {
[3959595]409                info_thread( L ) i = { active_thread() };
[eeb5023]410                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]411        }
412
[6a8882c]413        void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
[3959595]414                info_thread( L ) i = { active_thread(), info };
[eeb5023]415                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]416        }
417
[eeb5023]418        void wait( condition_variable(L) & this, Time time ) with(this) {
[3959595]419                info_thread( L ) i = { active_thread() };
[eeb5023]420                queue_info_thread_timeout(this, i, time);
[848439f]421        }
422
[eeb5023]423        void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
[3959595]424                info_thread( L ) i = { active_thread(), info };
[eeb5023]425                queue_info_thread_timeout(this, i, time);
[848439f]426        }
427
[eeb5023]428        void wait( condition_variable(L) & this, L & l ) with(this) {
[3959595]429                info_thread(L) i = { active_thread() };
[eeb5023]430                i.lock = &l;
431                queue_info_thread( this, i );
[848439f]432        }
433
[eeb5023]434        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
[3959595]435                info_thread(L) i = { active_thread(), info };
[eeb5023]436                i.lock = &l;
437                queue_info_thread( this, i );
[848439f]438        }
[6a8882c]439       
[eeb5023]440        void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
[3959595]441                info_thread(L) i = { active_thread() };
[eeb5023]442                i.lock = &l;
443                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]444        }
[6a8882c]445       
[eeb5023]446        void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
[3959595]447                info_thread(L) i = { active_thread(), info };
[eeb5023]448                i.lock = &l;
449                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]450        }
[6a8882c]451       
[eeb5023]452        void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
[3959595]453                info_thread(L) i = { active_thread() };
[eeb5023]454                i.lock = &l;
455                queue_info_thread_timeout(this, i, time );
[848439f]456        }
[6a8882c]457       
[eeb5023]458        void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
[3959595]459                info_thread(L) i = { active_thread(), info };
[eeb5023]460                i.lock = &l;
461                queue_info_thread_timeout(this, i, time );
[848439f]462        }
463}
[6a8882c]464
465// thread T1 {};
466// thread T2 {};
467
468// multiple_acquisition_lock m;
469// condition_variable( multiple_acquisition_lock ) c;
470
471// void main( T1 & this ) {
472//      printf("T1 start\n");
473//      lock(m);
474//      printf("%d\n", counter(c));
475//      if(empty(c)) {
476//              printf("T1 wait\n");
477//              wait(c,m,12);
478//      }else{
479//              printf("%d\n", front(c));
480//              notify_one(c);
481//      }
482//      unlock(m);
483//      printf("curr thd in main %p \n", active_thread());
484//      printf("T1 waits for 2s\n");
485//      lock(m);
486//      wait( c, m, 2`s );
487//      unlock(m);
488//      printf("T1 wakes\n");
489//      printf("T1 done\n");
490// }
491
492// void main( T2 & this ) {
493//      printf("T2 start\n");
494//      lock(m);
495//      printf("%d\n", counter(c));
496//      if(empty(c)) {
497//              printf("T2 wait\n");
498//              wait(c,m,12);
499//      }else{
500//              printf("%d\n", front(c));
501//              notify_one(c);
502//      }
503//      unlock(m);
504//      printf("T2 done\n");
505// }
506
507// int main() {
508//      printf("start\n");
509//      processor p[2];
510//      {
511//              T1 t1;
512//              T2 t2;
513//      }
514//      printf("done\n");
515// }
Note: See TracBrowser for help on using the repository browser.