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

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

removed test program from locks.cfa

  • Property mode set to 100644
File size: 11.6 KB
Line 
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;
17                this.listed = false;
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;
24                this.listed = false;
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
53void ?{}( mutex_lock & this ) {
54        ((blocking_lock &)this){ false, false };
55}
56
57void ^?{}( mutex_lock & this ) {
58        // default
59}
60
61void ?{}( owner_lock & this ) {
62        ((blocking_lock &)this){ true, true };
63}
64
65void ^?{}( owner_lock & this ) {
66        // default
67}
68
69void ?{}( recursive_mutex_lock & this ) {
70        ((blocking_lock &)this){ true, false };
71}
72
73void ^?{}( recursive_mutex_lock & this ) {
74        // default
75}
76
77void lock( blocking_lock & this ) with( this ) {
78        lock( lock __cfaabi_dbg_ctx2 );
79        if ( owner == kernelTLS.this_thread && !multi_acquisition) {
80                fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead
81        exit(EXIT_FAILURE);
82        } else if ( owner != 0p && owner != kernelTLS.this_thread ) {
83                append( blocked_threads, kernelTLS.this_thread );
84                wait_count++;
85                unlock( lock );
86                park( );
87        } else if ( owner == kernelTLS.this_thread && multi_acquisition ) {
88                recursion_count++;
89                unlock( lock );
90        } else {
91                owner = kernelTLS.this_thread;
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 ) {
101                owner = kernelTLS.this_thread;
102                if ( multi_acquisition ) recursion_count = 1;
103                ret = true;
104        } else if ( owner == kernelTLS.this_thread && multi_acquisition ) {
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
115                fprintf( stderr, "There was an attempt to release a lock that isn't held" );
116                return;
117        } else if ( strict_owner && owner != kernelTLS.this_thread ) {
118                fprintf( stderr, "A thread other than the owner attempted to release an owner lock" );
119                return;
120        }
121        recursion_count--;
122        if ( recursion_count == 0 ) {
123                $thread * thrd = pop_head( blocked_threads );
124                owner = thrd;
125                recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
126                wait_count--;
127                unpark( thrd );
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;
153                if ( multi_acquisition ) recursion_count = 1;
154                #if !defined( __CFA_NO_STATISTICS__ )
155                        kernelTLS.this_stats = t->curr_cluster->stats;
156                #endif
157                unpark( t );
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
165                fprintf( stderr, "A lock that is not held was passed to a synchronization lock" );
166        } else if ( strict_owner && owner != kernelTLS.this_thread ) {
167                fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" );
168        } else {
169                $thread * thrd = pop_head( blocked_threads );
170                owner = thrd;
171                recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
172                wait_count--;
173                unpark( thrd );
174        }
175        unlock( lock );
176}
177
178///////////////////////////////////////////////////////////////////
179//// Overloaded routines for traits
180///////////////////////////////////////////////////////////////////
181
182// This is temporary until an inheritance bug is fixed
183
184void lock( mutex_lock & this ){
185        lock( (blocking_lock &)this );
186}
187
188void unlock( mutex_lock & this ){
189        unlock( (blocking_lock &)this );
190}
191
192void add_( mutex_lock & this, struct $thread * t ){
193        add_( (blocking_lock &)this, t );
194}
195
196void remove_( mutex_lock & this ){
197        remove_( (blocking_lock &)this );
198}
199
200void set_recursion_count( mutex_lock & this, size_t recursion ){
201        set_recursion_count( (blocking_lock &)this, recursion );
202}
203
204size_t get_recursion_count( mutex_lock & this ){
205        get_recursion_count( (blocking_lock &)this );
206}
207
208void lock( recursive_mutex_lock & this ){
209        lock( (blocking_lock &)this );
210}
211
212void unlock( recursive_mutex_lock & this ){
213        unlock( (blocking_lock &)this );
214}
215
216void add_( recursive_mutex_lock & this, struct $thread * t ){
217        add_( (blocking_lock &)this, t );
218}
219
220void remove_( recursive_mutex_lock & this ){
221        remove_( (blocking_lock &)this );
222}
223
224void set_recursion_count( recursive_mutex_lock & this, size_t recursion ){
225        set_recursion_count( (blocking_lock &)this, recursion );
226}
227
228size_t get_recursion_count( recursive_mutex_lock & this ){
229        get_recursion_count( (blocking_lock &)this );
230}
231
232///////////////////////////////////////////////////////////////////
233//// condition variable
234///////////////////////////////////////////////////////////////////
235
236forall(dtype L | is_blocking_lock(L)) {
237
238        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
239        // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
240            lock( cond->lock __cfaabi_dbg_ctx2 );
241            if ( (*i)->listed ) {                       // is thread on queue
242                info_thread(L) * copy = *i;
243                        remove( cond->blocked_threads, i );              //remove this thread O(1)
244                        cond->wait_count--;
245                        if( !copy->lock ) {
246                                unlock( cond->lock );
247                                #if !defined( __CFA_NO_STATISTICS__ )
248                                        kernelTLS.this_stats = copy->t->curr_cluster->stats;
249                                #endif
250                                unpark( copy->t );
251                } else {
252                        add_(*copy->lock, copy->t);                     // call lock's add_
253                }
254            }
255            unlock( cond->lock );
256        }
257
258        void alarm_node_wrap_cast( alarm_node_t & a ) {
259                timeout_handler( (alarm_node_wrap(L) &)a );
260        }
261
262        void ?{}( condition_variable(L) & this ){
263                this.lock{};
264                this.blocked_threads{};
265                this.count = 0;
266        }
267
268        void ^?{}( condition_variable(L) & this ){
269                // default
270        }
271
272        void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
273                this.alarm_node{ thrd, alarm, period, callback };
274        }
275
276        void ^?{}( alarm_node_wrap(L) & this ) {
277                // default
278        }
279
280        bool notify_one( condition_variable(L) & this ) with( this ) {
281                lock( lock __cfaabi_dbg_ctx2 );
282                bool ret = !!blocked_threads;
283                info_thread(L) * popped = pop_head( blocked_threads );
284                popped->listed = false;
285                if(popped != 0p) {
286                        count--;
287                        if (popped->lock) {
288                                add_(*popped->lock, popped->t);
289                        } else {
290                                unpark(popped->t);
291                        }
292                }
293                unlock( lock );
294                return ret;
295        }
296
297        bool notify_all( condition_variable(L) & this ) with(this) {
298                lock( lock __cfaabi_dbg_ctx2 );
299                bool ret = blocked_threads ? true : false;
300                while( blocked_threads ) {
301                        info_thread(L) * popped = pop_head( blocked_threads );
302                        popped->listed = false;
303                        if(popped != 0p){
304                                count--;
305                                if (popped->lock) {
306                                        add_(*popped->lock, popped->t);
307                                } else {
308                                        unpark(popped->t);
309                                }
310                        }
311                }
312                unlock( lock );
313                return ret;
314        }
315
316        uintptr_t front( condition_variable(L) & this ) with(this) {
317                if(!blocked_threads) return NULL;
318                return peek(blocked_threads)->info;
319        }
320
321        bool empty( condition_variable(L) & this ) with(this) {
322                return blocked_threads ? false : true;
323        }
324
325        int counter( condition_variable(L) & this ) with(this) {
326                return count;
327        }
328
329        // helper for wait()'s' without a timeout
330        void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
331                lock( lock __cfaabi_dbg_ctx2 );
332                append( this.blocked_threads, &i );
333                count++;
334                i.listed = true;
335                size_t recursion_count;
336                if (i.lock) {
337                        recursion_count = get_recursion_count(*i.lock);
338                        remove_( *i.lock );
339                }
340               
341                unlock( lock );
342                park( ); // blocks here
343
344                if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
345        }
346
347        // helper for wait()'s' with a timeout
348        void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
349                lock( lock __cfaabi_dbg_ctx2 );
350
351                info_thread(L) * queue_ptr = &info;
352
353                alarm_node_wrap(L) node_wrap = { info.t, t, 0`s, alarm_node_wrap_cast };
354                node_wrap.cond = &this;
355                node_wrap.i = &queue_ptr;
356
357                register_self( &node_wrap.alarm_node );
358
359                append( blocked_threads, queue_ptr );
360                info.listed = true;
361                count++;
362
363                size_t recursion_count;
364                if (info.lock) {
365                        recursion_count = get_recursion_count(*info.lock);
366                        remove_( *info.lock );
367                }
368
369                unlock( lock );
370                park();
371
372                if (info.lock) set_recursion_count(*info.lock, recursion_count);
373        }
374
375        void wait( condition_variable(L) & this ) with(this) {
376                info_thread( L ) i = { kernelTLS.this_thread };
377                queue_info_thread( this, i );
378        }
379
380        void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
381                info_thread( L ) i = { kernelTLS.this_thread, info };
382                queue_info_thread( this, i );
383        }
384       
385        void wait( condition_variable(L) & this, Duration duration ) with(this) {
386                info_thread( L ) i = { kernelTLS.this_thread };
387                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
388        }
389
390        void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
391                info_thread( L ) i = { kernelTLS.this_thread, info };
392                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
393        }
394
395        void wait( condition_variable(L) & this, Time time ) with(this) {
396                info_thread( L ) i = { kernelTLS.this_thread };
397                queue_info_thread_timeout(this, i, time);
398        }
399
400        void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
401                info_thread( L ) i = { kernelTLS.this_thread, info };
402                queue_info_thread_timeout(this, i, time);
403        }
404
405        void wait( condition_variable(L) & this, L & l ) with(this) {
406                info_thread(L) i = { kernelTLS.this_thread };
407                i.lock = &l;
408                queue_info_thread( this, i );
409        }
410
411        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
412                info_thread(L) i = { kernelTLS.this_thread, info };
413                i.lock = &l;
414                queue_info_thread( this, i );
415        }
416       
417        void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
418                info_thread(L) i = { kernelTLS.this_thread };
419                i.lock = &l;
420                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
421        }
422       
423        void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
424                info_thread(L) i = { kernelTLS.this_thread, info };
425                i.lock = &l;
426                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
427        }
428       
429        void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
430                info_thread(L) i = { kernelTLS.this_thread };
431                i.lock = &l;
432                queue_info_thread_timeout(this, i, time );
433        }
434       
435        void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
436                info_thread(L) i = { kernelTLS.this_thread, info };
437                i.lock = &l;
438                queue_info_thread_timeout(this, i, time );
439        }
440}
Note: See TracBrowser for help on using the repository browser.