source: libcfa/src/concurrency/invoke.h @ 1c01c58

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 1c01c58 was 1c01c58, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Rather large commit to get coroutine cancellation working.

This includes what you would expect, like new code in exceptions and a new
test, but it also includes a bunch of other things.

New coroutine state, currently just marks that the stack was cancelled. New
helpers for checking code structure and generating vtables. Changes to the
coroutine interface so resume may throw exceptions on cancellation, plus the
exception type that is thrown. Changes to the coroutine keyword generation to
generate exception code for each type of coroutine.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// invoke.h --
8//
9// Author           : Thierry Delisle
10// Created On       : Tue Jan 17 12:27:26 2016
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Thu Dec  5 16:26:03 2019
13// Update Count     : 44
14//
15
16#include "bits/containers.hfa"
17#include "bits/defs.hfa"
18#include "bits/locks.hfa"
19#include "kernel/fwd.hfa"
20
21#ifdef __cforall
22extern "C" {
23#endif
24
25#if ! defined(__CFA_INVOKE_PRIVATE__)
26#ifndef _INVOKE_H_
27#define _INVOKE_H_
28
29        struct __cfaehm_try_resume_node;
30        struct __cfaehm_base_exception_t;
31        struct exception_context_t {
32                struct __cfaehm_try_resume_node * top_resume;
33                struct __cfaehm_base_exception_t * current_exception;
34        };
35
36        struct __stack_context_t {
37                void * SP;
38                void * FP;
39        };
40
41        // low adresses  :           +----------------------+ <- start of allocation
42        //                           |  optional guard page |
43        //                           +----------------------+ <- __stack_t.limit
44        //                           |                      |
45        //                           |       /\ /\ /\       |
46        //                           |       || || ||       |
47        //                           |                      |
48        //                           |    program  stack    |
49        //                           |                      |
50        // __stack_info_t.storage -> +----------------------+ <- __stack_t.base
51        //                           |      __stack_t       |
52        // high adresses :           +----------------------+ <- end of allocation
53
54        struct __stack_t {
55                // stack grows towards stack limit
56                void * limit;
57
58                // base of stack
59                void * base;
60
61                // Information for exception handling.
62                struct exception_context_t exception_context;
63        };
64
65        struct __stack_info_t {
66                // pointer to stack
67                struct __stack_t * storage;
68        };
69
70        enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active, Cancelled };
71
72        struct $coroutine {
73                // context that is switch during a __cfactx_switch
74                struct __stack_context_t context;
75
76                // stack information of the coroutine
77                struct __stack_info_t stack;
78
79                // textual name for coroutine/task
80                const char * name;
81
82                // current execution status for coroutine
83                enum __Coroutine_State state;
84
85                // first coroutine to resume this one
86                struct $coroutine * starter;
87
88                // last coroutine to resume this one
89                struct $coroutine * last;
90
91                // If non-null stack must be unwound with this exception
92                struct _Unwind_Exception * cancellation;
93
94        };
95
96        static inline struct __stack_t * __get_stack( struct $coroutine * cor ) {
97                return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2));
98        }
99
100        // struct which calls the monitor is accepting
101        struct __waitfor_mask_t {
102                // the index of the accepted function, -1 if none
103                short * accepted;
104
105                // list of acceptable functions, null if any
106                __cfa_anonymous_object( __small_array_t(struct __acceptable_t) );
107        };
108
109        struct $monitor {
110                // spinlock to protect internal data
111                struct __spinlock_t lock;
112
113                // current owner of the monitor
114                struct $thread * owner;
115
116                // queue of threads that are blocked waiting for the monitor
117                __queue_t(struct $thread) entry_queue;
118
119                // stack of conditions to run next once we exit the monitor
120                __stack_t(struct __condition_criterion_t) signal_stack;
121
122                // monitor routines can be called recursively, we need to keep track of that
123                unsigned int recursion;
124
125                // mask used to know if some thread is waiting for something while holding the monitor
126                struct __waitfor_mask_t mask;
127
128                // node used to signal the dtor in a waitfor dtor
129                struct __condition_node_t * dtor_node;
130        };
131
132        struct __monitor_group_t {
133                // currently held monitors
134                __cfa_anonymous_object( __small_array_t($monitor*) );
135
136                // last function that acquired monitors
137                fptr_t func;
138        };
139
140        // Link lists fields
141        // instrusive link field for threads
142        struct __thread_desc_link {
143                struct $thread * next;
144                struct $thread * prev;
145                volatile unsigned long long ts;
146                int preferred;
147        };
148
149        struct $thread {
150                // Core threading fields
151                // context that is switch during a __cfactx_switch
152                struct __stack_context_t context;
153
154                // current execution status for coroutine
155                volatile int ticket;
156                enum __Coroutine_State state:8;
157                enum __Preemption_Reason preempted:8;
158
159                //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it
160
161                // pointer to the cluster on which the thread is running
162                struct cluster * curr_cluster;
163
164                // Link lists fields
165                // instrusive link field for threads
166                struct __thread_desc_link link;
167
168                // coroutine body used to store context
169                struct $coroutine  self_cor;
170
171                // current active context
172                struct $coroutine * curr_cor;
173
174                // monitor body used for mutual exclusion
175                struct $monitor    self_mon;
176
177                // pointer to monitor with sufficient lifetime for current monitors
178                struct $monitor *  self_mon_p;
179
180                // monitors currently held by this thread
181                struct __monitor_group_t monitors;
182
183                struct {
184                        struct $thread * next;
185                        struct $thread * prev;
186                } node;
187
188                #ifdef __CFA_DEBUG__
189                        // previous function to park/unpark the thread
190                        const char * park_caller;
191                        int park_result;
192                        enum __Coroutine_State park_state;
193                        bool park_stale;
194                        const char * unpark_caller;
195                        int unpark_result;
196                        enum __Coroutine_State unpark_state;
197                        bool unpark_stale;
198                #endif
199        };
200
201        #ifdef __CFA_DEBUG__
202                void __cfaabi_dbg_record_thrd($thread & this, bool park, const char prev_name[]);
203        #else
204                #define __cfaabi_dbg_record_thrd(x, y, z)
205        #endif
206
207        #ifdef __cforall
208        extern "Cforall" {
209
210                static inline $thread *& get_next( $thread & this ) __attribute__((const)) {
211                        return this.link.next;
212                }
213
214                static inline [$thread *&, $thread *& ] __get( $thread & this ) __attribute__((const)) {
215                        return this.node.[next, prev];
216                }
217
218                static inline void ?{}(__monitor_group_t & this) {
219                        (this.data){0p};
220                        (this.size){0};
221                        (this.func){NULL};
222                }
223
224                static inline void ?{}(__monitor_group_t & this, struct $monitor ** data, __lock_size_t size, fptr_t func) {
225                        (this.data){data};
226                        (this.size){size};
227                        (this.func){func};
228                }
229
230                static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) __attribute__((const)) {
231                        if( (lhs.data != 0) != (rhs.data != 0) ) return false;
232                        if( lhs.size != rhs.size ) return false;
233                        if( lhs.func != rhs.func ) return false;
234
235                        // Check that all the monitors match
236                        for( int i = 0; i < lhs.size; i++ ) {
237                                // If not a match, check next function
238                                if( lhs[i] != rhs[i] ) return false;
239                        }
240
241                        return true;
242                }
243
244                static inline void ?=?(__monitor_group_t & lhs, const __monitor_group_t & rhs) {
245                        lhs.data = rhs.data;
246                        lhs.size = rhs.size;
247                        lhs.func = rhs.func;
248                }
249        }
250        #endif
251
252#endif //_INVOKE_H_
253#else //! defined(__CFA_INVOKE_PRIVATE__)
254#ifndef _INVOKE_PRIVATE_H_
255#define _INVOKE_PRIVATE_H_
256
257        struct machine_context_t {
258                void *SP;
259                void *FP;
260                void *PC;
261        };
262
263        // assembler routines that performs the context switch
264        extern void __cfactx_invoke_stub( void );
265        extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
266        // void CtxStore ( void * this ) asm ("CtxStore");
267        // void CtxRet   ( void * dst  ) asm ("CtxRet");
268
269#endif //_INVOKE_PRIVATE_H_
270#endif //! defined(__CFA_INVOKE_PRIVATE__)
271#ifdef __cforall
272}
273#endif
274
275// Local Variables: //
276// mode: c //
277// tab-width: 4 //
278// End: //
Note: See TracBrowser for help on using the repository browser.