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

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

Changed many instances of kernelTLS to use active_thread/active_coroutine

  • Property mode set to 100644
File size: 10.9 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        }
18
19        void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) {
20                this.t = t;
21                this.info = info;
22                this.lock = 0p;
23        }
24
25        void ^?{}( info_thread(L) & this ){
26                // default
27        }
28
29        info_thread(L) *& get_next( info_thread(L) & this ) {
30                return this.next;
31        }
32}
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
47void ^?{}( blocking_lock & this ) {
48        // default
49}
50
51void ?{}( mutex_lock & this ) {
52        ((blocking_lock &)this){ false, false };
53}
54
55void ^?{}( mutex_lock & this ) {
56        // default
57}
58
59void ?{}( owner_lock & this ) {
60        ((blocking_lock &)this){ true, true };
61}
62
63void ^?{}( owner_lock & this ) {
64        // default
65}
66
67void ?{}( recursive_mutex_lock & this ) {
68        ((blocking_lock &)this){ true, false };
69}
70
71void ^?{}( recursive_mutex_lock & this ) {
72        // default
73}
74
75void lock( blocking_lock & this ) with( this ) {
76        $thread * thrd = active_thread();
77        lock( lock __cfaabi_dbg_ctx2 );
78        if ( owner == thrd && !multi_acquisition) {
79                fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead
80                exit(EXIT_FAILURE);
81        } else if ( owner != 0p && owner != thrd ) {
82                append( blocked_threads, thrd );
83                wait_count++;
84                unlock( lock );
85                park( __cfaabi_dbg_ctx );
86        } else if ( owner == thrd && multi_acquisition ) {
87                recursion_count++;
88                unlock( lock );
89        } else {
90                owner = thrd;
91                recursion_count = 1;
92                unlock( lock );
93        }
94}
95
96bool try_lock( blocking_lock & this ) with( this ) {
97        $thread * thrd = active_thread();
98        bool ret = false;
99        lock( lock __cfaabi_dbg_ctx2 );
100        if ( owner == 0p ) {
101                owner = thrd;
102                if ( multi_acquisition ) recursion_count = 1;
103                ret = true;
104        } else if ( owner == thrd && 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 && multi_acquisition ? 1 : 0 );
126                wait_count--;
127                unpark( thrd __cfaabi_dbg_ctx2 );
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                unpark( t __cfaabi_dbg_ctx2 );
155                unlock( lock );
156        }
157}
158
159void remove_( blocking_lock & this ) with( this ) {
160    lock( lock __cfaabi_dbg_ctx2 );
161        if ( owner == 0p ){ // no owner implies lock isn't held
162                fprintf( stderr, "A lock that is not held was passed to a synchronization lock" );
163        } else if ( strict_owner && owner != active_thread() ) {
164                fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" );
165        } else {
166                $thread * thrd = pop_head( blocked_threads );
167                owner = thrd;
168                recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
169                wait_count--;
170                unpark( thrd __cfaabi_dbg_ctx2 );
171        }
172        unlock( lock );
173}
174
175///////////////////////////////////////////////////////////////////
176//// Overloaded routines for traits
177///////////////////////////////////////////////////////////////////
178
179// In an ideal world this may not be necessary
180// Is it possible for nominal inheritance to inherit traits??
181// If that occurs we would avoid all this extra code
182
183void lock( mutex_lock & this ){
184        lock( (blocking_lock &)this );
185}
186
187void unlock( mutex_lock & this ){
188        unlock( (blocking_lock &)this );
189}
190
191void add_( mutex_lock & this, struct $thread * t ){
192        add_( (blocking_lock &)this, t );
193}
194
195void remove_( mutex_lock & this ){
196        remove_( (blocking_lock &)this );
197}
198
199void set_recursion_count( mutex_lock & this, size_t recursion ){
200        set_recursion_count( (blocking_lock &)this, recursion );
201}
202
203size_t get_recursion_count( mutex_lock & this ){
204        get_recursion_count( (blocking_lock &)this );
205}
206
207void lock( recursive_mutex_lock & this ){
208        lock( (blocking_lock &)this );
209}
210
211void unlock( recursive_mutex_lock & this ){
212        unlock( (blocking_lock &)this );
213}
214
215void add_( recursive_mutex_lock & this, struct $thread * t ){
216        add_( (blocking_lock &)this, t );
217}
218
219void remove_( recursive_mutex_lock & this ){
220        remove_( (blocking_lock &)this );
221}
222
223void set_recursion_count( recursive_mutex_lock & this, size_t recursion ){
224        set_recursion_count( (blocking_lock &)this, recursion );
225}
226
227size_t get_recursion_count( recursive_mutex_lock & this ){
228        get_recursion_count( (blocking_lock &)this );
229}
230
231///////////////////////////////////////////////////////////////////
232//// Synchronization Locks
233///////////////////////////////////////////////////////////////////
234
235forall(dtype L | is_blocking_lock(L)) {
236        void ?{}( synchronization_lock(L) & this, bool reacquire_after_signal ){
237                this.lock{};
238                this.blocked_threads{};
239                this.count = 0;
240                this.reacquire_after_signal = reacquire_after_signal;
241        }
242
243        void ^?{}( synchronization_lock(L) & this ){
244                // default
245        }
246
247        void ?{}( condition_variable(L) & this ){
248                ((synchronization_lock(L) &)this){ true };
249        }
250
251        void ^?{}( condition_variable(L) & this ){
252                // default
253        }
254
255        void ?{}( thread_queue(L) & this ){
256                ((synchronization_lock(L) &)this){ false };
257        }
258
259        void ^?{}( thread_queue(L) & this ){
260                // default
261        }
262
263        bool notify_one( synchronization_lock(L) & this ) with( this ) {
264                lock( lock __cfaabi_dbg_ctx2 );
265                bool ret = !!blocked_threads;
266                info_thread(L) * popped = pop_head( blocked_threads );
267                if(popped != 0p) {
268                        if( reacquire_after_signal ){
269                                add_(*popped->lock, popped->t);
270                        } else {
271                                unpark(
272                                        popped->t __cfaabi_dbg_ctx2
273                                );
274                        }
275                }
276                unlock( lock );
277                return ret;
278        }
279
280        bool notify_all( synchronization_lock(L) & this ) with(this) {
281                lock( lock __cfaabi_dbg_ctx2 );
282                bool ret = blocked_threads ? true : false;
283                while( blocked_threads ) {
284                        info_thread(L) * popped = pop_head( blocked_threads );
285                        if(popped != 0p){
286                                if( reacquire_after_signal ){
287                                        add_(*popped->lock, popped->t);
288                                } else {
289                                        unpark(
290                                                popped->t __cfaabi_dbg_ctx2
291                                        );
292                                }
293                        }
294                }
295                unlock( lock );
296                return ret;
297        }
298
299        uintptr_t front( synchronization_lock(L) & this ) with(this) {
300                return (*peek(blocked_threads)).info;
301        }
302
303        bool empty( synchronization_lock(L) & this ) with(this) {
304                return blocked_threads ? false : true;
305        }
306
307        int counter( synchronization_lock(L) & this ) with(this) {
308                return count;
309        }
310
311        void queue_info_thread( synchronization_lock(L) & this, info_thread(L) & i ) with(this) {
312                lock( lock __cfaabi_dbg_ctx2 );
313                append( blocked_threads, &i );
314                count++;
315                unlock( lock );
316                park( __cfaabi_dbg_ctx );
317        }
318
319
320        void wait( synchronization_lock(L) & this ) with(this) {
321                info_thread( L ) i = { active_thread() };
322                queue_info_thread( this, i );
323        }
324
325        void wait( synchronization_lock(L) & this, uintptr_t info ) with(this) {
326                info_thread( L ) i = { active_thread(), info };
327                queue_info_thread( this, i );
328        }
329        // I still need to implement the time delay wait routines
330        bool wait( synchronization_lock(L) & this, Duration duration ) with(this) {
331                timeval tv = { time(0) };
332                Time t = { tv };
333                return wait( this, t + duration );
334        }
335
336        bool wait( synchronization_lock(L) & this, uintptr_t info, Duration duration ) with(this) {
337                // TODO: ADD INFO
338                return wait( this, duration );
339        }
340
341        bool wait( synchronization_lock(L) & this, Time time ) with(this) {
342                return false; //default
343        }
344
345        bool wait( synchronization_lock(L) & this, uintptr_t info, Time time ) with(this) {
346                // TODO: ADD INFO
347                return wait( this, time );
348        }
349
350        void queue_info_thread_unlock( synchronization_lock(L) & this, L & l, info_thread(L) & i ) with(this) {
351                lock( lock __cfaabi_dbg_ctx2 );
352                append( this.blocked_threads, &i );
353                count++;
354                i.lock = &l;
355                size_t recursion_count = get_recursion_count(l);
356                remove_( l );
357                unlock( lock );
358                park( __cfaabi_dbg_ctx ); // blocks here
359
360                set_recursion_count(l, recursion_count); // resets recursion count here after waking
361        }
362
363        void wait( synchronization_lock(L) & this, L & l ) with(this) {
364                info_thread(L) i = { active_thread() };
365                queue_info_thread_unlock( this, l, i );
366        }
367
368        void wait( synchronization_lock(L) & this, L & l, uintptr_t info ) with(this) {
369                info_thread(L) i = { active_thread(), info };
370                queue_info_thread_unlock( this, l, i );
371        }
372
373        bool wait( synchronization_lock(L) & this, L & l, Duration duration ) with(this) {
374                timeval tv = { time(0) };
375                Time t = { tv };
376                return wait( this, l, t + duration );
377        }
378
379        bool wait( synchronization_lock(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
380                // TODO: ADD INFO
381                return wait( this, l, duration );
382        }
383
384        bool wait( synchronization_lock(L) & this, L & l, Time time ) with(this) {
385                return false; //default
386        }
387
388        bool wait( synchronization_lock(L) & this, L & l, uintptr_t info, Time time ) with(this) {
389                // TODO: ADD INFO
390                return wait( this, l, time );
391        }
392}
393
394///////////////////////////////////////////////////////////////////
395//// condition lock alternative approach
396///////////////////////////////////////////////////////////////////
397
398// the solution below is less efficient but does not require the lock to have a specific add/remove routine
399
400///////////////////////////////////////////////////////////////////
401//// is_simple_lock
402///////////////////////////////////////////////////////////////////
403
404forall(dtype L | is_simple_lock(L)) {
405        void ?{}( condition_lock(L) & this ){
406                // default
407        }
408
409        void ^?{}( condition_lock(L) & this ){
410                // default
411        }
412
413        bool notify_one( condition_lock(L) & this ) with(this) {
414                return notify_one( c_var );
415        }
416
417        bool notify_all( condition_lock(L) & this ) with(this) {
418                return notify_all( c_var );
419        }
420
421        void wait( condition_lock(L) & this, L & l ) with(this) {
422                lock( m_lock );
423                size_t recursion = get_recursion_count( l );
424                unlock( l );
425                wait( c_var, m_lock );
426                lock( l );
427                set_recursion_count( l , recursion );
428                unlock( m_lock );
429        }
430}
Note: See TracBrowser for help on using the repository browser.