1 #ifndef SCHEME_FUTURES_H
2 #define SCHEME_FUTURES_H
3 
4 #ifdef MZ_USE_FUTURES
5 
6 typedef Scheme_Object* (*prim_obj_int_pobj_obj_t)(Scheme_Object*, int, Scheme_Object**);
7 typedef Scheme_Object* (*prim_int_pobj_obj_t)(int, Scheme_Object**);
8 typedef Scheme_Object* (*prim_int_pobj_obj_obj_t)(int, Scheme_Object**, Scheme_Object*);
9 typedef void* (*prim_pvoid_pvoid_pvoid_t)(void*, void*);
10 
11 /* PENDING is ready to run: */
12 #define PENDING 0
13 /* RUNNING is running in some thread: */
14 #define RUNNING 1
15 /* WAITING_FOR_PRIM is waiting for the runtime thread to start runnin
16    a primitive -- possibiliy atomic, possibly not, and possibly a LWC
17    capture happens while waiting: */
18 #define WAITING_FOR_PRIM 2
19 /* FINISHED means the result (or failure) is ready: */
20 #define FINISHED 3
21 /* PENDING is ready to run, but won't work in a future thread: */
22 #define PENDING_OVERSIZE 4
23 /* WAITING_FOR_PRIM is the runtime thread working on a primitive: */
24 #define HANDLING_PRIM 5
25 /* WAITING_FOR_FSEMA is in the queue of an fsemaphore: */
26 #define WAITING_FOR_FSEMA 6
27 /* SUSPENDED is the owning custodian is gone, so the future will never finish: */
28 #define SUSPENDED 7
29 /* WAITING_FOR_OVERFLOW is waiting for an LCW capture to continue
30    for a stack overflow: */
31 #define WAITING_FOR_OVERFLOW 8
32 
33 /* FSRC_OTHER means: descriptive string is provided for logging,
34    called function *DOES NOT NEED* to lookup continuation marks. */
35 #define FSRC_OTHER 0
36 /* FSRC_RATOR means: Racket function provided, so use it in logging,
37    called function can lookup continuation marks. */
38 #define FSRC_RATOR 1
39 /* FSRC_PRIM means: Racket primitive provided, so use it in logging,
40    called function can lookup continuation marks. */
41 #define FSRC_PRIM  2
42 /* FSRC_MARKS means: like FSRC_OTHER, but
43    called function may need to lookup continuation marks. */
44 #define FSRC_MARKS 3
45 
46 typedef struct Fevent {
47   double timestamp;
48   int what, fid, data;
49 } Fevent;
50 
51 typedef struct Fevent_Buffer {
52   Fevent *a;
53   int pos, overflow;
54   int i, count; /* used during flush */
55 } Fevent_Buffer;
56 
57 typedef struct Scheme_Future_Thread_State {
58   int is_runtime_thread;
59   mz_proc_thread *t;
60   int id;
61   int worker_gc_counter;
62   mzrt_sema *worker_can_continue_sema;
63   intptr_t runstack_size;
64 
65   /* After a future thread starts, only the runtime thread
66      modifies the values at these pointers. Future threads
67      read them without any locks; assembly-level instructions,
68      such as mfence, ensure that future threads eventually see
69      changes made by the runtime thread, and the runtime thread
70      waits as needed. */
71   volatile int *fuel_pointer;
72   volatile uintptr_t *stack_boundary_pointer;
73   volatile int *need_gc_pointer;
74 
75   Scheme_Thread *thread;
76 
77   uintptr_t gen0_start;
78   uintptr_t gen0_size;
79   uintptr_t gen0_initial_offset;
80 
81   int local_capture_failed;
82 
83   int use_fevents1;
84   Fevent_Buffer fevents1;
85   Fevent_Buffer fevents2;
86 } Scheme_Future_Thread_State;
87 
88 typedef struct future_t {
89   Scheme_Object so;
90 
91   int id;
92   int thread_short_id;
93 
94   int status;
95   /* The status field is the main locking mechanism. It
96      should only be read and written when holding a lock
97      (and all associated fields for a status should be
98      set at the same time). */
99 
100   mzrt_sema *can_continue_sema;
101   /* this semcpahore is non_NULL when a future thread is blocked
102      while trying to run the future; th want_lw flag may be set in
103      that case */
104 
105   Scheme_Object *orig_lambda;
106 
107   Scheme_Custodian *cust; /* an approximate custodian; don't use a future
108                              thread if this custodian is shut down */
109 
110   /* Runtime call stuff */
111 
112   char want_lw;
113   /* flag to indicate waiting for lw capture; if this flag is set,
114      then the future thread currently running the future must be
115      blocked, and the runtime thread must not already be working on
116      behalf of the future; since a future thread is blocked on this
117      future, then can_continue_sema is normally set, but the runtime
118      thread sets can_continue_sema to NULL while trying to capture the
119      continuation --- in case anoter thread tries to let the original
120      future thread continue because it was blocked on a touch for a
121      future that completed; the `want_lw' flag should be changed only
122      while holding a lock */
123 
124   char in_queue_waiting_for_lwc;
125   /* flag to indicate whether the future is in the "waiting for lwc"
126      queue; the future might be in the queue even if want_lw is set to
127      0, and so this flag just prevents  */
128 
129   char in_touch_queue;
130   /* like `in_queue_waiting_for_lwc' but for being in a `touch'
131      future */
132 
133   char in_future_specific_touch_queue; /* a back-door argument */
134 
135   char rt_prim_is_atomic;
136   /* when a future thread is blocked on this future, it sets
137      `rt_prim_is_atomic' if the blocking operation can run
138      in any thread atomically (i.e., it's a "synchronizing"
139      operation insteda of a general blocking operation) */
140 
141   char in_future_queue, in_atomic_queue;
142 
143   double time_of_request;
144   const char *source_of_request;
145   int source_type;
146 
147   uintptr_t alloc_retval;
148   uintptr_t alloc_sz_retval;
149   int alloc_retval_counter;
150 
151   void *prim_func;
152   int prim_protocol;
153   Scheme_Object *arg_s0;
154   const Scheme_Object *arg_t0;
155   Scheme_Object **arg_S0;
156   Scheme_Bucket *arg_b0;
157   int arg_i0;
158   intptr_t arg_l0;
159   size_t arg_z0;
160   Scheme_Native_Lambda *arg_n0;
161   Scheme_Object *arg_s1;
162   const Scheme_Object *arg_t1;
163   Scheme_Object **arg_S1;
164   int arg_i1;
165   intptr_t arg_l1;
166   Scheme_Object *arg_s2;
167   Scheme_Object **arg_S2;
168   int arg_i2;
169   void *arg_p2;
170 
171   const char *arg_str0;
172   const char *arg_str1;
173   int arg_i3;
174   Scheme_Object **arg_S4;
175 
176   Scheme_Thread *arg_p;
177   /* when a future thread is blocked while running this future,
178      `arg_p' s set along with the blocking-operation arguments to
179      indicate the future thread's (fake) Racket thread, which has the
180      runstack, etc. */
181   struct Scheme_Current_LWC *lwc;
182   /* when a future thread is blocked while running this future,
183      if `want_lw' is set, then `lwc' points to information for
184      capturing a lightweight continuation */
185   struct Scheme_Future_Thread_State *fts;
186   /* when a future thread is blocked while running this future,
187      `fts' is set to identify the future thread */
188 
189   struct Scheme_Lightweight_Continuation *suspended_lw;
190   /* holds a lightweight continuation captured for the operation,
191      if any */
192   int maybe_suspended_lw;
193   /* set to 1 with suspended_lw untl test in runtime thread; this
194      extra flag avoids spinning if the suspended continuation
195      cannot be resumed in the main thread for some reason */
196 
197   void **suspended_lw_stack; /* for overflow handling */
198 
199   Scheme_Object *retval_s;
200   void *retval_p; /* use only with conservative GC */
201   MZ_MARK_STACK_TYPE retval_m;
202   int retval_i;
203   signed char no_retval;
204   char retval_is_rs_plus_two; /* => special result handling for on-demand JIT */
205 
206   Scheme_Object **multiple_array;
207   int multiple_count;
208 
209   Scheme_Object *tail_rator;
210   Scheme_Object **tail_rands;
211   int num_tail_rands;
212 
213   Scheme_Object *retval;
214   struct future_t *prev;
215   struct future_t *next;
216 
217   struct future_t *next_waiting_atomic;
218   struct future_t *next_waiting_lwc;
219   struct future_t *next_waiting_touch;
220 
221   struct future_t *prev_in_fsema_queue;
222   struct future_t *next_in_fsema_queue;
223 
224   int in_tracing_mode;
225 
226   Scheme_Object *touching; /* a list of weak pointers to futures touching this one */
227 } future_t;
228 
229 typedef struct fsemaphore_t {
230   Scheme_Object so;
231 
232   int ready;
233   mzrt_mutex *mut;
234   future_t *queue_front;
235   future_t *queue_end;
236 } fsemaphore_t;
237 
238 /* Primitive instrumentation stuff */
239 
240 /* Signature flags for primitive invocations */
241 #define SIG_ON_DEMAND          1
242 #define SIG_ALLOC              2
243 #define SIG_ALLOC_MARK_SEGMENT 3
244 #define SIG_ALLOC_VALUES       4
245 #define SIG_ALLOC_STRUCT       5
246 #define SIG_ALLOC_VECTOR       6
247 #define SIG_MAKE_FSEMAPHORE    7
248 #define SIG_FUTURE             8
249 #define SIG_WRONG_TYPE_EXN     9
250 #define SIG_TAIL_APPLY         10
251 #define SIG_APPLY_AFRESH       11
252 
253 # include "jit_ts_protos.h"
254 
255 extern Scheme_Object *scheme_force_value_same_mark_as_lightweight_continuation(Scheme_Object *v);
256 
257 extern Scheme_Object **scheme_rtcall_on_demand(Scheme_Object **argv);
258 extern uintptr_t scheme_rtcall_alloc(void);
259 extern void scheme_rtcall_new_mark_segment(Scheme_Thread *p);
260 extern void scheme_rtcall_allocate_values(int count, Scheme_Thread *t);
261 extern Scheme_Structure *scheme_rtcall_allocate_structure(int argc, Scheme_Struct_Type *stype);
262 extern Scheme_Object *scheme_rtcall_allocate_vector(int count);
263 extern Scheme_Object *scheme_rtcall_make_fsemaphore(Scheme_Object *ready);
264 extern Scheme_Object *scheme_rtcall_make_future(Scheme_Object *proc);
265 extern Scheme_Object *scheme_rtcall_tail_apply(Scheme_Object *rator, int argc, Scheme_Object **argv);
266 extern Scheme_Object *scheme_rtcall_apply_with_new_stack(Scheme_Object *rator, int argc, Scheme_Object **argv, int multi);
267 
268 int scheme_can_apply_native_in_future(Scheme_Object *proc);
269 
270 void scheme_future_block_until_gc();
271 void scheme_future_continue_after_gc();
272 void scheme_check_future_work();
273 void scheme_future_gc_pause();
274 void scheme_future_check_custodians();
275 int scheme_future_is_runtime_thread();
276 
277 #endif /* MZ_USE_FUTURES */
278 
279 /* always defined: */
280 Scheme_Object *scheme_future(int argc, Scheme_Object *argv[]);
281 Scheme_Object *scheme_current_future(int argc, Scheme_Object *argv[]);
282 Scheme_Object *scheme_fsemaphore_p(int argc, Scheme_Object *argv[]);
283 
284 Scheme_Object *scheme_fsemaphore_count(int argc, Scheme_Object *argv[]);
285 Scheme_Object *scheme_make_fsemaphore(int argc, Scheme_Object *argv[]);
286 Scheme_Object *scheme_make_fsemaphore_inl(Scheme_Object *ready);
287 Scheme_Object *scheme_fsemaphore_wait(int argc, Scheme_Object *argv[]);
288 Scheme_Object *scheme_fsemaphore_post(int argc, Scheme_Object *argv[]);
289 Scheme_Object *scheme_fsemaphore_try_wait(int argc, Scheme_Object *argv[]);
290 
291 Scheme_Object *scheme_box_cas(int argc, Scheme_Object *argv[]);
292 
293 #endif
294