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

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

small cleanup

  • Property mode set to 100644
File size: 11.7 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///////////////////////////////////////////////////////////////////
[cad1df1]13
[848439f]14forall(dtype L | is_blocking_lock(L)) {
15 void ?{}( info_thread(L) & this, $thread * t ) {
[cad1df1]16 ((Seqable &) this){};
[848439f]17 this.t = t;
18 this.lock = 0p;
[eeb5023]19 this.listed = false;
[848439f]20 }
21
22 void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) {
[cad1df1]23 ((Seqable &) this){};
[848439f]24 this.t = t;
25 this.info = info;
26 this.lock = 0p;
[eeb5023]27 this.listed = false;
[848439f]28 }
29
[cad1df1]30 void ^?{}( info_thread(L) & this ){ }
[c131a02]31
32 info_thread(L) *& Back( info_thread(L) * this ) {
33 return (info_thread(L) *)Back( (Seqable *)this );
34 }
35
36 info_thread(L) *& Next( info_thread(L) * this ) {
37 return (info_thread(L) *)Next( (Colable *)this );
38 }
39
40 bool listed( info_thread(L) * this ) {
41 return Next( (Colable *)this ) != 0p;
42 }
[848439f]43}
[cad1df1]44
[848439f]45///////////////////////////////////////////////////////////////////
46//// Blocking Locks
47///////////////////////////////////////////////////////////////////
48
49void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {
50 this.lock{};
51 this.blocked_threads{};
52 this.wait_count = 0;
53 this.multi_acquisition = multi_acquisition;
54 this.strict_owner = strict_owner;
55 this.owner = 0p;
56 this.recursion_count = 0;
57}
58
[cad1df1]59void ^?{}( blocking_lock & this ) {}
60void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
61void ^?{}( single_acquisition_lock & this ) {}
62void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
63void ^?{}( owner_lock & this ) {}
64void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
65void ^?{}( multiple_acquisition_lock & this ) {}
[848439f]66
67void lock( blocking_lock & this ) with( this ) {
68 lock( lock __cfaabi_dbg_ctx2 );
[6a8882c]69 if ( owner == active_thread() && !multi_acquisition) {
[cad1df1]70 abort("A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock.");
[6a8882c]71 } else if ( owner != 0p && owner != active_thread() ) {
[c131a02]72 addTail( blocked_threads, *active_thread() );
[848439f]73 wait_count++;
74 unlock( lock );
[eeb5023]75 park( );
[6a8882c]76 } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]77 recursion_count++;
78 unlock( lock );
79 } else {
[6a8882c]80 owner = active_thread();
[848439f]81 recursion_count = 1;
82 unlock( lock );
83 }
84}
85
86bool try_lock( blocking_lock & this ) with( this ) {
87 bool ret = false;
88 lock( lock __cfaabi_dbg_ctx2 );
89 if ( owner == 0p ) {
[6a8882c]90 owner = active_thread();
91 recursion_count = 1;
[848439f]92 ret = true;
[6a8882c]93 } else if ( owner == active_thread() && multi_acquisition ) {
[848439f]94 recursion_count++;
95 ret = true;
96 }
97 unlock( lock );
98 return ret;
99}
100
[cad1df1]101void unlock_error_check( blocking_lock & this ) with( this ) {
[848439f]102 if ( owner == 0p ){ // no owner implies lock isn't held
[cad1df1]103 abort( "There was an attempt to release a lock that isn't held" );
[6a8882c]104 } else if ( strict_owner && owner != active_thread() ) {
[cad1df1]105 abort( "A thread other than the owner attempted to release an owner lock" );
[848439f]106 }
[cad1df1]107}
108
109void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
[c131a02]110 $thread * t = &dropHead( blocked_threads );
[cad1df1]111 owner = t;
112 recursion_count = ( t ? 1 : 0 );
113 wait_count--;
114 unpark( t );
115}
116
117void unlock( blocking_lock & this ) with( this ) {
118 lock( lock __cfaabi_dbg_ctx2 );
119 unlock_error_check( this );
[848439f]120 recursion_count--;
121 if ( recursion_count == 0 ) {
[cad1df1]122 pop_and_set_new_owner( this );
[848439f]123 }
124 unlock( lock );
125}
126
127size_t wait_count( blocking_lock & this ) with( this ) {
128 return wait_count;
129}
130
131void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {
132 recursion_count = recursion;
133}
134
135size_t get_recursion_count( blocking_lock & this ) with( this ) {
136 return recursion_count;
137}
138
139void add_( blocking_lock & this, $thread * t ) with( this ) {
140 lock( lock __cfaabi_dbg_ctx2 );
141 if ( owner != 0p ) {
[c131a02]142 addTail( blocked_threads, *t );
[848439f]143 wait_count++;
144 unlock( lock );
145 } else {
146 owner = t;
[6a8882c]147 recursion_count = 1;
[eeb5023]148 unpark( t );
[848439f]149 unlock( lock );
150 }
151}
152
153void remove_( blocking_lock & this ) with( this ) {
154 lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]155 unlock_error_check( this );
156 pop_and_set_new_owner( this );
[848439f]157 unlock( lock );
158}
159
160///////////////////////////////////////////////////////////////////
161//// Overloaded routines for traits
162///////////////////////////////////////////////////////////////////
163
[eeb5023]164// This is temporary until an inheritance bug is fixed
[848439f]165
[cad1df1]166void lock( single_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
167void unlock( single_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
168void add_( single_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
169void remove_( single_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
170void set_recursion_count( single_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
171size_t get_recursion_count( single_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
172
173void lock( owner_lock & this ){ lock( (blocking_lock &)this ); }
174void unlock( owner_lock & this ){ unlock( (blocking_lock &)this ); }
175void add_( owner_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
176void remove_( owner_lock & this ){ remove_( (blocking_lock &)this ); }
177void set_recursion_count( owner_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
178size_t get_recursion_count( owner_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
179
180void lock( multiple_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
181void unlock( multiple_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
182void add_( multiple_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
183void remove_( multiple_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
184void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
185size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
[848439f]186
187///////////////////////////////////////////////////////////////////
[eeb5023]188//// condition variable
[848439f]189///////////////////////////////////////////////////////////////////
190
191forall(dtype L | is_blocking_lock(L)) {
192
[c5bbb9b]193 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
[eeb5023]194 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
195 lock( cond->lock __cfaabi_dbg_ctx2 );
[cad1df1]196
197 if ( i->listed ) { // is thread on queue
198 cond->last_thread = i; // REMOVE THIS AFTER DEBUG
199 remove( cond->blocked_threads, *i ); //remove this thread O(1)
[6a8882c]200 cond->count--;
[cad1df1]201 if( !i->lock ) {
202 unpark( i->t );
[eeb5023]203 } else {
[cad1df1]204 add_(*i->lock, i->t); // call lock's add_
[eeb5023]205 }
206 }
207 unlock( cond->lock );
[848439f]208 }
209
[cad1df1]210 void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
[848439f]211
212 void ?{}( condition_variable(L) & this ){
[eeb5023]213 this.lock{};
214 this.blocked_threads{};
215 this.count = 0;
[cad1df1]216 this.last_thread = 0p; // REMOVE AFTER DEBUG
[848439f]217 }
218
[cad1df1]219 void ^?{}( condition_variable(L) & this ){ }
[848439f]220
[4aeaee5]221 void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback ) {
222 this.alarm_node{ callback, alarm, period };
[848439f]223 }
224
[cad1df1]225 void ^?{}( alarm_node_wrap(L) & this ) { }
[848439f]226
[cad1df1]227 void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
228 if(&popped != 0p) {
229 popped.listed = false;
[eeb5023]230 count--;
[cad1df1]231 if (popped.lock) {
232 add_(*popped.lock, popped.t);
[848439f]233 } else {
[cad1df1]234 unpark(popped.t);
[848439f]235 }
236 }
[cad1df1]237 }
238
239 bool notify_one( condition_variable(L) & this ) with( this ) {
240 lock( lock __cfaabi_dbg_ctx2 );
241 bool ret = !empty(blocked_threads);
242 process_popped(this, dropHead( blocked_threads ));
[848439f]243 unlock( lock );
244 return ret;
245 }
246
[eeb5023]247 bool notify_all( condition_variable(L) & this ) with(this) {
[848439f]248 lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]249 bool ret = !empty(blocked_threads);
250 while( !empty(blocked_threads) ) {
251 process_popped(this, dropHead( blocked_threads ));
[848439f]252 }
253 unlock( lock );
254 return ret;
255 }
256
[eeb5023]257 uintptr_t front( condition_variable(L) & this ) with(this) {
[cad1df1]258 return empty(blocked_threads) ? NULL : head(blocked_threads).info;
[848439f]259 }
260
[cad1df1]261 bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); }
262
263 int counter( condition_variable(L) & this ) with(this) { return count; }
[848439f]264
[cad1df1]265 size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
266 addTail( blocked_threads, *i );
267 count++;
268 i->listed = true;
269 size_t recursion_count = 0;
270 if (i->lock) {
271 recursion_count = get_recursion_count(*i->lock);
272 remove_( *i->lock );
273 }
274 return recursion_count;
[848439f]275 }
276
[cad1df1]277 // helper for wait()'s' with no timeout
[eeb5023]278 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
[848439f]279 lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]280 size_t recursion_count = queue_and_get_recursion(this, &i);
[848439f]281 unlock( lock );
[eeb5023]282 park( ); // blocks here
283 if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
[848439f]284 }
285
[eeb5023]286 // helper for wait()'s' with a timeout
287 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
288 lock( lock __cfaabi_dbg_ctx2 );
[cad1df1]289 size_t recursion_count = queue_and_get_recursion(this, &info);
[4aeaee5]290 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast };
[eeb5023]291 node_wrap.cond = &this;
[cad1df1]292 node_wrap.i = &info;
[eeb5023]293 register_self( &node_wrap.alarm_node );
[848439f]294 unlock( lock );
[eeb5023]295 park();
[cad1df1]296 unregister_self( &node_wrap.alarm_node );
[eeb5023]297 if (info.lock) set_recursion_count(*info.lock, recursion_count);
[848439f]298 }
299
[eeb5023]300 void wait( condition_variable(L) & this ) with(this) {
[3959595]301 info_thread( L ) i = { active_thread() };
[848439f]302 queue_info_thread( this, i );
303 }
304
[eeb5023]305 void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
[3959595]306 info_thread( L ) i = { active_thread(), info };
[848439f]307 queue_info_thread( this, i );
308 }
[6a8882c]309
[eeb5023]310 void wait( condition_variable(L) & this, Duration duration ) with(this) {
[3959595]311 info_thread( L ) i = { active_thread() };
[eeb5023]312 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]313 }
314
[6a8882c]315 void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
[3959595]316 info_thread( L ) i = { active_thread(), info };
[eeb5023]317 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]318 }
319
[eeb5023]320 void wait( condition_variable(L) & this, Time time ) with(this) {
[3959595]321 info_thread( L ) i = { active_thread() };
[eeb5023]322 queue_info_thread_timeout(this, i, time);
[848439f]323 }
324
[eeb5023]325 void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
[3959595]326 info_thread( L ) i = { active_thread(), info };
[eeb5023]327 queue_info_thread_timeout(this, i, time);
[848439f]328 }
329
[eeb5023]330 void wait( condition_variable(L) & this, L & l ) with(this) {
[3959595]331 info_thread(L) i = { active_thread() };
[eeb5023]332 i.lock = &l;
333 queue_info_thread( this, i );
[848439f]334 }
335
[eeb5023]336 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
[3959595]337 info_thread(L) i = { active_thread(), info };
[eeb5023]338 i.lock = &l;
339 queue_info_thread( this, i );
[848439f]340 }
[6a8882c]341
[eeb5023]342 void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
[3959595]343 info_thread(L) i = { active_thread() };
[eeb5023]344 i.lock = &l;
345 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]346 }
[6a8882c]347
[eeb5023]348 void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
[3959595]349 info_thread(L) i = { active_thread(), info };
[eeb5023]350 i.lock = &l;
351 queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
[848439f]352 }
[6a8882c]353
[eeb5023]354 void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
[3959595]355 info_thread(L) i = { active_thread() };
[eeb5023]356 i.lock = &l;
357 queue_info_thread_timeout(this, i, time );
[848439f]358 }
[6a8882c]359
[eeb5023]360 void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
[3959595]361 info_thread(L) i = { active_thread(), info };
[eeb5023]362 i.lock = &l;
363 queue_info_thread_timeout(this, i, time );
[848439f]364 }
365}
Note: See TracBrowser for help on using the repository browser.