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

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since be73f30 was be73f30, checked in by Thierry Delisle <tdelisle@…>, 5 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.