mirrored from https://gitlab.haskell.org/ghc/ghc.git
/
TSO.h
303 lines (249 loc) · 8.26 KB
/
TSO.h
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/* -----------------------------------------------------------------------------
* $Id: TSO.h,v 1.34 2004/03/01 14:18:35 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
* The definitions for Thread State Objects.
*
* ---------------------------------------------------------------------------*/
#ifndef TSO_H
#define TSO_H
#if defined(GRAN) || defined(PAR)
#if DEBUG
#define TSO_MAGIC 4321
#endif
typedef struct {
StgInt pri;
StgInt magic;
StgInt sparkname;
rtsTime startedat;
rtsBool exported;
StgInt basicblocks;
StgInt allocs;
rtsTime exectime;
rtsTime fetchtime;
rtsTime fetchcount;
rtsTime blocktime;
StgInt blockcount;
rtsTime blockedat;
StgInt globalsparks;
StgInt localsparks;
rtsTime clock;
} StgTSOStatBuf;
#endif
#if defined(PROFILING)
typedef struct {
CostCentreStack *CCCS; /* thread's current CCS */
} StgTSOProfInfo;
#else /* !PROFILING */
# if defined(SUPPORTS_EMPTY_STRUCTS)
typedef struct {
/* empty */
} StgTSOProfInfo;
# endif
#endif /* PROFILING */
#if defined(PAR)
typedef StgTSOStatBuf StgTSOParInfo;
#else /* !PAR */
# if defined(SUPPORTS_EMPTY_STRUCTS)
typedef struct {
/* empty */
} StgTSOParInfo;
# endif
#endif /* PAR */
#if defined(DIST)
typedef struct {
StgThreadPriority priority;
StgInt revalTid; /* ToDo: merge both into 1 word */
StgInt revalSlot;
} StgTSODistInfo;
#else /* !DIST */
# if defined(SUPPORTS_EMPTY_STRUCTS)
typedef struct {
/* empty */
} StgTSODistInfo;
# endif
#endif /* DIST */
#if defined(GRAN)
typedef StgTSOStatBuf StgTSOGranInfo;
#else /* !GRAN */
# if defined(SUPPORTS_EMPTY_STRUCTS)
typedef struct {
/* empty */
} StgTSOGranInfo;
# endif
#endif /* GRAN */
#if defined(TICKY)
typedef struct {
} StgTSOTickyInfo;
#else /* !TICKY_TICKY */
# if defined(SUPPORTS_EMPTY_STRUCTS)
typedef struct {
/* empty */
} StgTSOTickyInfo;
# endif
#endif /* TICKY_TICKY */
typedef enum {
tso_state_runnable,
tso_state_stopped
} StgTSOState;
/*
* The what_next field of a TSO indicates how the thread is to be run.
*/
typedef enum {
ThreadRunGHC, /* return to address on top of stack */
ThreadInterpret, /* interpret this thread */
ThreadKilled, /* thread has died, don't run it */
ThreadRelocated, /* thread has moved, link points to new locn */
ThreadComplete /* thread has finished */
} StgTSOWhatNext;
/*
* Thread IDs are 32 bits.
*/
typedef StgWord32 StgThreadID;
/*
* This type is returned to the scheduler by a thread that has
* stopped for one reason or another.
*/
typedef enum {
HeapOverflow, /* might also be StackOverflow */
StackOverflow,
ThreadYielding,
ThreadBlocked,
ThreadFinished
} StgThreadReturnCode;
/*
* We distinguish between the various classes of threads in the system.
*/
typedef enum {
AdvisoryPriority,
MandatoryPriority,
RevalPriority
} StgThreadPriority;
/*
* Threads may be blocked for several reasons. A blocked thread will
* have the reason in the why_blocked field of the TSO, and some
* further info (such as the closure the thread is blocked on, or the
* file descriptor if the thread is waiting on I/O) in the block_info
* field.
*/
typedef enum {
NotBlocked,
BlockedOnMVar,
BlockedOnBlackHole,
BlockedOnException,
BlockedOnRead,
BlockedOnWrite,
BlockedOnDelay
#if defined(mingw32_TARGET_OS)
, BlockedOnDoProc
#endif
#if defined(PAR)
, BlockedOnGA // blocked on a remote closure represented by a Global Address
, BlockedOnGA_NoSend // same as above but without sending a Fetch message
#endif
, BlockedOnCCall
, BlockedOnCCall_NoUnblockExc // same as above but don't unblock
// async exceptions in resumeThread()
} StgTSOBlockReason;
#if defined(mingw32_TARGET_OS)
/* results from an async I/O request + it's ID. */
typedef struct {
unsigned int reqID;
int len;
int errCode;
} StgAsyncIOResult;
#endif
typedef union {
StgClosure *closure;
struct StgTSO_ *tso;
int fd;
#if defined(mingw32_TARGET_OS)
StgAsyncIOResult* async_result;
#endif
unsigned int target;
} StgTSOBlockInfo;
/*
* TSOs live on the heap, and therefore look just like heap objects.
* Large TSOs will live in their own "block group" allocated by the
* storage manager, and won't be copied during garbage collection.
*/
/*
* ToDo: make this structure sensible on a non-32-bit arch.
*/
typedef struct StgTSO_ {
StgHeader header;
struct StgTSO_* link; /* Links threads onto blocking queues */
StgMutClosure * mut_link; /* TSO's are mutable of course! */
struct StgTSO_* global_link; /* Links all threads together */
StgTSOWhatNext what_next : 16;
StgTSOBlockReason why_blocked : 16;
StgTSOBlockInfo block_info;
struct StgTSO_* blocked_exceptions;
StgThreadID id;
int saved_errno;
struct StgMainThread_* main;
MAYBE_EMPTY_STRUCT(StgTSOTickyInfo,ticky)
MAYBE_EMPTY_STRUCT(StgTSOProfInfo,prof)
MAYBE_EMPTY_STRUCT(StgTSOParInfo,par)
MAYBE_EMPTY_STRUCT(StgTSOGranInfo,gran)
MAYBE_EMPTY_STRUCT(StgTSODistInfo,dist)
/* The thread stack... */
StgWord stack_size; /* stack size in *words* */
StgWord max_stack_size; /* maximum stack size in *words* */
StgPtr sp;
StgWord stack[FLEXIBLE_ARRAY];
} StgTSO;
/* -----------------------------------------------------------------------------
Invariants:
An active thread has the following properties:
tso->stack < tso->sp < tso->stack+tso->stack_size
tso->stack_size <= tso->max_stack_size
RESERVED_STACK_WORDS is large enough for any heap-check or
stack-check failure.
The size of the TSO struct plus the stack is either
(a) smaller than a block, or
(b) a multiple of BLOCK_SIZE
tso->why_blocked tso->block_info location
----------------------------------------------------------------------
NotBlocked NULL runnable_queue, or running
BlockedOnBlackHole the BLACKHOLE_BQ the BLACKHOLE_BQ's queue
BlockedOnMVar the MVAR the MVAR's queue
BlockedOnException the TSO TSO->blocked_exception
BlockedOnRead NULL blocked_queue
BlockedOnWrite NULL blocked_queue
BlockedOnDelay NULL blocked_queue
BlockedOnGA closure TSO blocks on BQ of that closure
BlockedOnGA_NoSend closure TSO blocks on BQ of that closure
tso->link == END_TSO_QUEUE, if the thread is currently running.
A zombie thread has the following properties:
tso->what_next == ThreadComplete or ThreadKilled
tso->link == (could be on some queue somewhere)
tso->su == tso->stack + tso->stack_size
tso->sp == tso->stack + tso->stack_size - 1 (i.e. top stack word)
tso->sp[0] == return value of thread, if what_next == ThreadComplete,
exception , if what_next == ThreadKilled
(tso->sp is left pointing at the top word on the stack so that
the return value or exception will be retained by a GC).
tso->blocked_exceptions is either:
NULL if async exceptions are unblocked.
END_TSO_QUEUE if async exceptions are blocked, but no threads
are currently waiting to deliver.
(StgTSO *)tso if threads are currently awaiting delivery of
exceptions to this thread.
The 2 cases BlockedOnGA and BlockedOnGA_NoSend are needed in a GUM
setup only. They mark a TSO that has entered a FETCH_ME or
FETCH_ME_BQ closure, respectively; only the first TSO hitting the
closure will send a Fetch message.
Currently we have no separate code for blocking on an RBH; we use the
BlockedOnBlackHole case for that. -- HWL
---------------------------------------------------------------------------- */
/* Workaround for a bug/quirk in gcc on certain architectures.
* symptom is that (&tso->stack - &tso->header) /= sizeof(StgTSO)
* in other words, gcc pads the structure at the end.
*/
extern StgTSO dummy_tso;
#define TSO_STRUCT_SIZE \
((char *)&dummy_tso.stack - (char *)&dummy_tso.header)
#define TSO_STRUCT_SIZEW (TSO_STRUCT_SIZE / sizeof(W_))
#endif /* TSO_H */