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

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

added bool return to timeout routines and removed redundant listed field

  • Property mode set to 100644
File size: 11.7 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///////////////////////////////////////////////////////////////////
[cad1df1]13
[848439f]14forall(dtype L | is_blocking_lock(L)) {
15        void ?{}( info_thread(L) & this, $thread * t ) {
[cad1df1]16                ((Seqable &) this){};
[848439f]17                this.t = t;
18                this.lock = 0p;
19        }
20
21        void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) {
[cad1df1]22                ((Seqable &) this){};
[848439f]23                this.t = t;
24                this.info = info;
25                this.lock = 0p;
26        }
27
[cad1df1]28        void ^?{}( info_thread(L) & this ){ }
[c131a02]29
30        info_thread(L) *& Back( info_thread(L) * this ) {
31                return (info_thread(L) *)Back( (Seqable *)this );
32        }
33
34        info_thread(L) *& Next( info_thread(L) * this ) {
35                return (info_thread(L) *)Next( (Colable *)this );
36        }
[848439f]37}
[cad1df1]38
[848439f]39///////////////////////////////////////////////////////////////////
40//// Blocking Locks
41///////////////////////////////////////////////////////////////////
42
43void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {
44        this.lock{};
45        this.blocked_threads{};
46        this.wait_count = 0;
47        this.multi_acquisition = multi_acquisition;
48        this.strict_owner = strict_owner;
49        this.owner = 0p;
50        this.recursion_count = 0;
51}
52
[cad1df1]53void ^?{}( blocking_lock & this ) {}
54void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
55void ^?{}( single_acquisition_lock & this ) {}
56void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
57void ^?{}( owner_lock & this ) {}
58void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
59void ^?{}( multiple_acquisition_lock & this ) {}
[848439f]60
61void lock( blocking_lock & this ) with( this ) {
62        lock( lock __cfaabi_dbg_ctx2 );
[6a8882c]63        if ( owner == active_thread() && !multi_acquisition) {
[cad1df1]64                abort("A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock.");
[6a8882c]65        } else if ( owner != 0p && owner != active_thread() ) {
[c131a02]66                addTail( blocked_threads, *active_thread() );
[848439f]67                wait_count++;
68                unlock( lock );
[eeb5023]69                park( );
[6a8882c]70        } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]71                recursion_count++;
72                unlock( lock );
73        } else {
[6a8882c]74                owner = active_thread();
[848439f]75                recursion_count = 1;
76                unlock( lock );
77        }
78}
79
80bool try_lock( blocking_lock & this ) with( this ) {
81        bool ret = false;
82        lock( lock __cfaabi_dbg_ctx2 );
83        if ( owner == 0p ) {
[6a8882c]84                owner = active_thread();
85                recursion_count = 1;
[848439f]86                ret = true;
[6a8882c]87        } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]88                recursion_count++;
89                ret = true;
90        }
91        unlock( lock );
92        return ret;
93}
94
[cad1df1]95void unlock_error_check( blocking_lock & this ) with( this ) {
[848439f]96        if ( owner == 0p ){ // no owner implies lock isn't held
[cad1df1]97                abort( "There was an attempt to release a lock that isn't held" );
[6a8882c]98        } else if ( strict_owner && owner != active_thread() ) {
[cad1df1]99                abort( "A thread other than the owner attempted to release an owner lock" );
[848439f]100        }
[cad1df1]101}
102
103void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
[c131a02]104        $thread * t = &dropHead( blocked_threads );
[cad1df1]105        owner = t;
106        recursion_count = ( t ? 1 : 0 );
107        wait_count--;
108        unpark( t );
109}
110
111void unlock( blocking_lock & this ) with( this ) {
112        lock( lock __cfaabi_dbg_ctx2 );
113        unlock_error_check( this );
[848439f]114        recursion_count--;
115        if ( recursion_count == 0 ) {
[cad1df1]116                pop_and_set_new_owner( this );
[848439f]117        }
118        unlock( lock );
119}
120
121size_t wait_count( blocking_lock & this ) with( this ) {
122        return wait_count;
123}
124
125void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {
126        recursion_count = recursion;
127}
128
129size_t get_recursion_count( blocking_lock & this ) with( this ) {
130        return recursion_count;
131}
132
133void add_( blocking_lock & this, $thread * t ) with( this ) {
134    lock( lock __cfaabi_dbg_ctx2 );
135        if ( owner != 0p ) {
[c131a02]136                addTail( blocked_threads, *t );
[848439f]137                wait_count++;
138                unlock( lock );
139        } else {
140                owner = t;
[6a8882c]141                recursion_count = 1;
[eeb5023]142                unpark( t );
[848439f]143                unlock( lock );
144        }
145}
146
147void remove_( blocking_lock & this ) with( this ) {
148    lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]149        unlock_error_check( this );
150        pop_and_set_new_owner( this );
[848439f]151        unlock( lock );
152}
153
154///////////////////////////////////////////////////////////////////
155//// Overloaded routines for traits
156///////////////////////////////////////////////////////////////////
157
[eeb5023]158// This is temporary until an inheritance bug is fixed
[848439f]159
[cad1df1]160void lock( single_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
161void unlock( single_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
162void add_( single_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
163void remove_( single_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
164void set_recursion_count( single_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
165size_t get_recursion_count( single_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
166
167void lock( owner_lock & this ){ lock( (blocking_lock &)this ); }
168void unlock( owner_lock & this ){ unlock( (blocking_lock &)this ); }
169void add_( owner_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
170void remove_( owner_lock & this ){ remove_( (blocking_lock &)this ); }
171void set_recursion_count( owner_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
172size_t get_recursion_count( owner_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
173
174void lock( multiple_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
175void unlock( multiple_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
176void add_( multiple_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
177void remove_( multiple_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
178void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
179size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
[848439f]180
181///////////////////////////////////////////////////////////////////
[eeb5023]182//// condition variable
[848439f]183///////////////////////////////////////////////////////////////////
184
185forall(dtype L | is_blocking_lock(L)) {
186
[c5bbb9b]187        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
[eeb5023]188        // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
189            lock( cond->lock __cfaabi_dbg_ctx2 );
[dff1fd1]190            if ( listed(i) ) {                  // is thread on queue
191                i->signalled = false;
[cad1df1]192                cond->last_thread = i;          // REMOVE THIS AFTER DEBUG
193                        remove( cond->blocked_threads, *i );             //remove this thread O(1)
[6a8882c]194                        cond->count--;
[cad1df1]195                        if( !i->lock ) {
196                                unpark( i->t );
[eeb5023]197                } else {
[cad1df1]198                        add_(*i->lock, i->t);                   // call lock's add_
[eeb5023]199                }
200            }
201            unlock( cond->lock );
[848439f]202        }
203
[cad1df1]204        void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
[848439f]205
206        void ?{}( condition_variable(L) & this ){
[eeb5023]207                this.lock{};
208                this.blocked_threads{};
209                this.count = 0;
[cad1df1]210                this.last_thread = 0p; // REMOVE AFTER DEBUG
[848439f]211        }
212
[cad1df1]213        void ^?{}( condition_variable(L) & this ){ }
[848439f]214
[4aeaee5]215        void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback ) {
216                this.alarm_node{ callback, alarm, period };
[848439f]217        }
218
[cad1df1]219        void ^?{}( alarm_node_wrap(L) & this ) { }
[848439f]220
[cad1df1]221        void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
222                if(&popped != 0p) {
[dff1fd1]223                        popped.signalled = true;
[eeb5023]224                        count--;
[cad1df1]225                        if (popped.lock) {
226                                add_(*popped.lock, popped.t);
[848439f]227                        } else {
[cad1df1]228                                unpark(popped.t);
[848439f]229                        }
230                }
[cad1df1]231        }
232
233        bool notify_one( condition_variable(L) & this ) with( this ) {
234                lock( lock __cfaabi_dbg_ctx2 );
235                bool ret = !empty(blocked_threads);
236                process_popped(this, dropHead( blocked_threads ));
[848439f]237                unlock( lock );
238                return ret;
239        }
240
[eeb5023]241        bool notify_all( condition_variable(L) & this ) with(this) {
[848439f]242                lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]243                bool ret = !empty(blocked_threads);
244                while( !empty(blocked_threads) ) {
245                        process_popped(this, dropHead( blocked_threads ));
[848439f]246                }
247                unlock( lock );
248                return ret;
249        }
250
[eeb5023]251        uintptr_t front( condition_variable(L) & this ) with(this) {
[cad1df1]252                return empty(blocked_threads) ? NULL : head(blocked_threads).info;
[848439f]253        }
254
[cad1df1]255        bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); }
256
257        int counter( condition_variable(L) & this ) with(this) { return count; }
[848439f]258
[cad1df1]259        size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
260                addTail( blocked_threads, *i );
261                count++;
262                size_t recursion_count = 0;
263                if (i->lock) {
264                        recursion_count = get_recursion_count(*i->lock);
265                        remove_( *i->lock );
266                }
267                return recursion_count;
[848439f]268        }
269
[cad1df1]270        // helper for wait()'s' with no timeout
[eeb5023]271        void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
[848439f]272                lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]273                size_t recursion_count = queue_and_get_recursion(this, &i);
[848439f]274                unlock( lock );
[eeb5023]275                park( ); // blocks here
276                if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
[848439f]277        }
278
[eeb5023]279        // helper for wait()'s' with a timeout
280        void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
281                lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]282                size_t recursion_count = queue_and_get_recursion(this, &info);
[4aeaee5]283                alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast };
[eeb5023]284                node_wrap.cond = &this;
[cad1df1]285                node_wrap.i = &info;
[eeb5023]286                register_self( &node_wrap.alarm_node );
[848439f]287                unlock( lock );
[eeb5023]288                park();
[cad1df1]289                unregister_self( &node_wrap.alarm_node );
[eeb5023]290                if (info.lock) set_recursion_count(*info.lock, recursion_count);
[848439f]291        }
292
[eeb5023]293        void wait( condition_variable(L) & this ) with(this) {
[3959595]294                info_thread( L ) i = { active_thread() };
[848439f]295                queue_info_thread( this, i );
296        }
297
[eeb5023]298        void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
[3959595]299                info_thread( L ) i = { active_thread(), info };
[848439f]300                queue_info_thread( this, i );
301        }
[6a8882c]302       
[dff1fd1]303        bool wait( condition_variable(L) & this, Duration duration ) with(this) {
[3959595]304                info_thread( L ) i = { active_thread() };
[eeb5023]305                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[dff1fd1]306                return i.signalled;
[848439f]307        }
308
[dff1fd1]309        bool wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
[3959595]310                info_thread( L ) i = { active_thread(), info };
[eeb5023]311                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[dff1fd1]312                return i.signalled;
[848439f]313        }
314
[dff1fd1]315        bool wait( condition_variable(L) & this, Time time ) with(this) {
[3959595]316                info_thread( L ) i = { active_thread() };
[eeb5023]317                queue_info_thread_timeout(this, i, time);
[dff1fd1]318                return i.signalled;
[848439f]319        }
320
[dff1fd1]321        bool wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
[3959595]322                info_thread( L ) i = { active_thread(), info };
[eeb5023]323                queue_info_thread_timeout(this, i, time);
[dff1fd1]324                return i.signalled;
[848439f]325        }
326
[eeb5023]327        void wait( condition_variable(L) & this, L & l ) with(this) {
[3959595]328                info_thread(L) i = { active_thread() };
[eeb5023]329                i.lock = &l;
330                queue_info_thread( this, i );
[848439f]331        }
332
[eeb5023]333        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
[3959595]334                info_thread(L) i = { active_thread(), info };
[eeb5023]335                i.lock = &l;
336                queue_info_thread( this, i );
[848439f]337        }
[6a8882c]338       
[dff1fd1]339        bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
[3959595]340                info_thread(L) i = { active_thread() };
[eeb5023]341                i.lock = &l;
342                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[dff1fd1]343                return i.signalled;
[848439f]344        }
[6a8882c]345       
[dff1fd1]346        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
[3959595]347                info_thread(L) i = { active_thread(), info };
[eeb5023]348                i.lock = &l;
349                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[dff1fd1]350                return i.signalled;
[848439f]351        }
[6a8882c]352       
[dff1fd1]353        bool wait( condition_variable(L) & this, L & l, Time time ) with(this) {
[3959595]354                info_thread(L) i = { active_thread() };
[eeb5023]355                i.lock = &l;
356                queue_info_thread_timeout(this, i, time );
[dff1fd1]357                return i.signalled;
[848439f]358        }
[6a8882c]359       
[dff1fd1]360        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
[3959595]361                info_thread(L) i = { active_thread(), info };
[eeb5023]362                i.lock = &l;
363                queue_info_thread_timeout(this, i, time );
[dff1fd1]364                return i.signalled;
[848439f]365        }
366}
Note: See TracBrowser for help on using the repository browser.