source: libcfa/src/concurrency/locks.cfa @ 936d95c

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

Fixed newlines and tabs in concurrency/locks

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