summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rts/PrimOps.cmm54
-rw-r--r--rts/Schedule.c66
-rw-r--r--rts/Schedule.h3
3 files changed, 103 insertions, 20 deletions
diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
index d06cde05d9..ec35ee42b4 100644
--- a/rts/PrimOps.cmm
+++ b/rts/PrimOps.cmm
@@ -1032,6 +1032,37 @@ stg_threadStatuszh ( gcptr tso )
* TVar primitives
* -------------------------------------------------------------------------- */
+stg_abort /* no arg list: explicit stack layout */
+{
+ W_ frame_type;
+ W_ frame;
+ W_ trec;
+ W_ outer;
+ W_ r;
+
+ // STM operations may allocate
+ MAYBE_GC_ (stg_abort); // NB. not MAYBE_GC(), we cannot make a
+ // function call in an explicit-stack proc
+
+ // Find the enclosing ATOMICALLY_FRAME
+ SAVE_THREAD_STATE();
+ (frame_type) = ccall findAtomicallyFrameHelper(MyCapability(), CurrentTSO "ptr");
+ LOAD_THREAD_STATE();
+ frame = Sp;
+ trec = StgTSO_trec(CurrentTSO);
+ outer = StgTRecHeader_enclosing_trec(trec);
+
+ // We've reached the ATOMICALLY_FRAME
+ ASSERT(frame_type == ATOMICALLY_FRAME);
+ ASSERT(outer == NO_TREC);
+
+ // Restart the transaction.
+ ("ptr" trec) = ccall stmStartTransaction(MyCapability() "ptr", outer "ptr");
+ StgTSO_trec(CurrentTSO) = trec;
+ Sp = frame;
+ R1 = StgAtomicallyFrame_code(frame);
+ jump stg_ap_v_fast [R1];
+}
// Catch retry frame -----------------------------------------------------------
#define CATCH_RETRY_FRAME_FIELDS(w_,p_,info_ptr, \
@@ -1066,26 +1097,9 @@ INFO_TABLE_RET(stg_catch_retry_frame, CATCH_RETRY_FRAME,
StgTSO_trec(CurrentTSO) = outer;
return (ret);
} else {
- // Did not commit: re-execute
- P_ new_trec;
- ("ptr" new_trec) = ccall stmStartTransaction(MyCapability() "ptr",
- outer "ptr");
- StgTSO_trec(CurrentTSO) = new_trec;
- if (running_alt_code != 0) {
- jump stg_ap_v_fast
- (CATCH_RETRY_FRAME_FIELDS(,,info_ptr, p1, p2,
- running_alt_code,
- first_code,
- alt_code))
- (alt_code);
- } else {
- jump stg_ap_v_fast
- (CATCH_RETRY_FRAME_FIELDS(,,info_ptr, p1, p2,
- running_alt_code,
- first_code,
- alt_code))
- (first_code);
- }
+ // Did not commit: abort and restart.
+ StgTSO_trec(CurrentTSO) = outer;
+ jump stg_abort();
}
}
diff --git a/rts/Schedule.c b/rts/Schedule.c
index 7ffd44d22f..eced4d4fb6 100644
--- a/rts/Schedule.c
+++ b/rts/Schedule.c
@@ -2999,6 +2999,72 @@ findRetryFrameHelper (Capability *cap, StgTSO *tso)
}
/* -----------------------------------------------------------------------------
+ findAtomicallyFrameHelper
+
+ This function is called by stg_abort via catch_retry_frame primitive. It is
+ like findRetryFrameHelper but it will only stop at ATOMICALLY_FRAME.
+ -------------------------------------------------------------------------- */
+
+StgWord
+findAtomicallyFrameHelper (Capability *cap, StgTSO *tso)
+{
+ const StgRetInfoTable *info;
+ StgPtr p, next;
+
+ p = tso->stackobj->sp;
+ while (1) {
+ info = get_ret_itbl((const StgClosure *)p);
+ next = p + stack_frame_sizeW((StgClosure *)p);
+ switch (info->i.type) {
+
+ case ATOMICALLY_FRAME:
+ debugTrace(DEBUG_stm,
+ "found ATOMICALLY_FRAME at %p while aborting after orElse", p);
+ tso->stackobj->sp = p;
+ return ATOMICALLY_FRAME;
+
+ case CATCH_RETRY_FRAME: {
+ StgTRecHeader *trec = tso -> trec;
+ StgTRecHeader *outer = trec -> enclosing_trec;
+ debugTrace(DEBUG_stm,
+ "found CATCH_RETRY_FRAME at %p while aborting after orElse", p);
+ debugTrace(DEBUG_stm, "trec=%p outer=%p", trec, outer);
+ stmAbortTransaction(cap, trec);
+ stmFreeAbortedTRec(cap, trec);
+ tso -> trec = outer;
+ p = next;
+ continue;
+ }
+
+ case CATCH_STM_FRAME: {
+ StgTRecHeader *trec = tso -> trec;
+ StgTRecHeader *outer = trec -> enclosing_trec;
+ debugTrace(DEBUG_stm,
+ "found CATCH_STM_FRAME at %p while aborting after orElse", p);
+ debugTrace(DEBUG_stm, "trec=%p outer=%p", trec, outer);
+ stmAbortTransaction(cap, trec);
+ stmFreeAbortedTRec(cap, trec);
+ tso -> trec = outer;
+ p = next;
+ continue;
+ }
+
+ case UNDERFLOW_FRAME:
+ tso->stackobj->sp = p;
+ threadStackUnderflow(cap,tso);
+ p = tso->stackobj->sp;
+ continue;
+
+ default:
+ ASSERT(info->i.type != CATCH_FRAME);
+ ASSERT(info->i.type != STOP_FRAME);
+ p = next;
+ continue;
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------
resurrectThreads is called after garbage collection on the list of
threads found to be garbage. Each of these threads will be woken
up and sent a signal: BlockedOnDeadMVar if the thread was blocked
diff --git a/rts/Schedule.h b/rts/Schedule.h
index 66cf8391f3..3197980041 100644
--- a/rts/Schedule.h
+++ b/rts/Schedule.h
@@ -46,6 +46,9 @@ StgWord raiseExceptionHelper (StgRegTable *reg, StgTSO *tso, StgClosure *excepti
/* findRetryFrameHelper */
StgWord findRetryFrameHelper (Capability *cap, StgTSO *tso);
+/* findAtomicallyFrameHelper */
+StgWord findAtomicallyFrameHelper (Capability *cap, StgTSO *tso);
+
/* Entry point for a new worker */
void scheduleWorker (Capability *cap, Task *task);