source: doc/working/unified_semaphores/semaphore.cfa @ 4bb5d36

ADTast-experimentalpthread-emulationqualifiedEnum
Last change on this file since 4bb5d36 was c2409fd, checked in by caparsons <caparson@…>, 4 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.