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