| 1 | /* ----------------------------------------------------------------------------- |
|---|
| 2 | * |
|---|
| 3 | * (c) The GHC Team, 1998-2012 |
|---|
| 4 | * |
|---|
| 5 | * Code for starting, stopping and restarting threads. |
|---|
| 6 | * |
|---|
| 7 | * This file is written in a subset of C--, extended with various |
|---|
| 8 | * features specific to GHC. It is compiled by GHC directly. For the |
|---|
| 9 | * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y. |
|---|
| 10 | * |
|---|
| 11 | * ---------------------------------------------------------------------------*/ |
|---|
| 12 | |
|---|
| 13 | #include "Cmm.h" |
|---|
| 14 | |
|---|
| 15 | /* |
|---|
| 16 | * This module contains the two entry points and the final exit point |
|---|
| 17 | * to/from the Haskell world. We can enter either by: |
|---|
| 18 | * |
|---|
| 19 | * a) returning to the address on the top of the stack, or |
|---|
| 20 | * b) entering the closure on the top of the stack |
|---|
| 21 | * |
|---|
| 22 | * the function stg_stop_thread_entry is the final exit for a |
|---|
| 23 | * thread: it is the last return address on the stack. It returns |
|---|
| 24 | * to the scheduler marking the thread as finished. |
|---|
| 25 | */ |
|---|
| 26 | |
|---|
| 27 | #define CHECK_SENSIBLE_REGS() \ |
|---|
| 28 | ASSERT(Hp != 0); \ |
|---|
| 29 | ASSERT(Sp != 0); \ |
|---|
| 30 | ASSERT(SpLim != 0); \ |
|---|
| 31 | ASSERT(SpLim - WDS(RESERVED_STACK_WORDS) <= Sp); |
|---|
| 32 | |
|---|
| 33 | /* ----------------------------------------------------------------------------- |
|---|
| 34 | Returning from the STG world. |
|---|
| 35 | -------------------------------------------------------------------------- */ |
|---|
| 36 | |
|---|
| 37 | INFO_TABLE_RET(stg_stop_thread, STOP_FRAME, |
|---|
| 38 | #if defined(PROFILING) |
|---|
| 39 | W_ unused, |
|---|
| 40 | W_ unused |
|---|
| 41 | #endif |
|---|
| 42 | ) |
|---|
| 43 | { |
|---|
| 44 | /* |
|---|
| 45 | The final exit. |
|---|
| 46 | |
|---|
| 47 | The top-top-level closures (e.g., "main") are of type "IO a". |
|---|
| 48 | When entered, they perform an IO action and return an 'a' in R1. |
|---|
| 49 | |
|---|
| 50 | We save R1 on top of the stack where the scheduler can find it, |
|---|
| 51 | tidy up the registers and return to the scheduler. |
|---|
| 52 | |
|---|
| 53 | We Leave the stack looking like this: |
|---|
| 54 | |
|---|
| 55 | +----------------+ |
|---|
| 56 | | -------------------> return value |
|---|
| 57 | +----------------+ |
|---|
| 58 | | stg_enter_info | |
|---|
| 59 | +----------------+ |
|---|
| 60 | |
|---|
| 61 | The stg_enter_info is just a dummy info table so that the |
|---|
| 62 | garbage collector can understand the stack (there must always |
|---|
| 63 | be an info table on top of the stack). |
|---|
| 64 | */ |
|---|
| 65 | |
|---|
| 66 | Sp = Sp + SIZEOF_StgStopFrame - WDS(2); |
|---|
| 67 | Sp(1) = R1; |
|---|
| 68 | Sp(0) = stg_enter_info; |
|---|
| 69 | |
|---|
| 70 | StgTSO_what_next(CurrentTSO) = ThreadComplete::I16; |
|---|
| 71 | |
|---|
| 72 | SAVE_THREAD_STATE(); |
|---|
| 73 | |
|---|
| 74 | /* The return code goes in BaseReg->rRet, and BaseReg is returned in R1 */ |
|---|
| 75 | StgRegTable_rRet(BaseReg) = ThreadFinished; |
|---|
| 76 | R1 = BaseReg; |
|---|
| 77 | |
|---|
| 78 | jump StgReturn; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | /* ----------------------------------------------------------------------------- |
|---|
| 82 | Start a thread from the scheduler by returning to the address on |
|---|
| 83 | the top of the stack. This is used for all entries to STG code |
|---|
| 84 | from C land. |
|---|
| 85 | |
|---|
| 86 | On the way back, we (usually) pass through stg_returnToSched which saves |
|---|
| 87 | the thread's state away nicely. |
|---|
| 88 | -------------------------------------------------------------------------- */ |
|---|
| 89 | |
|---|
| 90 | stg_returnToStackTop |
|---|
| 91 | { |
|---|
| 92 | LOAD_THREAD_STATE(); |
|---|
| 93 | CHECK_SENSIBLE_REGS(); |
|---|
| 94 | jump %ENTRY_CODE(Sp(0)); |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | stg_returnToSched |
|---|
| 98 | { |
|---|
| 99 | SAVE_THREAD_STATE(); |
|---|
| 100 | foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO); |
|---|
| 101 | jump StgReturn; |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | // A variant of stg_returnToSched that doesn't call threadPaused() on the |
|---|
| 105 | // current thread. This is used for switching from compiled execution to the |
|---|
| 106 | // interpreter, where calling threadPaused() on every switch would be too |
|---|
| 107 | // expensive. |
|---|
| 108 | stg_returnToSchedNotPaused |
|---|
| 109 | { |
|---|
| 110 | SAVE_THREAD_STATE(); |
|---|
| 111 | jump StgReturn; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | // A variant of stg_returnToSched, but instead of returning directly to the |
|---|
| 115 | // scheduler, we jump to the code fragment pointed to by R2. This lets us |
|---|
| 116 | // perform some final actions after making the thread safe, such as unlocking |
|---|
| 117 | // the MVar on which we are about to block in SMP mode. |
|---|
| 118 | stg_returnToSchedButFirst |
|---|
| 119 | { |
|---|
| 120 | SAVE_THREAD_STATE(); |
|---|
| 121 | foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO); |
|---|
| 122 | jump R2; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | stg_threadFinished |
|---|
| 126 | { |
|---|
| 127 | StgRegTable_rRet(BaseReg) = ThreadFinished; |
|---|
| 128 | R1 = BaseReg; |
|---|
| 129 | jump StgReturn; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | /* ----------------------------------------------------------------------------- |
|---|
| 133 | Strict IO application - performing an IO action and entering its result. |
|---|
| 134 | |
|---|
| 135 | rts_evalIO() lets you perform Haskell IO actions from outside of |
|---|
| 136 | Haskell-land, returning back to you their result. Want this result |
|---|
| 137 | to be evaluated to WHNF by that time, so that we can easily get at |
|---|
| 138 | the int/char/whatever using the various get{Ty} functions provided |
|---|
| 139 | by the RTS API. |
|---|
| 140 | |
|---|
| 141 | stg_forceIO takes care of this, performing the IO action and entering |
|---|
| 142 | the results that comes back. |
|---|
| 143 | |
|---|
| 144 | ------------------------------------------------------------------------- */ |
|---|
| 145 | |
|---|
| 146 | INFO_TABLE_RET(stg_forceIO, RET_SMALL) |
|---|
| 147 | |
|---|
| 148 | { |
|---|
| 149 | Sp_adj(1); |
|---|
| 150 | ENTER(); |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | /* ----------------------------------------------------------------------------- |
|---|
| 154 | Special STG entry points for module registration. |
|---|
| 155 | -------------------------------------------------------------------------- */ |
|---|
| 156 | |
|---|
| 157 | stg_init_finish |
|---|
| 158 | { |
|---|
| 159 | jump StgReturn; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | /* On entry to stg_init: |
|---|
| 163 | * init_stack[0] = &stg_init_ret; |
|---|
| 164 | * init_stack[1] = __stginit_Something; |
|---|
| 165 | */ |
|---|
| 166 | stg_init |
|---|
| 167 | { |
|---|
| 168 | W_ next; |
|---|
| 169 | Sp = W_[BaseReg + OFFSET_StgRegTable_rSp]; |
|---|
| 170 | next = W_[Sp]; |
|---|
| 171 | Sp_adj(1); |
|---|
| 172 | jump next; |
|---|
| 173 | } |
|---|