1 /*----------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2004
5 * STM interface definition
7 *----------------------------------------------------------------------
9 STM.h defines the C-level interface to the STM.
11 The interface is designed so that all of the operations return
12 directly: if the specified StgTSO should block then the Haskell
13 scheduler's data structures are updated within the STM
14 implementation, rather than blocking the native thread.
16 This interface can be supported by many different implementations,
17 in particular it is left unspecified:
19 - Whether nested transactions are fully supported.
21 A simple implementation would count the number of
22 stmStartTransaction operations that a thread invokes and only
23 attempt to really commit it to the heap when the corresponding
24 number of stmCommitTransaction calls have been made. This
25 prevents enclosed transactions from being aborted without also
26 aborting all of the outer ones.
28 The current implementation does support proper nesting.
30 - Whether stmWait and stmReWait are blocking.
32 A simple implementation would always return 'false' from these
33 operations, signalling that the calling thread should immediately
34 retry its transaction.
36 A fuller implementation would block the thread and return 'True'
37 when it is safe for the thread to block.
39 The current implementation does provide stmWait and stmReWait
40 operations which can block the caller's TSO.
42 - Whether the transactional read, write, commit and validate
43 operations are blocking or non-blocking.
45 A simple implementation would use an internal lock to prevent
46 concurrent execution of any STM operations. (This does not
47 prevent multiple threads having concurrent transactions, merely
48 the concurrent execution of say stmCommitTransaction by two
49 threads at the same time).
51 A fuller implementation would offer obstruction-free or lock-free
52 progress guarantees, as in our OOPSLA 2003 paper.
54 The current implementation is lock-free for simple uncontended
55 operations, but uses an internal lock on SMP systems in some
56 cases. This aims to provide good performance on uniprocessors:
57 it substantially streamlines the design, when compared with the
58 OOPSLA paper, and on a uniprocessor we can be sure that threads
59 are never pre-empted within STM operations.
69 /*----------------------------------------------------------------------
76 extern void initSTM(void);
78 extern void stmPreGCHook(void);
80 /*----------------------------------------------------------------------
82 Transaction context management
83 ------------------------------
87 // Create and enter a new transaction context
89 extern StgTRecHeader *stmStartTransaction(StgTRecHeader *outer);
91 // Exit the current transaction context, abandoning any read/write
92 // operations performed within it and removing the thread from any
93 // tvar wait queues if it was waitin. Note that if nested transactions
94 // are not fully supported then this may leave the enclosing
95 // transaction contexts doomed to abort.
97 extern void stmAbortTransaction(StgTRecHeader *trec);
99 // Ensure that a subsequent commit / validation will fail. We use this
100 // in our current handling of transactions that may have become invalid
101 // and started looping. We strip their stack back to the ATOMICALLY_FRAME,
102 // and, when the thread is next scheduled, discover it to be invalid and
103 // re-execute it. However, we need to force the transaction to stay invalid
104 // in case other threads' updates make it valid in the mean time.
106 extern void stmCondemnTransaction(StgTRecHeader *trec);
108 // Return the trec within which the specified trec was created (not
109 // valid if trec==NO_TREC).
111 extern StgTRecHeader *stmGetEnclosingTRec(StgTRecHeader *trec);
113 /*----------------------------------------------------------------------
115 Validate/commit/wait/rewait operations
116 --------------------------------------
119 These four operations return boolean results which should be interpreted
122 true => The transaction context was definitely valid
124 false => The transaction context may not have been valid
126 The user of the STM should ensure that it is always safe to assume that a
127 transaction context is not valid when in fact it is (i.e. to return false in
128 place of true, with side-effects as defined below). This may cause
129 needless retries of transactions (in the case of validate and commit), or it
130 may cause needless spinning instead of blocking (in the case of wait and
133 In defining the behaviour of wait and rewait we distinguish between two
134 different aspects of a thread's runnability:
136 - We say that a thread is "blocked" when it is not running or
137 runnable as far as the scheduler is concerned.
139 - We say that a thread is "waiting" when its StgTRecHeader is linked on an
142 Considering only STM operations, (blocked) => (waiting). The user of the STM
143 should ensure that they are prepared for threads to be unblocked spuriously
144 and for wait/reWait to return false even when the previous transaction context
145 is actually still valid.
148 // Test whether the current transaction context is valid, i.e. whether
149 // it is still possible for it to commit successfully. Note: we assume that
150 // once stmValidateTransaction has returned FALSE for a given transaction then
151 // that transaction will never again be valid -- we rely on this in Schedule.c when
152 // kicking invalid threads at GC (in case they are stuck looping)
154 extern StgBool stmValidateTransaction(StgTRecHeader *trec);
156 // Test whether the current transaction context is valid and, if so,
157 // commit its memory accesses to the heap. stmCommitTransaction must
158 // unblock any threads which are waiting on tvars that updates have
159 // been committed to.
161 extern StgBool stmCommitTransaction(StgTRecHeader *trec);
163 // Test whether the current transaction context is valid and, if so,
164 // start the thread waiting for updates to any of the tvars it has
165 // ready from and mark it as blocked. It is an error to call stmWait
166 // if the thread is already waiting.
168 extern StgBool stmWait(StgTSO *tso, StgTRecHeader *trec);
170 // Test whether the current transaction context is valid and, if so,
171 // leave the thread waiting and mark it as blocked again. If the
172 // transaction context is no longer valid then stop the thread waiting
173 // and leave it as unblocked. It is an error to call stmReWait if the
174 // thread is not waiting.
176 extern StgBool stmReWait(StgTSO *tso);
178 // Merge the accesses made so far in the second trec into the first trec.
179 // Note that the resulting trec is only intended to be used in wait operations.
180 // This avoids defining what happens if "trec" and "other" contain conflicting
183 extern StgBool stmMergeForWaiting(StgTRecHeader *trec, StgTRecHeader *other);
186 /*----------------------------------------------------------------------
188 Data access operations
189 ----------------------
192 // Return the logical contents of 'tvar' within the context of the
193 // thread's current transaction.
195 extern StgClosure *stmReadTVar(StgTRecHeader *trec,
198 // Update the logical contents of 'tvar' within the context of the
199 // thread's current transaction.
201 extern void stmWriteTVar(StgTRecHeader *trec,
203 StgClosure *new_value);
205 /*----------------------------------------------------------------------*/
209 #define END_STM_WAIT_QUEUE ((StgTVarWaitQueue *)(void *)&stg_END_STM_WAIT_QUEUE_closure)
210 #define END_STM_CHUNK_LIST ((StgTRecChunk *)(void *)&stg_END_STM_CHUNK_LIST_closure)
211 #define NO_TREC ((StgTRecHeader *)(void *)&stg_NO_TREC_closure)
213 /*----------------------------------------------------------------------*/