source: libcfa/src/concurrency/locks.cfa@ 0dd9a5e

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 0dd9a5e was 3959595, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

  • Property mode set to 100644
File size: 11.5 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 ) {
[be73f30]78 $thread * thrd = active_thread();
[848439f]79 lock( lock __cfaabi_dbg_ctx2 );
[be73f30]80 if ( owner == thrd && !multi_acquisition) {
[848439f]81 fprintf(stderr, "A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock."); // Possibly throw instead
[eeb5023]82 exit(EXIT_FAILURE);
[be73f30]83 } else if ( owner != 0p && owner != thrd ) {
84 append( blocked_threads, thrd );
[848439f]85 wait_count++;
86 unlock( lock );
[eeb5023]87 park( );
[be73f30]88 } else if ( owner == thrd && multi_acquisition ) {
[848439f]89 recursion_count++;
90 unlock( lock );
91 } else {
[be73f30]92 owner = thrd;
[848439f]93 recursion_count = 1;
94 unlock( lock );
95 }
96}
97
98bool try_lock( blocking_lock & this ) with( this ) {
[be73f30]99 $thread * thrd = active_thread();
[848439f]100 bool ret = false;
101 lock( lock __cfaabi_dbg_ctx2 );
102 if ( owner == 0p ) {
[be73f30]103 owner = thrd;
[848439f]104 if ( multi_acquisition ) recursion_count = 1;
105 ret = true;
[be73f30]106 } else if ( owner == thrd && multi_acquisition ) {
[848439f]107 recursion_count++;
108 ret = true;
109 }
110 unlock( lock );
111 return ret;
112}
113
114void unlock( blocking_lock & this ) with( this ) {
115 lock( lock __cfaabi_dbg_ctx2 );
116 if ( owner == 0p ){ // no owner implies lock isn't held
117 fprintf( stderr, "There was an attempt to release a lock that isn't held" );
118 return;
[3959595]119 } else if ( strict_owner && active_thread() ) {
[848439f]120 fprintf( stderr, "A thread other than the owner attempted to release an owner lock" );
121 return;
122 }
123 recursion_count--;
124 if ( recursion_count == 0 ) {
125 $thread * thrd = pop_head( blocked_threads );
126 owner = thrd;
127 recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
128 wait_count--;
[eeb5023]129 unpark( thrd );
[848439f]130 }
131 unlock( lock );
132}
133
134size_t wait_count( blocking_lock & this ) with( this ) {
135 return wait_count;
136}
137
138
139void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {
140 recursion_count = recursion;
141}
142
143size_t get_recursion_count( blocking_lock & this ) with( this ) {
144 return recursion_count;
145}
146
147void add_( blocking_lock & this, $thread * t ) with( this ) {
148 lock( lock __cfaabi_dbg_ctx2 );
149 if ( owner != 0p ) {
150 append( blocked_threads, t );
151 wait_count++;
152 unlock( lock );
153 } else {
154 owner = t;
155 if ( multi_acquisition ) recursion_count = 1;
[eeb5023]156 #if !defined( __CFA_NO_STATISTICS__ )
157 kernelTLS.this_stats = t->curr_cluster->stats;
158 #endif
159 unpark( t );
[848439f]160 unlock( lock );
161 }
162}
163
164void remove_( blocking_lock & this ) with( this ) {
165 lock( lock __cfaabi_dbg_ctx2 );
166 if ( owner == 0p ){ // no owner implies lock isn't held
167 fprintf( stderr, "A lock that is not held was passed to a synchronization lock" );
[3959595]168 } else if ( strict_owner && active_thread() ) {
[848439f]169 fprintf( stderr, "A thread other than the owner of a lock passed it to a synchronization lock" );
170 } else {
171 $thread * thrd = pop_head( blocked_threads );
172 owner = thrd;
173 recursion_count = ( thrd && multi_acquisition ? 1 : 0 );
174 wait_count--;
[eeb5023]175 unpark( thrd );
[848439f]176 }
177 unlock( lock );
178}
179
180///////////////////////////////////////////////////////////////////
181//// Overloaded routines for traits
182///////////////////////////////////////////////////////////////////
183
[eeb5023]184// This is temporary until an inheritance bug is fixed
[848439f]185
186void lock( mutex_lock & this ){
187 lock( (blocking_lock &)this );
188}
189
190void unlock( mutex_lock & this ){
191 unlock( (blocking_lock &)this );
192}
193
194void add_( mutex_lock & this, struct $thread * t ){
195 add_( (blocking_lock &)this, t );
196}
197
198void remove_( mutex_lock & this ){
199 remove_( (blocking_lock &)this );
200}
201
202void set_recursion_count( mutex_lock & this, size_t recursion ){
203 set_recursion_count( (blocking_lock &)this, recursion );
204}
205
206size_t get_recursion_count( mutex_lock & this ){
207 get_recursion_count( (blocking_lock &)this );
208}
209
210void lock( recursive_mutex_lock & this ){
211 lock( (blocking_lock &)this );
212}
213
214void unlock( recursive_mutex_lock & this ){
215 unlock( (blocking_lock &)this );
216}
217
218void add_( recursive_mutex_lock & this, struct $thread * t ){
219 add_( (blocking_lock &)this, t );
220}
221
222void remove_( recursive_mutex_lock & this ){
223 remove_( (blocking_lock &)this );
224}
225
226void set_recursion_count( recursive_mutex_lock & this, size_t recursion ){
227 set_recursion_count( (blocking_lock &)this, recursion );
228}
229
230size_t get_recursion_count( recursive_mutex_lock & this ){
231 get_recursion_count( (blocking_lock &)this );
232}
233
234///////////////////////////////////////////////////////////////////
[eeb5023]235//// condition variable
[848439f]236///////////////////////////////////////////////////////////////////
237
238forall(dtype L | is_blocking_lock(L)) {
239
[c5bbb9b]240 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
[eeb5023]241 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
242 lock( cond->lock __cfaabi_dbg_ctx2 );
243 if ( (*i)->listed ) { // is thread on queue
244 info_thread(L) * copy = *i;
245 remove( cond->blocked_threads, i ); //remove this thread O(1)
[c5bbb9b]246 cond->wait_count--;
[eeb5023]247 if( !copy->lock ) {
248 unlock( cond->lock );
249 #if !defined( __CFA_NO_STATISTICS__ )
[3959595]250 #warning unprotected access to tls TODO discuss this
[eeb5023]251 kernelTLS.this_stats = copy->t->curr_cluster->stats;
252 #endif
253 unpark( copy->t );
254 } else {
255 add_(*copy->lock, copy->t); // call lock's add_
256 }
257 }
258 unlock( cond->lock );
[848439f]259 }
260
[eeb5023]261 void alarm_node_wrap_cast( alarm_node_t & a ) {
[c5bbb9b]262 timeout_handler( (alarm_node_wrap(L) &)a );
[848439f]263 }
264
265 void ?{}( condition_variable(L) & this ){
[eeb5023]266 this.lock{};
267 this.blocked_threads{};
268 this.count = 0;
[848439f]269 }
270
271 void ^?{}( condition_variable(L) & this ){
272 // default
273 }
274
[eeb5023]275 void ?{}( alarm_node_wrap(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
276 this.alarm_node{ thrd, alarm, period, callback };
[848439f]277 }
278
[eeb5023]279 void ^?{}( alarm_node_wrap(L) & this ) {
[848439f]280 // default
281 }
282
[eeb5023]283 bool notify_one( condition_variable(L) & this ) with( this ) {
[848439f]284 lock( lock __cfaabi_dbg_ctx2 );
285 bool ret = !!blocked_threads;
286 info_thread(L) * popped = pop_head( blocked_threads );
[eeb5023]287 popped->listed = false;
[848439f]288 if(popped != 0p) {
[eeb5023]289 count--;
[c5bbb9b]290 if (popped->lock) {
[848439f]291 add_(*popped->lock, popped->t);
292 } else {
[c5bbb9b]293 unpark(popped->t);
[848439f]294 }
295 }
296 unlock( lock );
297 return ret;
298 }
299
[eeb5023]300 bool notify_all( condition_variable(L) & this ) with(this) {
[848439f]301 lock( lock __cfaabi_dbg_ctx2 );
302 bool ret = blocked_threads ? true : false;
303 while( blocked_threads ) {
304 info_thread(L) * popped = pop_head( blocked_threads );
[eeb5023]305 popped->listed = false;
[848439f]306 if(popped != 0p){
[eeb5023]307 count--;
[c5bbb9b]308 if (popped->lock) {
[848439f]309 add_(*popped->lock, popped->t);
310 } else {
[c5bbb9b]311 unpark(popped->t);
[848439f]312 }
313 }
314 }
315 unlock( lock );
316 return ret;
317 }
318
[eeb5023]319 uintptr_t front( condition_variable(L) & this ) with(this) {
320 if(!blocked_threads) return NULL;
321 return peek(blocked_threads)->info;
[848439f]322 }
323
[eeb5023]324 bool empty( condition_variable(L) & this ) with(this) {
[848439f]325 return blocked_threads ? false : true;
326 }
327
[eeb5023]328 int counter( condition_variable(L) & this ) with(this) {
[848439f]329 return count;
330 }
331
[eeb5023]332 // helper for wait()'s' without a timeout
333 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
[848439f]334 lock( lock __cfaabi_dbg_ctx2 );
[eeb5023]335 append( this.blocked_threads, &i );
[848439f]336 count++;
[eeb5023]337 i.listed = true;
338 size_t recursion_count;
339 if (i.lock) {
340 recursion_count = get_recursion_count(*i.lock);
341 remove_( *i.lock );
342 }
[848439f]343
344 unlock( lock );
[eeb5023]345 park( ); // blocks here
[848439f]346
[eeb5023]347 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
[848439f]348 }
349
[eeb5023]350 // helper for wait()'s' with a timeout
351 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
352 lock( lock __cfaabi_dbg_ctx2 );
[848439f]353
[eeb5023]354 info_thread(L) * queue_ptr = &info;
[848439f]355
[eeb5023]356 alarm_node_wrap(L) node_wrap = { info.t, t, 0`s, alarm_node_wrap_cast };
357 node_wrap.cond = &this;
358 node_wrap.i = &queue_ptr;
[848439f]359
[eeb5023]360 register_self( &node_wrap.alarm_node );
[848439f]361
[eeb5023]362 append( blocked_threads, queue_ptr );
363 info.listed = true;
[848439f]364 count++;
[eeb5023]365
366 size_t recursion_count;
367 if (info.lock) {
368 recursion_count = get_recursion_count(*info.lock);
369 remove_( *info.lock );
370 }
371
[848439f]372 unlock( lock );
[eeb5023]373 park();
[848439f]374
[eeb5023]375 if (info.lock) set_recursion_count(*info.lock, recursion_count);
[848439f]376 }
377
[eeb5023]378 void wait( condition_variable(L) & this ) with(this) {
[3959595]379 info_thread( L ) i = { active_thread() };
[848439f]380 queue_info_thread( this, i );
381 }
382
[eeb5023]383 void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
[3959595]384 info_thread( L ) i = { active_thread(), info };
[848439f]385 queue_info_thread( this, i );
386 }
387
[eeb5023]388 void wait( condition_variable(L) & this, Duration duration ) with(this) {
[3959595]389 info_thread( L ) i = { active_thread() };
[eeb5023]390 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]391 }
392
[3959595]393 void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
394 info_thread( L ) i = { active_thread(), info };
[eeb5023]395 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]396 }
397
[eeb5023]398 void wait( condition_variable(L) & this, Time time ) with(this) {
[3959595]399 info_thread( L ) i = { active_thread() };
[eeb5023]400 queue_info_thread_timeout(this, i, time);
[848439f]401 }
402
[eeb5023]403 void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
[3959595]404 info_thread( L ) i = { active_thread(), info };
[eeb5023]405 queue_info_thread_timeout(this, i, time);
[848439f]406 }
407
[eeb5023]408 void wait( condition_variable(L) & this, L & l ) with(this) {
[3959595]409 info_thread(L) i = { active_thread() };
[eeb5023]410 i.lock = &l;
411 queue_info_thread( this, i );
[848439f]412 }
413
[eeb5023]414 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
[3959595]415 info_thread(L) i = { active_thread(), info };
[eeb5023]416 i.lock = &l;
417 queue_info_thread( this, i );
[848439f]418 }
419
[eeb5023]420 void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
[3959595]421 info_thread(L) i = { active_thread() };
[eeb5023]422 i.lock = &l;
423 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]424 }
425
[eeb5023]426 void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
[3959595]427 info_thread(L) i = { active_thread(), info };
[eeb5023]428 i.lock = &l;
429 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]430 }
431
[eeb5023]432 void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
[3959595]433 info_thread(L) i = { active_thread() };
[eeb5023]434 i.lock = &l;
435 queue_info_thread_timeout(this, i, time );
[848439f]436 }
437
[eeb5023]438 void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
[3959595]439 info_thread(L) i = { active_thread(), info };
[eeb5023]440 i.lock = &l;
441 queue_info_thread_timeout(this, i, time );
[848439f]442 }
443}
Note: See TracBrowser for help on using the repository browser.