source: doc/working/unified_semaphores/semaphore.cfa@ b9c06b98

Last change on this file since b9c06b98 was c2409fd, checked in by caparsons <caparson@…>, 5 years ago

added WIP unified semaphore code

  • Property mode set to 100644
File size: 10.0 KB
Line 
1#include "semaphore.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
10forall(dtype L | is_blocking_lock(L)) {
11
12 void ?{}(base_semaphore(L) & this, int count, bool is_binary) {
13 this.count = count;
14 this.lock{};
15 this.blocked_threads{};
16 this.is_binary = is_binary;
17 }
18
19 void ^?{}(base_semaphore(L) & this) {
20 // default
21 }
22
23 void ?{}(binary_semaphore(L) & this) {
24 ((base_semaphore(L) &)this){ 1, true };
25 }
26
27 void ?{}(binary_semaphore(L) & this, int count) {
28 ((base_semaphore(L) &)this){ count, true };
29 }
30
31 void ^?{}(binary_semaphore(L) & this) {
32 // default
33 }
34
35 void ?{}(counting_semaphore(L) & this) {
36 ((base_semaphore(L) &)this){ 1, false };
37 }
38
39 void ?{}(counting_semaphore(L) & this, int count) {
40 ((base_semaphore(L) &)this){ count, false };
41 }
42
43 void ^?{}(counting_semaphore(L) & this) {
44 // default
45 }
46
47 void ?{}( alarm_node_semaphore(L) & this, $thread * thrd, Time alarm, Duration period, Alarm_Callback callback ) {
48 this.alarm_node{ thrd, alarm, period, callback };
49 }
50
51 void ^?{}( alarm_node_semaphore(L) & this ) {
52
53 }
54
55 void add_( base_semaphore(L) & this, struct $thread * t ) with( this ) {
56 lock( lock __cfaabi_dbg_ctx2 );
57 #if !defined( __CFA_NO_STATISTICS__ )
58 kernelTLS.this_stats = t->curr_cluster->stats;
59 #endif
60 unpark( t );
61 unlock( lock );
62 }
63
64 void remove_( base_semaphore(L) & this ) with( this ) {
65 V(this);
66 }
67
68 ////////////////////////////////////////////////////////////////////////////////
69 // These extras are needed since the inheritance is broken with traits
70 ////////////////////////////////////////////////////////////////////////////////
71
72 void add_( binary_semaphore(L) & this, struct $thread * t ) with( this ) {
73 add_( (base_semaphore(L) &)this, t );
74 }
75
76 void remove_( binary_semaphore(L) & this ) with( this ) {
77 remove_( (base_semaphore(L) &)this );
78 }
79
80 void add_( counting_semaphore(L) & this, struct $thread * t ) with( this ) {
81 add_( (base_semaphore(L) &)this, t );
82 }
83
84 void remove_( counting_semaphore(L) & this ) with( this ) {
85 remove_( (base_semaphore(L) &)this );
86 }
87
88 ////////////////////////////////////////////////////////////////////////////////
89 ////////////////////////////////////////////////////////////////////////////////
90
91 void timeout_handler ( alarm_node_semaphore(L) & this ) with( this ) {
92 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
93 lock( sem->lock __cfaabi_dbg_ctx2 );
94 if ( (*i)->listed ) { // is thread on queue
95 info_thread(L) * copy = *i;
96 remove( sem->blocked_threads, i ); //remove this thread O(1)
97 sem->count++;
98 if( !copy->lock ) {
99 unlock( sem->lock );
100 #if !defined( __CFA_NO_STATISTICS__ )
101 kernelTLS.this_stats = copy->t->curr_cluster->stats;
102 #endif
103 unpark( copy->t );
104 } else {
105 add_(*copy->lock, copy->t); // call lock's add_
106 }
107 }
108 unlock( sem->lock );
109 }
110
111 void alarm_node_sem_cast( alarm_node_t & a ) {
112 timeout_handler( (alarm_node_semaphore(L) &)a );
113 }
114
115 void handle_P(base_semaphore(L) & this, info_thread( L ) & i ) with( this ) {
116 lock( lock __cfaabi_dbg_ctx2 );
117 if ( count <= 0) {
118 append( blocked_threads, &i );
119
120 if (!is_binary) count--;
121
122 i.listed = true;
123
124 size_t recursion_count;
125 if (i.lock) {
126 recursion_count = get_recursion_count( *i.lock );
127 remove_( *i.lock );
128 }
129
130 unlock( lock );
131 park( );
132
133 if (i.lock) set_recursion_count( *i.lock, recursion_count );
134 } else {
135 if (i.lock) {
136 size_t recursion_count = get_recursion_count( *i.lock );
137 remove_( *i.lock );
138 add_( *i.lock, i.t );
139 set_recursion_count( *i.lock, recursion_count );
140 }
141 count--;
142 unlock( lock );
143 }
144 }
145
146 void handle_P_timeout(base_semaphore(L) & this, info_thread( L ) & i, Time time) with( this ) {
147 lock( lock __cfaabi_dbg_ctx2 );
148 if ( count <= 0) {
149 append( blocked_threads, &i );
150
151 if (!is_binary) count--;
152
153 info_thread(L) * queue_ptr = &i;
154 i.listed = true;
155
156 alarm_node_semaphore(L) node_wrap = { i.t, time, 0`s, alarm_node_sem_cast };
157 node_wrap.sem = &this;
158 node_wrap.i = &queue_ptr;
159
160 register_self( &node_wrap.alarm_node );
161
162 size_t recursion_count;
163 if (i.lock) {
164 recursion_count = get_recursion_count( *i.lock );
165 remove_( *i.lock );
166 }
167
168 unlock( lock );
169 park( );
170
171 if (i.lock) set_recursion_count( *i.lock, recursion_count );
172 } else {
173 count--;
174 unlock( lock );
175 }
176 }
177
178 void P(base_semaphore(L) & this) with( this ) {
179 info_thread( L ) i = { kernelTLS.this_thread };
180 handle_P(this, i);
181 }
182
183 void P(base_semaphore(L) & this, uintptr_t info) with( this ) {
184 info_thread( L ) i = { kernelTLS.this_thread, info };
185 handle_P(this, i);
186 }
187
188 void P(base_semaphore(L) & this, Duration duration) with( this ) {
189 info_thread( L ) i = { kernelTLS.this_thread };
190 handle_P_timeout(this, i, __kernel_get_time() + duration);
191 }
192
193 void P(base_semaphore(L) & this, uintptr_t info, Duration duration) with( this ) {
194 info_thread( L ) i = { kernelTLS.this_thread, info };
195 handle_P_timeout(this, i, __kernel_get_time() + duration);
196 }
197
198 void P(base_semaphore(L) & this, Time time) with( this ) {
199 info_thread( L ) i = { kernelTLS.this_thread };
200 handle_P_timeout(this, i, time);
201 }
202
203 void P(base_semaphore(L) & this, uintptr_t info, Time time) with( this ) {
204 info_thread( L ) i = { kernelTLS.this_thread, info };
205 handle_P_timeout(this, i, time);
206 }
207
208 void P(base_semaphore(L) & this, L & l ) with( this ) {
209 info_thread( L ) i = { kernelTLS.this_thread };
210 i.lock = &l;
211 handle_P(this, i);
212 }
213
214 void P(base_semaphore(L) & this, L & l, uintptr_t info) with( this ) {
215 info_thread( L ) i = { kernelTLS.this_thread, info };
216 i.lock = &l;
217 handle_P(this, i);
218 }
219
220 void P(base_semaphore(L) & this, L & l, Duration duration ) with( this ) {
221 info_thread( L ) i = { kernelTLS.this_thread };
222 i.lock = &l;
223 handle_P_timeout(this, i, __kernel_get_time() + duration);
224 }
225
226 void P(base_semaphore(L) & this, L & l, uintptr_t info, Duration duration) with( this ) {
227 info_thread( L ) i = { kernelTLS.this_thread, info };
228 i.lock = &l;
229 handle_P_timeout(this, i, __kernel_get_time() + duration);
230 }
231
232 void P(base_semaphore(L) & this, L & l, Time time) with( this ) {
233 info_thread( L ) i = { kernelTLS.this_thread };
234 i.lock = &l;
235 handle_P_timeout(this, i, time);
236 }
237
238 void P(base_semaphore(L) & this, L & l, uintptr_t info, Time time) with( this ) {
239 info_thread( L ) i = { kernelTLS.this_thread, info };
240 i.lock = &l;
241 handle_P_timeout(this, i, time);
242 }
243
244 bool tryP(base_semaphore(L) & this) with( this ) {
245 lock( lock __cfaabi_dbg_ctx2 );
246 if ( count <= 0) {
247 unlock( lock );
248 return false;
249 } else {
250 count--;
251 }
252 unlock( lock );
253 }
254
255 void V(base_semaphore(L) & this) with( this ) {
256 lock( lock __cfaabi_dbg_ctx2 );
257 if( count < 0) {
258 info_thread(L) * i = pop_head( blocked_threads );
259 i->listed = false;
260 count++;
261 if ( i != 0p ) {
262 if (i->lock) {
263 add_(*i->lock, i->t);
264 } else {
265 unpark(i->t);
266 }
267 }
268 } else if (!is_binary || count == 0) {
269 count++;
270 } else {
271 fprintf( stderr, "A binary semaphore was V'd when it was already at 1" );
272 }
273 unlock( lock );
274 }
275
276
277 // TODO: Should we be able to V a binary semaphore multiple times to wake up multiple thds?
278 // right now we can't
279 void V(base_semaphore(L) & this, int times) with( this ) {
280 assert( times > 0 );
281 lock( lock __cfaabi_dbg_ctx2 );
282 while ( count < 0 && times > 0 ) {
283 info_thread(L) * i = pop_head( blocked_threads );
284 i->listed = false;
285 count++;
286 if ( i != 0p ) {
287 if (i->lock) {
288 add_(*i->lock, i->t);
289 } else {
290 unpark(i->t);
291 }
292 }
293 times--;
294 }
295 if( !is_binary ) {
296 count += times;
297 } else if (count == 0 && times > 1) {
298 fprintf( stderr, "A binary semaphore was V'd when it was already at 1" );
299 } else {
300 count++;
301 }
302 unlock( lock );
303 }
304
305 // void ?++(base_semaphore(L) & this) with( this ) {
306 // V(this);
307 // }
308
309 // void ?--(base_semaphore(L) & this) with( this ) {
310 // P(this);
311 // }
312
313 // void ?`V(base_semaphore(L) & this) with( this ) {
314 // V(this);
315 // }
316
317 // void ?`P(base_semaphore(L) & this) with( this ) {
318 // P(this);
319 // }
320
321 uintptr_t front(base_semaphore(L) & this) with( this ) {
322 info_thread(L) *front = peek(blocked_threads);
323 if(!blocked_threads) return 0;
324 return front->info;
325 }
326
327 bool empty(base_semaphore(L) & this) with( this ) {
328 return blocked_threads ? false : true;
329 }
330
331 int counter(base_semaphore(L) & this) with( this ) {
332 return count;
333 }
334
335 // these are just to allow the semaphore to be a part of the is_blocking_lock trait
336 // they do nothing
337 void set_recursion_count( base_semaphore(L) & this, size_t recursion ) with( this ) {
338 // default
339 }
340
341 size_t get_recursion_count( base_semaphore(L) & this ) with( this ) {
342 return 0;
343 }
344
345 ////////////////////////////////////////////////////////////////////////////////
346 // These extras are needed since the inheritance is broken with traits
347 // normally I'd cast to a semaphore & to call the parent but theres no need
348 // since these routines are so simple
349 ////////////////////////////////////////////////////////////////////////////////
350
351 void set_recursion_count( binary_semaphore(L) & this, size_t recursion ) with( this ) {
352 // default
353 }
354
355 size_t get_recursion_count( binary_semaphore(L) & this ) with( this ) {
356 return 0;
357 }
358
359 void set_recursion_count( counting_semaphore(L) & this, size_t recursion ) with( this ) {
360 // default
361 }
362
363 size_t get_recursion_count( counting_semaphore(L) & this ) with( this ) {
364 return 0;
365 }
366
367 ////////////////////////////////////////////////////////////////////////////////
368 ////////////////////////////////////////////////////////////////////////////////
369}
370
371thread T1 {};
372thread T2 {};
373
374// counting_semaphore( ) s0, s1;
375
376// void main( T1 & this ) {
377// printf("T1 start\n");
378// V(s1);
379// P(s0);
380// P(s0);
381// V(s1, 2);
382
383// printf("T1 done\n");
384// }
385
386// void main( T2 & this ) {
387// printf("T2 start\n");
388// V(s0);
389// P(s1);
390// P(s1, s0);
391// P(s1);
392// printf("T2 done\n");
393// }
394
395int main() {
396 printf("start\n");
397 // processor p[2];
398 // {
399 // T1 t1;
400 // T2 t2;
401 // }
402 printf("done\n");
403}
Note: See TracBrowser for help on using the repository browser.