source: libcfa/src/concurrency/locks.cfa @ 34dcc78c

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

added alarm callback to union and refactored

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