source: libcfa/src/concurrency/locks.cfa@ 2dda05d

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 2dda05d was 4aeaee5, checked in by Colby Alexander Parsons <caparsons@…>, 5 years ago

added alarm callback to union and refactored

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