summaryrefslogtreecommitdiff
path: root/ghc/includes/STM.h
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/includes/STM.h')
-rw-r--r--ghc/includes/STM.h131
1 files changed, 58 insertions, 73 deletions
diff --git a/ghc/includes/STM.h b/ghc/includes/STM.h
index 6b65b0e871..cf821dc3a1 100644
--- a/ghc/includes/STM.h
+++ b/ghc/includes/STM.h
@@ -8,60 +8,38 @@
STM.h defines the C-level interface to the STM.
- The interface is designed so that all of the operations return
- directly: if the specified StgTSO should block then the Haskell
- scheduler's data structures are updated within the STM
- implementation, rather than blocking the native thread.
+ The design follows that of the PPoPP 2005 paper "Composable memory
+ transactions" extended to include fine-grained locking of TVars.
- This interface can be supported by many different implementations,
- in particular it is left unspecified:
-
- - Whether nested transactions are fully supported.
+ Three different implementations can be built. In overview:
+
+ STM_UNIPROC -- no locking at all: not safe for concurrent invocations
- A simple implementation would count the number of
- stmStartTransaction operations that a thread invokes and only
- attempt to really commit it to the heap when the corresponding
- number of stmCommitTransaction calls have been made. This
- prevents enclosed transactions from being aborted without also
- aborting all of the outer ones.
+ STM_CG_LOCK -- coarse-grained locking : a single mutex protects all
+ TVars
- The current implementation does support proper nesting.
-
- - Whether stmWait and stmReWait are blocking.
-
- A simple implementation would always return 'false' from these
- operations, signalling that the calling thread should immediately
- retry its transaction.
-
- A fuller implementation would block the thread and return 'True'
- when it is safe for the thread to block.
-
- The current implementation does provide stmWait and stmReWait
- operations which can block the caller's TSO.
-
- - Whether the transactional read, write, commit and validate
- operations are blocking or non-blocking.
-
- A simple implementation would use an internal lock to prevent
- concurrent execution of any STM operations. (This does not
- prevent multiple threads having concurrent transactions, merely
- the concurrent execution of say stmCommitTransaction by two
- threads at the same time).
+ STM_FG_LOCKS -- per-TVar exclusion : each TVar can be owned by at
+ most one TRec at any time. This allows dynamically
+ non-conflicting transactions to commit in parallel.
+ The implementation treats reads optimisitcally --
+ extra versioning information is retained in the
+ saw_update_by field of the TVars so that they do not
+ need to be locked for reading.
- A fuller implementation would offer obstruction-free or lock-free
- progress guarantees, as in our OOPSLA 2003 paper.
+ STM.C contains more details about the locking schemes used.
- The current implementation is lock-free for simple uncontended
- operations, but uses an internal lock on SMP systems in some
- cases. This aims to provide good performance on uniprocessors:
- it substantially streamlines the design, when compared with the
- OOPSLA paper, and on a uniprocessor we can be sure that threads
- are never pre-empted within STM operations.
*/
#ifndef STM_H
#define STM_H
+#ifdef SMP
+//#define STM_CG_LOCK
+#define STM_FG_LOCKS
+#else
+#define STM_UNIPROC
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -86,7 +64,9 @@ extern void stmPreGCHook(void);
/* Create and enter a new transaction context */
-extern StgTRecHeader *stmStartTransaction(StgTRecHeader *outer);
+extern StgTRecHeader *stmStartTransaction(StgRegTable *reg, StgTRecHeader *outer);
+extern StgTRecHeader *stmStartNestedTransaction(StgRegTable *reg, StgTRecHeader *outer
+);
/*
* Exit the current transaction context, abandoning any read/write
@@ -118,16 +98,36 @@ extern StgTRecHeader *stmGetEnclosingTRec(StgTRecHeader *trec);
/*----------------------------------------------------------------------
- Validate/commit/wait/rewait operations
- --------------------------------------
+ Validation
+ ----------
+
+ Test whether the specified transaction record, and all those within which
+ it is nested, are still valid.
+
+ Note: the caller can assume that once stmValidateTransaction has
+ returned FALSE for a given trec then that transaction will never
+ again be valid -- we rely on this in Schedule.c when kicking invalid
+ threads at GC (in case they are stuck looping)
+*/
+
+extern StgBool stmValidateNestOfTransactions(StgTRecHeader *trec);
+
+/*----------------------------------------------------------------------
+ Commit/wait/rewait operations
+ -----------------------------
These four operations return boolean results which should be interpreted
as follows:
- true => The transaction context was definitely valid
+ true => The transaction record was definitely valid
+
+ false => The transaction record may not have been valid
- false => The transaction context may not have been valid
+ Note that, for nested operations, validity here is solely in terms
+ of the specified trec: it does not say whether those that it may be
+ nested are themselves valid. Callers can check this with
+ stmValidateNestOfTransactions.
The user of the STM should ensure that it is always safe to assume that a
transaction context is not valid when in fact it is (i.e. to return false in
@@ -152,23 +152,14 @@ extern StgTRecHeader *stmGetEnclosingTRec(StgTRecHeader *trec);
*/
/*
- * Test whether the current transaction context is valid, i.e. whether
- * it is still possible for it to commit successfully. Note: we assume that
- * once stmValidateTransaction has returned FALSE for a given transaction then
- * that transaction will never again be valid -- we rely on this in Schedule.c when
- * kicking invalid threads at GC (in case they are stuck looping)
- */
-
-extern StgBool stmValidateTransaction(StgTRecHeader *trec);
-
-/*
* Test whether the current transaction context is valid and, if so,
* commit its memory accesses to the heap. stmCommitTransaction must
* unblock any threads which are waiting on tvars that updates have
* been committed to.
*/
-extern StgBool stmCommitTransaction(StgTRecHeader *trec);
+extern StgBool stmCommitTransaction(StgRegTable *reg, StgTRecHeader *trec);
+extern StgBool stmCommitNestedTransaction(StgRegTable *reg, StgTRecHeader *trec);
/*
* Test whether the current transaction context is valid and, if so,
@@ -177,7 +168,9 @@ extern StgBool stmCommitTransaction(StgTRecHeader *trec);
* if the thread is already waiting.
*/
-extern StgBool stmWait(StgTSO *tso, StgTRecHeader *trec);
+extern StgBool stmWait(StgRegTable *reg,
+ StgTSO *tso,
+ StgTRecHeader *trec);
/*
* Test whether the current transaction context is valid and, if so,
@@ -189,16 +182,6 @@ extern StgBool stmWait(StgTSO *tso, StgTRecHeader *trec);
extern StgBool stmReWait(StgTSO *tso);
-/*
- * Merge the accesses made so far in the second trec into the first trec.
- * Note that the resulting trec is only intended to be used in wait operations.
- * This avoids defining what happens if "trec" and "other" contain conflicting
- * updates.
- */
-
-extern StgBool stmMergeForWaiting(StgTRecHeader *trec, StgTRecHeader *other);
-
-
/*----------------------------------------------------------------------
Data access operations
@@ -210,14 +193,16 @@ extern StgBool stmMergeForWaiting(StgTRecHeader *trec, StgTRecHeader *other);
* thread's current transaction.
*/
-extern StgClosure *stmReadTVar(StgTRecHeader *trec,
+extern StgClosure *stmReadTVar(StgRegTable *reg,
+ StgTRecHeader *trec,
StgTVar *tvar);
/* Update the logical contents of 'tvar' within the context of the
* thread's current transaction.
*/
-extern void stmWriteTVar(StgTRecHeader *trec,
+extern void stmWriteTVar(StgRegTable *reg,
+ StgTRecHeader *trec,
StgTVar *tvar,
StgClosure *new_value);