source: libcfa/src/concurrency/locks.cfa@ 16ba4a6f

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 16ba4a6f was c5bbb9b, checked in by Colby Alexander Parsons <caparsons@…>, 5 years ago

removed test program from locks.cfa

  • Property mode set to 100644
File size: 11.6 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
53void ?{}( mutex_lock & this ) {
54 ((blocking_lock &)this){ false, false };
55}
56
57void ^?{}( mutex_lock & this ) {
58 // default
59}
60
61void ?{}( owner_lock & this ) {
62 ((blocking_lock &)this){ true, true };
63}
64
65void ^?{}( owner_lock & this ) {
66 // default
67}
68
69void ?{}( recursive_mutex_lock & this ) {
70 ((blocking_lock &)this){ true, false };
71}
72
73void ^?{}( recursive_mutex_lock & this ) {
74 // default
75}
76
77void lock( blocking_lock & this ) with( this ) {
78 lock( lock __cfaabi_dbg_ctx2 );
79 if ( owner == kernelTLS.this_thread && !multi_acquisition) {
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);
[848439f]82 } else if ( owner != 0p && owner != kernelTLS.this_thread ) {
83 append( blocked_threads, kernelTLS.this_thread );
84 wait_count++;
85 unlock( lock );
[eeb5023]86 park( );
[848439f]87 } else if ( owner == kernelTLS.this_thread && multi_acquisition ) {
88 recursion_count++;
89 unlock( lock );
90 } else {
91 owner = kernelTLS.this_thread;
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 ) {
101 owner = kernelTLS.this_thread;
102 if ( multi_acquisition ) recursion_count = 1;
103 ret = true;
104 } else if ( owner == kernelTLS.this_thread && 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
[eeb5023]115 fprintf( stderr, "There was an attempt to release a lock that isn't held" );
[848439f]116 return;
117 } else if ( strict_owner && owner != kernelTLS.this_thread ) {
[eeb5023]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;
125 recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
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;
153 if ( multi_acquisition ) recursion_count = 1;
[eeb5023]154 #if !defined( __CFA_NO_STATISTICS__ )
155 kernelTLS.this_stats = t->curr_cluster->stats;
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
[eeb5023]165 fprintf( stderr, "A lock that is not held was passed to a synchronization lock" );
[848439f]166 } else if ( strict_owner && owner != kernelTLS.this_thread ) {
[eeb5023]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;
171 recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
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
184void lock( mutex_lock & this ){
185 lock( (blocking_lock &)this );
186}
187
188void unlock( mutex_lock & this ){
189 unlock( (blocking_lock &)this );
190}
191
192void add_( mutex_lock & this, struct $thread * t ){
193 add_( (blocking_lock &)this, t );
194}
195
196void remove_( mutex_lock & this ){
197 remove_( (blocking_lock &)this );
198}
199
200void set_recursion_count( mutex_lock & this, size_t recursion ){
201 set_recursion_count( (blocking_lock &)this, recursion );
202}
203
204size_t get_recursion_count( mutex_lock & this ){
205 get_recursion_count( (blocking_lock &)this );
206}
207
208void lock( recursive_mutex_lock & this ){
209 lock( (blocking_lock &)this );
210}
211
212void unlock( recursive_mutex_lock & this ){
213 unlock( (blocking_lock &)this );
214}
215
216void add_( recursive_mutex_lock & this, struct $thread * t ){
217 add_( (blocking_lock &)this, t );
218}
219
220void remove_( recursive_mutex_lock & this ){
221 remove_( (blocking_lock &)this );
222}
223
224void set_recursion_count( recursive_mutex_lock & this, size_t recursion ){
225 set_recursion_count( (blocking_lock &)this, recursion );
226}
227
228size_t get_recursion_count( recursive_mutex_lock & this ){
229 get_recursion_count( (blocking_lock &)this );
230}
231
232///////////////////////////////////////////////////////////////////
[eeb5023]233//// condition variable
[848439f]234///////////////////////////////////////////////////////////////////
235
236forall(dtype L | is_blocking_lock(L)) {
[eeb5023]237
[c5bbb9b]238 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
[eeb5023]239 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
240 lock( cond->lock __cfaabi_dbg_ctx2 );
241 if ( (*i)->listed ) { // is thread on queue
242 info_thread(L) * copy = *i;
243 remove( cond->blocked_threads, i ); //remove this thread O(1)
[c5bbb9b]244 cond->wait_count--;
[eeb5023]245 if( !copy->lock ) {
246 unlock( cond->lock );
247 #if !defined( __CFA_NO_STATISTICS__ )
248 kernelTLS.this_stats = copy->t->curr_cluster->stats;
249 #endif
250 unpark( copy->t );
251 } else {
252 add_(*copy->lock, copy->t); // call lock's add_
253 }
254 }
255 unlock( cond->lock );
[848439f]256 }
257
[eeb5023]258 void alarm_node_wrap_cast( alarm_node_t & a ) {
[c5bbb9b]259 timeout_handler( (alarm_node_wrap(L) &)a );
[848439f]260 }
261
262 void ?{}( condition_variable(L) & this ){
[eeb5023]263 this.lock{};
264 this.blocked_threads{};
265 this.count = 0;
[848439f]266 }
267
268 void ^?{}( condition_variable(L) & this ){
269 // default
270 }
271
[eeb5023]272 void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
273 this.alarm_node{ thrd, alarm, period, callback };
[848439f]274 }
275
[eeb5023]276 void ^?{}( alarm_node_wrap(L) & this ) {
[848439f]277 // default
278 }
279
[eeb5023]280 bool notify_one( condition_variable(L) & this ) with( this ) {
[848439f]281 lock( lock __cfaabi_dbg_ctx2 );
282 bool ret = !!blocked_threads;
283 info_thread(L) * popped = pop_head( blocked_threads );
[eeb5023]284 popped->listed = false;
[848439f]285 if(popped != 0p) {
[eeb5023]286 count--;
[c5bbb9b]287 if (popped->lock) {
288 add_(*popped->lock, popped->t);
289 } else {
290 unpark(popped->t);
291 }
[848439f]292 }
293 unlock( lock );
294 return ret;
295 }
296
[eeb5023]297 bool notify_all( condition_variable(L) & this ) with(this) {
[848439f]298 lock( lock __cfaabi_dbg_ctx2 );
299 bool ret = blocked_threads ? true : false;
300 while( blocked_threads ) {
301 info_thread(L) * popped = pop_head( blocked_threads );
[eeb5023]302 popped->listed = false;
[848439f]303 if(popped != 0p){
[eeb5023]304 count--;
[c5bbb9b]305 if (popped->lock) {
306 add_(*popped->lock, popped->t);
307 } else {
308 unpark(popped->t);
309 }
[848439f]310 }
311 }
312 unlock( lock );
313 return ret;
314 }
315
[eeb5023]316 uintptr_t front( condition_variable(L) & this ) with(this) {
317 if(!blocked_threads) return NULL;
318 return peek(blocked_threads)->info;
[848439f]319 }
320
[eeb5023]321 bool empty( condition_variable(L) & this ) with(this) {
[848439f]322 return blocked_threads ? false : true;
323 }
324
[eeb5023]325 int counter( condition_variable(L) & this ) with(this) {
[848439f]326 return count;
327 }
328
[eeb5023]329 // helper for wait()'s' without a timeout
330 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
[848439f]331 lock( lock __cfaabi_dbg_ctx2 );
[eeb5023]332 append( this.blocked_threads, &i );
[848439f]333 count++;
[eeb5023]334 i.listed = true;
335 size_t recursion_count;
336 if (i.lock) {
337 recursion_count = get_recursion_count(*i.lock);
338 remove_( *i.lock );
339 }
340
[848439f]341 unlock( lock );
[eeb5023]342 park( ); // blocks here
343
344 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
[848439f]345 }
346
[eeb5023]347 // helper for wait()'s' with a timeout
348 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
349 lock( lock __cfaabi_dbg_ctx2 );
350
351 info_thread(L) * queue_ptr = &info;
352
353 alarm_node_wrap(L) node_wrap = { info.t, t, 0`s, alarm_node_wrap_cast };
354 node_wrap.cond = &this;
355 node_wrap.i = &queue_ptr;
[848439f]356
[eeb5023]357 register_self( &node_wrap.alarm_node );
358
359 append( blocked_threads, queue_ptr );
360 info.listed = true;
361 count++;
362
363 size_t recursion_count;
364 if (info.lock) {
365 recursion_count = get_recursion_count(*info.lock);
366 remove_( *info.lock );
367 }
368
369 unlock( lock );
370 park();
371
372 if (info.lock) set_recursion_count(*info.lock, recursion_count);
373 }
374
375 void wait( condition_variable(L) & this ) with(this) {
[848439f]376 info_thread( L ) i = { kernelTLS.this_thread };
377 queue_info_thread( this, i );
378 }
379
[eeb5023]380 void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
[848439f]381 info_thread( L ) i = { kernelTLS.this_thread, info };
382 queue_info_thread( this, i );
383 }
[eeb5023]384
385 void wait( condition_variable(L) & this, Duration duration ) with(this) {
386 info_thread( L ) i = { kernelTLS.this_thread };
387 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]388 }
389
[eeb5023]390 void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
391 info_thread( L ) i = { kernelTLS.this_thread, info };
392 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]393 }
394
[eeb5023]395 void wait( condition_variable(L) & this, Time time ) with(this) {
396 info_thread( L ) i = { kernelTLS.this_thread };
397 queue_info_thread_timeout(this, i, time);
[848439f]398 }
399
[eeb5023]400 void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
401 info_thread( L ) i = { kernelTLS.this_thread, info };
402 queue_info_thread_timeout(this, i, time);
[848439f]403 }
404
[eeb5023]405 void wait( condition_variable(L) & this, L & l ) with(this) {
[848439f]406 info_thread(L) i = { kernelTLS.this_thread };
[eeb5023]407 i.lock = &l;
408 queue_info_thread( this, i );
[848439f]409 }
410
[eeb5023]411 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
[848439f]412 info_thread(L) i = { kernelTLS.this_thread, info };
[eeb5023]413 i.lock = &l;
414 queue_info_thread( this, i );
[848439f]415 }
[eeb5023]416
417 void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
418 info_thread(L) i = { kernelTLS.this_thread };
419 i.lock = &l;
420 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]421 }
[eeb5023]422
423 void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
424 info_thread(L) i = { kernelTLS.this_thread, info };
425 i.lock = &l;
426 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]427 }
[eeb5023]428
429 void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
430 info_thread(L) i = { kernelTLS.this_thread };
431 i.lock = &l;
432 queue_info_thread_timeout(this, i, time );
[848439f]433 }
[eeb5023]434
435 void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
436 info_thread(L) i = { kernelTLS.this_thread, info };
437 i.lock = &l;
438 queue_info_thread_timeout(this, i, time );
[848439f]439 }
440}
Note: See TracBrowser for help on using the repository browser.