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

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since b82d140 was 3959595, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

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