TSO.h 12.2 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2
 *
Simon Marlow's avatar
Simon Marlow committed
3
 * (c) The GHC Team, 1998-2009
4
5
6
7
8
 *
 * The definitions for Thread State Objects.
 *
 * ---------------------------------------------------------------------------*/

9
#pragma once
10

11
12
#include "rts/storage/Closures.h"

13
14
15
/*
 * PROFILING info in a TSO
 */
16
typedef struct {
17
  CostCentreStack *cccs;       /* thread's current CCS */
18
19
} StgTSOProfInfo;

20
/*
21
 * There is no TICKY info in a TSO at this time.
22
 */
23
24

/*
25
 * Thread IDs are 64 bits.
26
 */
27
typedef StgWord64 StgThreadID;
28

29
30
#define FMT_StgThreadID FMT_Word64

31
#define tsoLocked(tso) ((tso)->flags & TSO_LOCKED)
32

33
/*
34
35
36
 * Type returned after running a thread.  Values of this type
 * include HeapOverflow, StackOverflow etc.  See Constants.h for the
 * full list.
37
 */
38
typedef unsigned int StgThreadReturnCode;
39

40
#if defined(mingw32_HOST_OS)
sof's avatar
sof committed
41
/* results from an async I/O request + its request ID. */
sof's avatar
sof committed
42
43
44
45
46
47
48
typedef struct {
  unsigned int reqID;
  int          len;
  int          errCode;
} StgAsyncIOResult;
#endif

49
/* Reason for thread being blocked. See comment above struct StgTso_. */
50
51
typedef union {
  StgClosure *closure;
52
  StgTSO *prev; // a back-link when the TSO is on the run queue (NotBlocked)
53
  struct MessageBlackHole_ *bh;
54
55
  struct MessageThrowTo_ *throwto;
  struct MessageWakeup_  *wakeup;
56
  StgInt fd;    /* StgInt instead of int, so that it's the same size as the ptrs */
57
#if defined(mingw32_HOST_OS)
sof's avatar
sof committed
58
  StgAsyncIOResult *async_result;
sof's avatar
sof committed
59
#endif
Simon Marlow's avatar
Simon Marlow committed
60
#if !defined(THREADED_RTS)
61
  StgWord target;
Simon Marlow's avatar
Simon Marlow committed
62
    // Only for the non-threaded RTS: the target time for a thread
63
    // blocked in threadDelay, in units of 1ms.  This is a
Simon Marlow's avatar
Simon Marlow committed
64
65
66
    // compromise: we don't want to take up much space in the TSO.  If
    // you want better resolution for threadDelay, use -threaded.
#endif
67
68
} StgTSOBlockInfo;

69

70
71
72
73
74
75
/*
 * 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.
 */

76
/*
77
78
79
80
81
82
83
 * 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.
 */

84
typedef struct StgTSO_ {
85
86
    StgHeader               header;

87
88
89
90
91
    /* The link field, for linking threads together in lists (e.g. the
       run queue on a Capability.
    */
    struct StgTSO_*         _link;
    /*
92
93
94
      Currently used for linking TSOs on:
      * cap->run_queue_{hd,tl}
      * (non-THREADED_RTS); the blocked_queue
95
      * and pointing to the next chunk for a ThreadOldStack
96

97
98
99
100
101
102
103
104
105
       NOTE!!!  do not modify _link directly, it is subject to
       a write barrier for generational GC.  Instead use the
       setTSOLink() function.  Exceptions to this rule are:

       * setting the link field to END_TSO_QUEUE
       * setting the link field of the currently running TSO, as it
         will already be dirty.
    */

106
107
    struct StgTSO_*         global_link;    // Links threads on the
                                            // generation->threads lists
108

109
110
111
112
113
    /*
     * The thread's stack
     */
    struct StgStack_       *stackobj;

114
115
116
117
118
119
120
121
122
123
124
125
126
127
    /*
     * The tso->dirty flag indicates that this TSO's stack should be
     * scanned during garbage collection.  It also indicates that this
     * TSO is on the mutable list.
     *
     * NB. The dirty flag gets a word to itself, so that it can be set
     * safely by multiple threads simultaneously (the flags field is
     * not safe for this purpose; see #3429).  It is harmless for the
     * TSO to be on the mutable list multiple times.
     *
     * tso->dirty is set by dirty_TSO(), and unset by the garbage
     * collector (only).
     */

128
129
130
    StgWord16               what_next;      // Values defined in Constants.h
    StgWord16               why_blocked;    // Values defined in Constants.h
    StgWord32               flags;          // Values defined in Constants.h
131
132
    StgTSOBlockInfo         block_info;
    StgThreadID             id;
133
134
    StgWord32               saved_errno;
    StgWord32               dirty;          /* non-zero => dirty */
135
    struct InCall_*         bound;
136
    struct Capability_*     cap;
137

Ben Gamari's avatar
Ben Gamari committed
138
139
    struct StgTRecHeader_ * trec;           /* STM transaction record */
    StgArrBytes*            label;          /* Thread label */
140

141
    /*
142
     * A list of threads blocked on this TSO waiting to throw exceptions.
143
    */
144
    struct MessageThrowTo_ * blocked_exceptions;
145

146
    /*
147
148
     * A list of StgBlockingQueue objects, representing threads
     * blocked on thunks that are under evaluation by this thread.
149
150
151
    */
    struct StgBlockingQueue_ *bq;

152
153
154
155
156
157
158
159
160
161
    /*
     * The allocation limit for this thread, which is updated as the
     * thread allocates.  If the value drops below zero, and
     * TSO_ALLOC_LIMIT is set in flags, we raise an exception in the
     * thread, and give the thread a little more space to handle the
     * exception before we raise the exception again.
     *
     * This is an integer, because we might update it in a place where
     * it isn't convenient to raise the exception, so we want it to
     * stay negative until we get around to checking it.
162
163
     *
     * Use only PK_Int64/ASSIGN_Int64 macros to get/set the value of alloc_limit
Ben Gamari's avatar
Ben Gamari committed
164
     * in C code otherwise you will cause alignment issues
165
166
     */
    StgInt64  alloc_limit;     /* in bytes */
167

168
169
170
171
172
173
174
175
176
177
178
179
180
    /*
     * sum of the sizes of all stack chunks (in words), used to decide
     * whether to throw the StackOverflow exception when the stack
     * overflows, or whether to just chain on another stack chunk.
     *
     * Note that this overestimates the real stack size, because each
     * chunk will have a gap at the end, of +RTS -kb<size> words.
     * This means stack overflows are not entirely accurate, because
     * the more gaps there are, the sooner the stack will run into the
     * hard +RTS -K<size> limit.
     */
    StgWord32  tot_stack_size;

Ben Gamari's avatar
Ben Gamari committed
181
#if defined(TICKY_TICKY)
182
183
    /* TICKY-specific stuff would go here. */
#endif
Ben Gamari's avatar
Ben Gamari committed
184
#if defined(PROFILING)
185
186
    StgTSOProfInfo prof;
#endif
Ben Gamari's avatar
Ben Gamari committed
187
#if defined(mingw32_HOST_OS)
188
189
190
    StgWord32 saved_winerror;
#endif

191
} *StgTSOPtr; // StgTSO defined in rts/Types.h
192

193
194
/* Note [StgStack dirtiness flags and concurrent marking]
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ben Gamari's avatar
Ben Gamari committed
195
196
197
 * Without concurrent collection by the nonmoving collector the stack dirtiness
 * story is quite simple: The stack is either STACK_DIRTY (meaning it has been
 * added to mut_list) or not.
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
 *
 * However, things are considerably more complicated with concurrent collection
 * (namely, when nonmoving_write_barrier_enabled is set): In addition to adding
 * the stack to mut_list and flagging it as STACK_DIRTY, we also must ensure
 * that stacks are marked in accordance with the nonmoving collector's snapshot
 * invariant. This is: every stack alive at the time the snapshot is taken must
 * be marked at some point after the moment the snapshot is taken and before it
 * is mutated or the commencement of the sweep phase.
 *
 * This marking may be done by the concurrent mark phase (in the case of a
 * thread that never runs during the concurrent mark) or by the mutator when
 * dirtying the stack. However, it is unsafe for the concurrent collector to
 * traverse the stack while it is under mutation. Consequently, the following
 * handshake is obeyed by the mutator's write barrier and the concurrent mark to
 * ensure this doesn't happen:
 *
 * 1. The entity seeking to mark first checks that the stack lives in the nonmoving
 *    generation; if not then the stack was not alive at the time the snapshot
 *    was taken and therefore we need not mark it.
 *
 * 2. The entity seeking to mark checks the stack's mark bit. If it is set then
 *    no mark is necessary.
 *
 * 3. The entity seeking to mark tries to lock the stack for marking by
 *    atomically setting its `marking` field to the current non-moving mark
 *    epoch:
 *
 *    a. If the mutator finds the concurrent collector has already locked the
 *       stack then it waits until it is finished (indicated by the mark bit
 *       being set) before proceeding with execution.
 *
 *    b. If the concurrent collector finds that the mutator has locked the stack
 *       then it moves on, leaving the mutator to mark it. There is no need to wait;
 *       the mark is guaranteed to finish before sweep due to the post-mark
 *       synchronization with mutators.
 *
 *    c. Whoever succeeds in locking the stack is responsible for marking it and
 *       setting the stack's mark bit (either the BF_MARKED bit for large objects
 *       or otherwise its bit in its segment's mark bitmap).
 *
Ben Gamari's avatar
Ben Gamari committed
238
239
240
 * To ensure that mutation does not proceed until the stack is fully marked the
 * mark phase must not set the mark bit until it has finished tracing.
 *
241
 */
242
243
244
245
246

#define STACK_DIRTY 1
// used by sanity checker to verify that all dirty stacks are on the mutable list
#define STACK_SANE 64

247
248
typedef struct StgStack_ {
    StgHeader  header;
249
250
251
252
253
254
255

    /* Size of the `stack` field in *words*. This is not affected by how much of
     * the stack space is used, nor if more stack space is linked to by an
     * UNDERFLOW_FRAME.
     */
    StgWord32  stack_size;

256
257
    StgWord8   dirty;          // non-zero => dirty
    StgWord8   marking;        // non-zero => someone is currently marking the stack
258
259
260
261
262
263
264

    /* Pointer to the "top" of the stack i.e. the most recently written address.
     * The stack is filled downwards, so the "top" of the stack starts with `sp
     * = stack + stack_size` and is decremented as the stack fills with data.
     * See comment on "Invariants" below.
     */
    StgPtr     sp;
ase's avatar
ase committed
265

266
    StgWord    stack[];
267
268
269
270
271
272
273
274
275
} StgStack;

// Calculate SpLim from a TSO (reads tso->stackobj, but no fields from
// the stackobj itself).
INLINE_HEADER StgPtr tso_SpLim (StgTSO* tso)
{
    return tso->stackobj->stack + RESERVED_STACK_WORDS;
}

276
277
278
279
/* -----------------------------------------------------------------------------
   functions
   -------------------------------------------------------------------------- */

Simon Marlow's avatar
Simon Marlow committed
280
281
void dirty_TSO  (Capability *cap, StgTSO *tso);
void setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target);
282
void setTSOPrev (Capability *cap, StgTSO *tso, StgTSO *target);
283

284
void dirty_STACK (Capability *cap, StgStack *stack);
285

286
287
288
289
290
291
292
/* -----------------------------------------------------------------------------
   Invariants:

   An active thread has the following properties:

      tso->stack < tso->sp < tso->stack+tso->stack_size
      tso->stack_size <= tso->max_stack_size
293

294
295
296
297
298
      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
299
        (b) a multiple of BLOCK_SIZE
300

301
        tso->why_blocked       tso->block_info      location
302
        ----------------------------------------------------------------------
303
304
        NotBlocked             END_TSO_QUEUE        runnable_queue, or running

305
        BlockedOnBlackHole     MessageBlackHole *   TSO->bq
306

307
        BlockedOnMVar          the MVAR             the MVAR's queue
308

Ben Gamari's avatar
Ben Gamari committed
309
310
        BlockedOnSTM           END_TSO_QUEUE        STM wait queue(s)
        BlockedOnSTM           STM_AWOKEN           run queue
311

312
        BlockedOnMsgThrowTo    MessageThrowTo *     TSO->blocked_exception
313
314

        BlockedOnRead          NULL                 blocked_queue
315
        BlockedOnWrite         NULL                 blocked_queue
316
317
318
        BlockedOnDelay         NULL                 blocked_queue

      tso->link == END_TSO_QUEUE, if the thread is currently running.
319
320

   A zombie thread has the following properties:
321

322
      tso->what_next == ThreadComplete or ThreadKilled
323
324
      tso->link     ==  (could be on some queue somewhere)
      tso->sp       ==  tso->stack + tso->stack_size - 1 (i.e. top stack word)
325
326
      tso->sp[0]    ==  return value of thread, if what_next == ThreadComplete,
                        exception             , if what_next == ThreadKilled
327
328
329
330

      (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).

331
 ---------------------------------------------------------------------------- */
332

333
/* this is the NIL ptr for a TSO queue (e.g. runnable queue) */
334
#define END_TSO_QUEUE  ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure)