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

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 b982fb2 was 848439f, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Fixed newlines and tabs in concurrency/locks

  • Property mode set to 100644
File size: 11.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 }
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.