source: libcfa/src/concurrency/locks.cfa@ 3f8baf4

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

added bool return to timeout routines and removed redundant listed field

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