| 1 | /* ----------------------------------------------------------------------------- |
|---|
| 2 | * |
|---|
| 3 | * (c) The GHC Team, 1998-2009 |
|---|
| 4 | * |
|---|
| 5 | * The definitions for Thread State Objects. |
|---|
| 6 | * |
|---|
| 7 | * ---------------------------------------------------------------------------*/ |
|---|
| 8 | |
|---|
| 9 | #ifndef RTS_STORAGE_TSO_H |
|---|
| 10 | #define RTS_STORAGE_TSO_H |
|---|
| 11 | |
|---|
| 12 | /* |
|---|
| 13 | * PROFILING info in a TSO |
|---|
| 14 | */ |
|---|
| 15 | typedef struct { |
|---|
| 16 | CostCentreStack *cccs; /* thread's current CCS */ |
|---|
| 17 | } StgTSOProfInfo; |
|---|
| 18 | |
|---|
| 19 | /* |
|---|
| 20 | * There is no TICKY info in a TSO at this time. |
|---|
| 21 | */ |
|---|
| 22 | |
|---|
| 23 | /* |
|---|
| 24 | * Thread IDs are 32 bits. |
|---|
| 25 | */ |
|---|
| 26 | typedef StgWord32 StgThreadID; |
|---|
| 27 | |
|---|
| 28 | #define tsoLocked(tso) ((tso)->flags & TSO_LOCKED) |
|---|
| 29 | |
|---|
| 30 | /* |
|---|
| 31 | * Type returned after running a thread. Values of this type |
|---|
| 32 | * include HeapOverflow, StackOverflow etc. See Constants.h for the |
|---|
| 33 | * full list. |
|---|
| 34 | */ |
|---|
| 35 | typedef unsigned int StgThreadReturnCode; |
|---|
| 36 | |
|---|
| 37 | #if defined(mingw32_HOST_OS) |
|---|
| 38 | /* results from an async I/O request + its request ID. */ |
|---|
| 39 | typedef struct { |
|---|
| 40 | unsigned int reqID; |
|---|
| 41 | int len; |
|---|
| 42 | int errCode; |
|---|
| 43 | } StgAsyncIOResult; |
|---|
| 44 | #endif |
|---|
| 45 | |
|---|
| 46 | /* Reason for thread being blocked. See comment above struct StgTso_. */ |
|---|
| 47 | typedef union { |
|---|
| 48 | StgClosure *closure; |
|---|
| 49 | StgTSO *prev; // a back-link when the TSO is on the run queue (NotBlocked) |
|---|
| 50 | struct MessageBlackHole_ *bh; |
|---|
| 51 | struct MessageThrowTo_ *throwto; |
|---|
| 52 | struct MessageWakeup_ *wakeup; |
|---|
| 53 | StgInt fd; /* StgInt instead of int, so that it's the same size as the ptrs */ |
|---|
| 54 | #if defined(mingw32_HOST_OS) |
|---|
| 55 | StgAsyncIOResult *async_result; |
|---|
| 56 | #endif |
|---|
| 57 | #if !defined(THREADED_RTS) |
|---|
| 58 | StgWord target; |
|---|
| 59 | // Only for the non-threaded RTS: the target time for a thread |
|---|
| 60 | // blocked in threadDelay, in units of 1ms. This is a |
|---|
| 61 | // compromise: we don't want to take up much space in the TSO. If |
|---|
| 62 | // you want better resolution for threadDelay, use -threaded. |
|---|
| 63 | #endif |
|---|
| 64 | } StgTSOBlockInfo; |
|---|
| 65 | |
|---|
| 66 | |
|---|
| 67 | /* |
|---|
| 68 | * TSOs live on the heap, and therefore look just like heap objects. |
|---|
| 69 | * Large TSOs will live in their own "block group" allocated by the |
|---|
| 70 | * storage manager, and won't be copied during garbage collection. |
|---|
| 71 | */ |
|---|
| 72 | |
|---|
| 73 | /* |
|---|
| 74 | * Threads may be blocked for several reasons. A blocked thread will |
|---|
| 75 | * have the reason in the why_blocked field of the TSO, and some |
|---|
| 76 | * further info (such as the closure the thread is blocked on, or the |
|---|
| 77 | * file descriptor if the thread is waiting on I/O) in the block_info |
|---|
| 78 | * field. |
|---|
| 79 | */ |
|---|
| 80 | |
|---|
| 81 | typedef struct StgTSO_ { |
|---|
| 82 | StgHeader header; |
|---|
| 83 | |
|---|
| 84 | /* The link field, for linking threads together in lists (e.g. the |
|---|
| 85 | run queue on a Capability. |
|---|
| 86 | */ |
|---|
| 87 | struct StgTSO_* _link; |
|---|
| 88 | /* |
|---|
| 89 | Currently used for linking TSOs on: |
|---|
| 90 | * cap->run_queue_{hd,tl} |
|---|
| 91 | * (non-THREADED_RTS); the blocked_queue |
|---|
| 92 | * and pointing to the next chunk for a ThreadOldStack |
|---|
| 93 | |
|---|
| 94 | NOTE!!! do not modify _link directly, it is subject to |
|---|
| 95 | a write barrier for generational GC. Instead use the |
|---|
| 96 | setTSOLink() function. Exceptions to this rule are: |
|---|
| 97 | |
|---|
| 98 | * setting the link field to END_TSO_QUEUE |
|---|
| 99 | * setting the link field of the currently running TSO, as it |
|---|
| 100 | will already be dirty. |
|---|
| 101 | */ |
|---|
| 102 | |
|---|
| 103 | struct StgTSO_* global_link; // Links threads on the |
|---|
| 104 | // generation->threads lists |
|---|
| 105 | |
|---|
| 106 | /* |
|---|
| 107 | * The thread's stack |
|---|
| 108 | */ |
|---|
| 109 | struct StgStack_ *stackobj; |
|---|
| 110 | |
|---|
| 111 | /* |
|---|
| 112 | * The tso->dirty flag indicates that this TSO's stack should be |
|---|
| 113 | * scanned during garbage collection. It also indicates that this |
|---|
| 114 | * TSO is on the mutable list. |
|---|
| 115 | * |
|---|
| 116 | * NB. The dirty flag gets a word to itself, so that it can be set |
|---|
| 117 | * safely by multiple threads simultaneously (the flags field is |
|---|
| 118 | * not safe for this purpose; see #3429). It is harmless for the |
|---|
| 119 | * TSO to be on the mutable list multiple times. |
|---|
| 120 | * |
|---|
| 121 | * tso->dirty is set by dirty_TSO(), and unset by the garbage |
|---|
| 122 | * collector (only). |
|---|
| 123 | */ |
|---|
| 124 | |
|---|
| 125 | StgWord16 what_next; // Values defined in Constants.h |
|---|
| 126 | StgWord16 why_blocked; // Values defined in Constants.h |
|---|
| 127 | StgWord32 flags; // Values defined in Constants.h |
|---|
| 128 | StgTSOBlockInfo block_info; |
|---|
| 129 | StgThreadID id; |
|---|
| 130 | StgWord32 saved_errno; |
|---|
| 131 | StgWord32 dirty; /* non-zero => dirty */ |
|---|
| 132 | struct InCall_* bound; |
|---|
| 133 | struct Capability_* cap; |
|---|
| 134 | |
|---|
| 135 | struct StgTRecHeader_ * trec; /* STM transaction record */ |
|---|
| 136 | |
|---|
| 137 | /* |
|---|
| 138 | * A list of threads blocked on this TSO waiting to throw exceptions. |
|---|
| 139 | */ |
|---|
| 140 | struct MessageThrowTo_ * blocked_exceptions; |
|---|
| 141 | |
|---|
| 142 | /* |
|---|
| 143 | * A list of StgBlockingQueue objects, representing threads |
|---|
| 144 | * blocked on thunks that are under evaluation by this thread. |
|---|
| 145 | */ |
|---|
| 146 | struct StgBlockingQueue_ *bq; |
|---|
| 147 | |
|---|
| 148 | #ifdef TICKY_TICKY |
|---|
| 149 | /* TICKY-specific stuff would go here. */ |
|---|
| 150 | #endif |
|---|
| 151 | #ifdef PROFILING |
|---|
| 152 | StgTSOProfInfo prof; |
|---|
| 153 | #endif |
|---|
| 154 | #ifdef mingw32_HOST_OS |
|---|
| 155 | StgWord32 saved_winerror; |
|---|
| 156 | #endif |
|---|
| 157 | |
|---|
| 158 | /* |
|---|
| 159 | * sum of the sizes of all stack chunks (in words), used to decide |
|---|
| 160 | * whether to throw the StackOverflow exception when the stack |
|---|
| 161 | * overflows, or whether to just chain on another stack chunk. |
|---|
| 162 | * |
|---|
| 163 | * Note that this overestimates the real stack size, because each |
|---|
| 164 | * chunk will have a gap at the end, of +RTS -kb<size> words. |
|---|
| 165 | * This means stack overflows are not entirely accurate, because |
|---|
| 166 | * the more gaps there are, the sooner the stack will run into the |
|---|
| 167 | * hard +RTS -K<size> limit. |
|---|
| 168 | */ |
|---|
| 169 | StgWord32 tot_stack_size; |
|---|
| 170 | |
|---|
| 171 | } *StgTSOPtr; |
|---|
| 172 | |
|---|
| 173 | typedef struct StgStack_ { |
|---|
| 174 | StgHeader header; |
|---|
| 175 | StgWord32 stack_size; // stack size in *words* |
|---|
| 176 | StgWord32 dirty; // non-zero => dirty |
|---|
| 177 | StgPtr sp; // current stack pointer |
|---|
| 178 | StgWord stack[FLEXIBLE_ARRAY]; |
|---|
| 179 | } StgStack; |
|---|
| 180 | |
|---|
| 181 | // Calculate SpLim from a TSO (reads tso->stackobj, but no fields from |
|---|
| 182 | // the stackobj itself). |
|---|
| 183 | INLINE_HEADER StgPtr tso_SpLim (StgTSO* tso) |
|---|
| 184 | { |
|---|
| 185 | return tso->stackobj->stack + RESERVED_STACK_WORDS; |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | /* ----------------------------------------------------------------------------- |
|---|
| 189 | functions |
|---|
| 190 | -------------------------------------------------------------------------- */ |
|---|
| 191 | |
|---|
| 192 | void dirty_TSO (Capability *cap, StgTSO *tso); |
|---|
| 193 | void setTSOLink (Capability *cap, StgTSO *tso, StgTSO *target); |
|---|
| 194 | void setTSOPrev (Capability *cap, StgTSO *tso, StgTSO *target); |
|---|
| 195 | |
|---|
| 196 | void dirty_STACK (Capability *cap, StgStack *stack); |
|---|
| 197 | |
|---|
| 198 | /* ----------------------------------------------------------------------------- |
|---|
| 199 | Invariants: |
|---|
| 200 | |
|---|
| 201 | An active thread has the following properties: |
|---|
| 202 | |
|---|
| 203 | tso->stack < tso->sp < tso->stack+tso->stack_size |
|---|
| 204 | tso->stack_size <= tso->max_stack_size |
|---|
| 205 | |
|---|
| 206 | RESERVED_STACK_WORDS is large enough for any heap-check or |
|---|
| 207 | stack-check failure. |
|---|
| 208 | |
|---|
| 209 | The size of the TSO struct plus the stack is either |
|---|
| 210 | (a) smaller than a block, or |
|---|
| 211 | (b) a multiple of BLOCK_SIZE |
|---|
| 212 | |
|---|
| 213 | tso->why_blocked tso->block_info location |
|---|
| 214 | ---------------------------------------------------------------------- |
|---|
| 215 | NotBlocked END_TSO_QUEUE runnable_queue, or running |
|---|
| 216 | |
|---|
| 217 | BlockedOnBlackHole the BLACKHOLE blackhole_queue |
|---|
| 218 | |
|---|
| 219 | BlockedOnMVar the MVAR the MVAR's queue |
|---|
| 220 | |
|---|
| 221 | BlockedOnSTM END_TSO_QUEUE STM wait queue(s) |
|---|
| 222 | |
|---|
| 223 | BlockedOnMsgThrowTo MessageThrowTo * TSO->blocked_exception |
|---|
| 224 | |
|---|
| 225 | BlockedOnRead NULL blocked_queue |
|---|
| 226 | BlockedOnWrite NULL blocked_queue |
|---|
| 227 | BlockedOnDelay NULL blocked_queue |
|---|
| 228 | BlockedOnGA closure TSO blocks on BQ of that closure |
|---|
| 229 | BlockedOnGA_NoSend closure TSO blocks on BQ of that closure |
|---|
| 230 | |
|---|
| 231 | tso->link == END_TSO_QUEUE, if the thread is currently running. |
|---|
| 232 | |
|---|
| 233 | A zombie thread has the following properties: |
|---|
| 234 | |
|---|
| 235 | tso->what_next == ThreadComplete or ThreadKilled |
|---|
| 236 | tso->link == (could be on some queue somewhere) |
|---|
| 237 | tso->sp == tso->stack + tso->stack_size - 1 (i.e. top stack word) |
|---|
| 238 | tso->sp[0] == return value of thread, if what_next == ThreadComplete, |
|---|
| 239 | exception , if what_next == ThreadKilled |
|---|
| 240 | |
|---|
| 241 | (tso->sp is left pointing at the top word on the stack so that |
|---|
| 242 | the return value or exception will be retained by a GC). |
|---|
| 243 | |
|---|
| 244 | The 2 cases BlockedOnGA and BlockedOnGA_NoSend are needed in a GUM |
|---|
| 245 | setup only. They mark a TSO that has entered a FETCH_ME or |
|---|
| 246 | FETCH_ME_BQ closure, respectively; only the first TSO hitting the |
|---|
| 247 | closure will send a Fetch message. |
|---|
| 248 | Currently we have no separate code for blocking on an RBH; we use the |
|---|
| 249 | BlockedOnBlackHole case for that. -- HWL |
|---|
| 250 | |
|---|
| 251 | ---------------------------------------------------------------------------- */ |
|---|
| 252 | |
|---|
| 253 | /* this is the NIL ptr for a TSO queue (e.g. runnable queue) */ |
|---|
| 254 | #define END_TSO_QUEUE ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure) |
|---|
| 255 | |
|---|
| 256 | #endif /* RTS_STORAGE_TSO_H */ |
|---|