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

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since cd6a6ff 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
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 ?{}( single_acquisition_lock & this ) {
54        ((blocking_lock &)this){ false, false };
55}
56
57void ^?{}( single_acquisition_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 ?{}( multiple_acquisition_lock & this ) {
70        ((blocking_lock &)this){ true, false };
71}
72
73void ^?{}( multiple_acquisition_lock & this ) {
74        // default
75}
76
77void lock( blocking_lock & this ) with( this ) {
78        lock( lock __cfaabi_dbg_ctx2 );
79        if ( owner == active_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 != active_thread() ) {
83                append( blocked_threads, active_thread() );
84                wait_count++;
85                unlock( lock );
86                park( );
87        } else if ( owner == active_thread() && multi_acquisition ) {
88                recursion_count++;
89                unlock( lock );
90        } else {
91                owner = active_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 = active_thread();
102                recursion_count = 1;
103                ret = true;
104        } else if ( owner == active_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 != active_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 ? 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                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 != active_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 ? 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( 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 ){
209        lock( (blocking_lock &)this );
210}
211
212void unlock( owner_lock & this ){
213        unlock( (blocking_lock &)this );
214}
215
216void add_( owner_lock & this, struct $thread * t ){
217        add_( (blocking_lock &)this, t );
218}
219
220void remove_( owner_lock & this ){
221        remove_( (blocking_lock &)this );
222}
223
224void set_recursion_count( owner_lock & this, size_t recursion ){
225        set_recursion_count( (blocking_lock &)this, recursion );
226}
227
228size_t get_recursion_count( owner_lock & this ){
229        return get_recursion_count( (blocking_lock &)this );
230}
231
232void lock( multiple_acquisition_lock & this ){
233        lock( (blocking_lock &)this );
234}
235
236void unlock( multiple_acquisition_lock & this ){
237        unlock( (blocking_lock &)this );
238}
239
240void add_( multiple_acquisition_lock & this, struct $thread * t ){
241        add_( (blocking_lock &)this, t );
242}
243
244void remove_( multiple_acquisition_lock & this ){
245        remove_( (blocking_lock &)this );
246}
247
248void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){
249        set_recursion_count( (blocking_lock &)this, recursion );
250}
251
252size_t get_recursion_count( multiple_acquisition_lock & this ){
253        return get_recursion_count( (blocking_lock &)this );
254}
255
256///////////////////////////////////////////////////////////////////
257//// condition variable
258///////////////////////////////////////////////////////////////////
259
260forall(dtype L | is_blocking_lock(L)) {
261
262        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
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)
268                        cond->count--;
269                        if( !copy->lock ) {
270                                #if !defined( __CFA_NO_STATISTICS__ )
271                                        //kernelTLS.this_stats = copy->t->curr_cluster->stats;
272                                #endif
273                                unpark( copy->t );
274                } else {
275                        add_(*copy->lock, copy->t);                     // call lock's add_
276                }
277            }
278            unlock( cond->lock );
279        }
280
281        void alarm_node_wrap_cast( alarm_node_t & a ) {
282                timeout_handler( (alarm_node_wrap(L) &)a );
283        }
284
285        void ?{}( condition_variable(L) & this ){
286                this.lock{};
287                this.blocked_threads{};
288                this.count = 0;
289        }
290
291        void ^?{}( condition_variable(L) & this ){
292                // default
293        }
294
295        void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
296                this.alarm_node{ thrd, alarm, period, callback };
297        }
298
299        void ^?{}( alarm_node_wrap(L) & this ) {
300                // default
301        }
302
303        bool notify_one( condition_variable(L) & this ) with( this ) {
304                lock( lock __cfaabi_dbg_ctx2 );
305                bool ret = !!blocked_threads;
306                info_thread(L) * popped = pop_head( blocked_threads );
307                if(popped != 0p) {
308                        popped->listed = false;
309                        count--;
310                        if (popped->lock) {
311                                add_(*popped->lock, popped->t);
312                        } else {
313                                unpark(popped->t);
314                        }
315                }
316                unlock( lock );
317                return ret;
318        }
319
320        bool notify_all( condition_variable(L) & this ) with(this) {
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){
326                                popped->listed = false;
327                                count--;
328                                if (popped->lock) {
329                                        add_(*popped->lock, popped->t);
330                                } else {
331                                        unpark(popped->t);
332                                }
333                        }
334                }
335                unlock( lock );
336                return ret;
337        }
338
339        uintptr_t front( condition_variable(L) & this ) with(this) {
340                if(!blocked_threads) return NULL;
341                return peek(blocked_threads)->info;
342        }
343
344        bool empty( condition_variable(L) & this ) with(this) {
345                return blocked_threads ? false : true;
346        }
347
348        int counter( condition_variable(L) & this ) with(this) {
349                return count;
350        }
351
352        // helper for wait()'s' without a timeout
353        void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
354                lock( lock __cfaabi_dbg_ctx2 );
355                append( this.blocked_threads, &i );
356                count++;
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                }
363               
364                unlock( lock );
365                park( ); // blocks here
366
367                if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
368        }
369
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 );
373
374                info_thread(L) * queue_ptr = &info;
375
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;
379
380                register_self( &node_wrap.alarm_node );
381
382                append( blocked_threads, queue_ptr );
383                info.listed = true;
384                count++;
385
386                size_t recursion_count;
387                if (info.lock) {
388                        recursion_count = get_recursion_count(*info.lock);
389                        remove_( *info.lock );
390                }
391
392                unlock( lock );
393                park();
394
395                if (info.lock) set_recursion_count(*info.lock, recursion_count);
396        }
397
398        void wait( condition_variable(L) & this ) with(this) {
399                info_thread( L ) i = { active_thread() };
400                queue_info_thread( this, i );
401        }
402
403        void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
404                info_thread( L ) i = { active_thread(), info };
405                queue_info_thread( this, i );
406        }
407       
408        void wait( condition_variable(L) & this, Duration duration ) with(this) {
409                info_thread( L ) i = { active_thread() };
410                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
411        }
412
413        void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
414                info_thread( L ) i = { active_thread(), info };
415                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
416        }
417
418        void wait( condition_variable(L) & this, Time time ) with(this) {
419                info_thread( L ) i = { active_thread() };
420                queue_info_thread_timeout(this, i, time);
421        }
422
423        void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
424                info_thread( L ) i = { active_thread(), info };
425                queue_info_thread_timeout(this, i, time);
426        }
427
428        void wait( condition_variable(L) & this, L & l ) with(this) {
429                info_thread(L) i = { active_thread() };
430                i.lock = &l;
431                queue_info_thread( this, i );
432        }
433
434        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
435                info_thread(L) i = { active_thread(), info };
436                i.lock = &l;
437                queue_info_thread( this, i );
438        }
439       
440        void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
441                info_thread(L) i = { active_thread() };
442                i.lock = &l;
443                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
444        }
445       
446        void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
447                info_thread(L) i = { active_thread(), info };
448                i.lock = &l;
449                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
450        }
451       
452        void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
453                info_thread(L) i = { active_thread() };
454                i.lock = &l;
455                queue_info_thread_timeout(this, i, time );
456        }
457       
458        void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
459                info_thread(L) i = { active_thread(), info };
460                i.lock = &l;
461                queue_info_thread_timeout(this, i, time );
462        }
463}
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.