source: libcfa/src/concurrency/locks.cfa@ 172dba9c

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 172dba9c was 6a8882c, checked in by Colby Alexander Parsons <caparsons@…>, 5 years ago

fixed some bugs

  • Property mode set to 100644
File size: 13.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;
[eeb5023]17 this.listed = false;
[848439f]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;
[eeb5023]24 this.listed = false;
[848439f]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
[6a8882c]53void ?{}( single_acquisition_lock & this ) {
[848439f]54 ((blocking_lock &)this){ false, false };
55}
56
[6a8882c]57void ^?{}( single_acquisition_lock & this ) {
[848439f]58 // default
59}
60
61void ?{}( owner_lock & this ) {
62 ((blocking_lock &)this){ true, true };
63}
64
65void ^?{}( owner_lock & this ) {
66 // default
67}
68
[6a8882c]69void ?{}( multiple_acquisition_lock & this ) {
[848439f]70 ((blocking_lock &)this){ true, false };
71}
72
[6a8882c]73void ^?{}( multiple_acquisition_lock & this ) {
[848439f]74 // default
75}
76
77void lock( blocking_lock & this ) with( this ) {
78 lock( lock __cfaabi_dbg_ctx2 );
[6a8882c]79 if ( owner == active_thread() && !multi_acquisition) {
[848439f]80 fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead
[eeb5023]81 exit(EXIT_FAILURE);
[6a8882c]82 } else if ( owner != 0p && owner != active_thread() ) {
83 append( blocked_threads, active_thread() );
[848439f]84 wait_count++;
85 unlock( lock );
[eeb5023]86 park( );
[6a8882c]87 } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]88 recursion_count++;
89 unlock( lock );
90 } else {
[6a8882c]91 owner = active_thread();
[848439f]92 recursion_count = 1;
93 unlock( lock );
94 }
95}
96
97bool try_lock( blocking_lock & this ) with( this ) {
98 bool ret = false;
99 lock( lock __cfaabi_dbg_ctx2 );
100 if ( owner == 0p ) {
[6a8882c]101 owner = active_thread();
102 recursion_count = 1;
[848439f]103 ret = true;
[6a8882c]104 } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]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
[6a8882c]115 fprintf( stderr, "There was an attempt to release a lock that isn't held" );
[848439f]116 return;
[6a8882c]117 } else if ( strict_owner && owner != active_thread() ) {
118 fprintf( stderr, "A thread other than the owner attempted to release an owner lock" );
[848439f]119 return;
120 }
121 recursion_count--;
122 if ( recursion_count == 0 ) {
123 $thread * thrd = pop_head( blocked_threads );
124 owner = thrd;
[6a8882c]125 recursion_count = ( thrd ? 1 : 0 );
[848439f]126 wait_count--;
[eeb5023]127 unpark( thrd );
[848439f]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;
[6a8882c]153 recursion_count = 1;
[eeb5023]154 #if !defined( __CFA_NO_STATISTICS__ )
[6a8882c]155 //kernelTLS.this_stats = t->curr_cluster->stats;
[eeb5023]156 #endif
157 unpark( t );
[848439f]158 unlock( lock );
159 }
160}
161
162void remove_( blocking_lock & this ) with( this ) {
163 lock( lock __cfaabi_dbg_ctx2 );
164 if ( owner == 0p ){ // no owner implies lock isn't held
[6a8882c]165 fprintf( stderr, "A lock that is not held was passed to a synchronization lock" );
166 } else if ( strict_owner && owner != active_thread() ) {
167 fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" );
[848439f]168 } else {
169 $thread * thrd = pop_head( blocked_threads );
170 owner = thrd;
[6a8882c]171 recursion_count = ( thrd ? 1 : 0 );
[848439f]172 wait_count--;
[eeb5023]173 unpark( thrd );
[848439f]174 }
175 unlock( lock );
176}
177
178///////////////////////////////////////////////////////////////////
179//// Overloaded routines for traits
180///////////////////////////////////////////////////////////////////
181
[eeb5023]182// This is temporary until an inheritance bug is fixed
[848439f]183
[6a8882c]184void lock( single_acquisition_lock & this ){
185 lock( (blocking_lock &)this );
186}
187
188void unlock( single_acquisition_lock & this ){
189 unlock( (blocking_lock &)this );
190}
191
192void add_( single_acquisition_lock & this, struct $thread * t ){
193 add_( (blocking_lock &)this, t );
194}
195
196void remove_( single_acquisition_lock & this ){
197 remove_( (blocking_lock &)this );
198}
199
200void set_recursion_count( single_acquisition_lock & this, size_t recursion ){
201 set_recursion_count( (blocking_lock &)this, recursion );
202}
203
204size_t get_recursion_count( single_acquisition_lock & this ){
205 return get_recursion_count( (blocking_lock &)this );
206}
207
208void lock( owner_lock & this ){
[848439f]209 lock( (blocking_lock &)this );
210}
211
[6a8882c]212void unlock( owner_lock & this ){
[848439f]213 unlock( (blocking_lock &)this );
214}
215
[6a8882c]216void add_( owner_lock & this, struct $thread * t ){
[848439f]217 add_( (blocking_lock &)this, t );
218}
219
[6a8882c]220void remove_( owner_lock & this ){
[848439f]221 remove_( (blocking_lock &)this );
222}
223
[6a8882c]224void set_recursion_count( owner_lock & this, size_t recursion ){
[848439f]225 set_recursion_count( (blocking_lock &)this, recursion );
226}
227
[6a8882c]228size_t get_recursion_count( owner_lock & this ){
229 return get_recursion_count( (blocking_lock &)this );
[848439f]230}
231
[6a8882c]232void lock( multiple_acquisition_lock & this ){
[848439f]233 lock( (blocking_lock &)this );
234}
235
[6a8882c]236void unlock( multiple_acquisition_lock & this ){
[848439f]237 unlock( (blocking_lock &)this );
238}
239
[6a8882c]240void add_( multiple_acquisition_lock & this, struct $thread * t ){
[848439f]241 add_( (blocking_lock &)this, t );
242}
243
[6a8882c]244void remove_( multiple_acquisition_lock & this ){
[848439f]245 remove_( (blocking_lock &)this );
246}
247
[6a8882c]248void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){
[848439f]249 set_recursion_count( (blocking_lock &)this, recursion );
250}
251
[6a8882c]252size_t get_recursion_count( multiple_acquisition_lock & this ){
253 return get_recursion_count( (blocking_lock &)this );
[848439f]254}
255
256///////////////////////////////////////////////////////////////////
[eeb5023]257//// condition variable
[848439f]258///////////////////////////////////////////////////////////////////
259
260forall(dtype L | is_blocking_lock(L)) {
261
[c5bbb9b]262 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
[eeb5023]263 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
264 lock( cond->lock __cfaabi_dbg_ctx2 );
265 if ( (*i)->listed ) { // is thread on queue
266 info_thread(L) * copy = *i;
267 remove( cond->blocked_threads, i ); //remove this thread O(1)
[6a8882c]268 cond->count--;
[eeb5023]269 if( !copy->lock ) {
270 #if !defined( __CFA_NO_STATISTICS__ )
[6a8882c]271 //kernelTLS.this_stats = copy->t->curr_cluster->stats;
[eeb5023]272 #endif
273 unpark( copy->t );
274 } else {
275 add_(*copy->lock, copy->t); // call lock's add_
276 }
277 }
278 unlock( cond->lock );
[848439f]279 }
280
[eeb5023]281 void alarm_node_wrap_cast( alarm_node_t & a ) {
[c5bbb9b]282 timeout_handler( (alarm_node_wrap(L) &)a );
[848439f]283 }
284
285 void ?{}( condition_variable(L) & this ){
[eeb5023]286 this.lock{};
287 this.blocked_threads{};
288 this.count = 0;
[848439f]289 }
290
291 void ^?{}( condition_variable(L) & this ){
292 // default
293 }
294
[eeb5023]295 void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
296 this.alarm_node{ thrd, alarm, period, callback };
[848439f]297 }
298
[eeb5023]299 void ^?{}( alarm_node_wrap(L) & this ) {
[848439f]300 // default
301 }
302
[eeb5023]303 bool notify_one( condition_variable(L) & this ) with( this ) {
[848439f]304 lock( lock __cfaabi_dbg_ctx2 );
305 bool ret = !!blocked_threads;
306 info_thread(L) * popped = pop_head( blocked_threads );
307 if(popped != 0p) {
[6a8882c]308 popped->listed = false;
[eeb5023]309 count--;
[c5bbb9b]310 if (popped->lock) {
[848439f]311 add_(*popped->lock, popped->t);
312 } else {
[c5bbb9b]313 unpark(popped->t);
[848439f]314 }
315 }
316 unlock( lock );
317 return ret;
318 }
319
[eeb5023]320 bool notify_all( condition_variable(L) & this ) with(this) {
[848439f]321 lock( lock __cfaabi_dbg_ctx2 );
322 bool ret = blocked_threads ? true : false;
323 while( blocked_threads ) {
324 info_thread(L) * popped = pop_head( blocked_threads );
325 if(popped != 0p){
[6a8882c]326 popped->listed = false;
[eeb5023]327 count--;
[c5bbb9b]328 if (popped->lock) {
[848439f]329 add_(*popped->lock, popped->t);
330 } else {
[c5bbb9b]331 unpark(popped->t);
[848439f]332 }
333 }
334 }
335 unlock( lock );
336 return ret;
337 }
338
[eeb5023]339 uintptr_t front( condition_variable(L) & this ) with(this) {
340 if(!blocked_threads) return NULL;
341 return peek(blocked_threads)->info;
[848439f]342 }
343
[eeb5023]344 bool empty( condition_variable(L) & this ) with(this) {
[848439f]345 return blocked_threads ? false : true;
346 }
347
[eeb5023]348 int counter( condition_variable(L) & this ) with(this) {
[848439f]349 return count;
350 }
351
[eeb5023]352 // helper for wait()'s' without a timeout
353 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
[848439f]354 lock( lock __cfaabi_dbg_ctx2 );
[eeb5023]355 append( this.blocked_threads, &i );
[848439f]356 count++;
[eeb5023]357 i.listed = true;
358 size_t recursion_count;
359 if (i.lock) {
360 recursion_count = get_recursion_count(*i.lock);
361 remove_( *i.lock );
362 }
[6a8882c]363
[848439f]364 unlock( lock );
[eeb5023]365 park( ); // blocks here
[848439f]366
[eeb5023]367 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
[848439f]368 }
369
[eeb5023]370 // helper for wait()'s' with a timeout
371 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
372 lock( lock __cfaabi_dbg_ctx2 );
[848439f]373
[eeb5023]374 info_thread(L) * queue_ptr = &info;
[848439f]375
[eeb5023]376 alarm_node_wrap(L) node_wrap = { info.t, t, 0`s, alarm_node_wrap_cast };
377 node_wrap.cond = &this;
378 node_wrap.i = &queue_ptr;
[848439f]379
[eeb5023]380 register_self( &node_wrap.alarm_node );
[848439f]381
[eeb5023]382 append( blocked_threads, queue_ptr );
383 info.listed = true;
[848439f]384 count++;
[eeb5023]385
386 size_t recursion_count;
387 if (info.lock) {
388 recursion_count = get_recursion_count(*info.lock);
389 remove_( *info.lock );
390 }
391
[848439f]392 unlock( lock );
[eeb5023]393 park();
[848439f]394
[eeb5023]395 if (info.lock) set_recursion_count(*info.lock, recursion_count);
[848439f]396 }
397
[eeb5023]398 void wait( condition_variable(L) & this ) with(this) {
[3959595]399 info_thread( L ) i = { active_thread() };
[848439f]400 queue_info_thread( this, i );
401 }
402
[eeb5023]403 void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
[3959595]404 info_thread( L ) i = { active_thread(), info };
[848439f]405 queue_info_thread( this, i );
406 }
[6a8882c]407
[eeb5023]408 void wait( condition_variable(L) & this, Duration duration ) with(this) {
[3959595]409 info_thread( L ) i = { active_thread() };
[eeb5023]410 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]411 }
412
[6a8882c]413 void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
[3959595]414 info_thread( L ) i = { active_thread(), info };
[eeb5023]415 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]416 }
417
[eeb5023]418 void wait( condition_variable(L) & this, Time time ) with(this) {
[3959595]419 info_thread( L ) i = { active_thread() };
[eeb5023]420 queue_info_thread_timeout(this, i, time);
[848439f]421 }
422
[eeb5023]423 void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
[3959595]424 info_thread( L ) i = { active_thread(), info };
[eeb5023]425 queue_info_thread_timeout(this, i, time);
[848439f]426 }
427
[eeb5023]428 void wait( condition_variable(L) & this, L & l ) with(this) {
[3959595]429 info_thread(L) i = { active_thread() };
[eeb5023]430 i.lock = &l;
431 queue_info_thread( this, i );
[848439f]432 }
433
[eeb5023]434 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
[3959595]435 info_thread(L) i = { active_thread(), info };
[eeb5023]436 i.lock = &l;
437 queue_info_thread( this, i );
[848439f]438 }
[6a8882c]439
[eeb5023]440 void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
[3959595]441 info_thread(L) i = { active_thread() };
[eeb5023]442 i.lock = &l;
443 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]444 }
[6a8882c]445
[eeb5023]446 void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
[3959595]447 info_thread(L) i = { active_thread(), info };
[eeb5023]448 i.lock = &l;
449 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]450 }
[6a8882c]451
[eeb5023]452 void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
[3959595]453 info_thread(L) i = { active_thread() };
[eeb5023]454 i.lock = &l;
455 queue_info_thread_timeout(this, i, time );
[848439f]456 }
[6a8882c]457
[eeb5023]458 void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
[3959595]459 info_thread(L) i = { active_thread(), info };
[eeb5023]460 i.lock = &l;
461 queue_info_thread_timeout(this, i, time );
[848439f]462 }
463}
[6a8882c]464
465// thread T1 {};
466// thread T2 {};
467
468// multiple_acquisition_lock m;
469// condition_variable( multiple_acquisition_lock ) c;
470
471// void main( T1 & this ) {
472// printf("T1 start\n");
473// lock(m);
474// printf("%d\n", counter(c));
475// if(empty(c)) {
476// printf("T1 wait\n");
477// wait(c,m,12);
478// }else{
479// printf("%d\n", front(c));
480// notify_one(c);
481// }
482// unlock(m);
483// printf("curr thd in main %p \n", active_thread());
484// printf("T1 waits for 2s\n");
485// lock(m);
486// wait( c, m, 2`s );
487// unlock(m);
488// printf("T1 wakes\n");
489// printf("T1 done\n");
490// }
491
492// void main( T2 & this ) {
493// printf("T2 start\n");
494// lock(m);
495// printf("%d\n", counter(c));
496// if(empty(c)) {
497// printf("T2 wait\n");
498// wait(c,m,12);
499// }else{
500// printf("%d\n", front(c));
501// notify_one(c);
502// }
503// unlock(m);
504// printf("T2 done\n");
505// }
506
507// int main() {
508// printf("start\n");
509// processor p[2];
510// {
511// T1 t1;
512// T2 t2;
513// }
514// printf("done\n");
515// }
Note: See TracBrowser for help on using the repository browser.