summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViktor Dukhovni <ietf-dane@dukhovni.org>2020-11-14 17:50:26 -0800
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-11-30 19:48:17 -0500
commitab334262a605b0ebc228096d8af88a55aa5ea6b8 (patch)
treeb008a32494a42a5d2cb3b6c81996abfb10c26a2e
parent6af074cecdee533791943af1191541f82abc34c4 (diff)
downloadhaskell-ab334262a605b0ebc228096d8af88a55aa5ea6b8.tar.gz
dirty MVAR after mutating TSO queue head
While the original head and tail of the TSO queue may be in the same generation as the MVAR, interior elements of the queue could be younger after a GC run and may then be exposed by putMVar operation that updates the queue head. Resolves #18919
-rw-r--r--rts/PrimOps.cmm30
-rw-r--r--rts/Threads.c13
2 files changed, 28 insertions, 15 deletions
diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
index 7767ead2d8..a6b60ae1cc 100644
--- a/rts/PrimOps.cmm
+++ b/rts/PrimOps.cmm
@@ -1827,9 +1827,16 @@ loop:
// There are readMVar/takeMVar(s) waiting: wake up the first one
tso = StgMVarTSOQueue_tso(q);
- StgMVar_head(mvar) = StgMVarTSOQueue_link(q);
- if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+ q = StgMVarTSOQueue_link(q);
+ StgMVar_head(mvar) = q;
+ if (q == stg_END_TSO_QUEUE_closure) {
StgMVar_tail(mvar) = stg_END_TSO_QUEUE_closure;
+ } else {
+ if (info == stg_MVAR_CLEAN_info) {
+ // Resolve #18919.
+ ccall dirty_MVAR(BaseReg "ptr", mvar "ptr",
+ StgMVar_value(mvar) "ptr");
+ }
}
ASSERT(StgTSO_block_info(tso) == mvar);
@@ -1854,10 +1861,8 @@ loop:
// If it was a readMVar, then we can still do work,
// so loop back. (XXX: This could take a while)
- if (why_blocked == BlockedOnMVarRead) {
- q = StgMVarTSOQueue_link(q);
+ if (why_blocked == BlockedOnMVarRead)
goto loop;
- }
ASSERT(why_blocked == BlockedOnMVar);
@@ -1912,9 +1917,16 @@ loop:
// There are takeMVar(s) waiting: wake up the first one
tso = StgMVarTSOQueue_tso(q);
- StgMVar_head(mvar) = StgMVarTSOQueue_link(q);
- if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
+ q = StgMVarTSOQueue_link(q);
+ StgMVar_head(mvar) = q;
+ if (q == stg_END_TSO_QUEUE_closure) {
StgMVar_tail(mvar) = stg_END_TSO_QUEUE_closure;
+ } else {
+ if (info == stg_MVAR_CLEAN_info) {
+ // Resolve #18919.
+ ccall dirty_MVAR(BaseReg "ptr", mvar "ptr",
+ StgMVar_value(mvar) "ptr");
+ }
}
ASSERT(StgTSO_block_info(tso) == mvar);
@@ -1939,10 +1951,8 @@ loop:
// If it was a readMVar, then we can still do work,
// so loop back. (XXX: This could take a while)
- if (why_blocked == BlockedOnMVarRead) {
- q = StgMVarTSOQueue_link(q);
+ if (why_blocked == BlockedOnMVarRead)
goto loop;
- }
ASSERT(why_blocked == BlockedOnMVar);
diff --git a/rts/Threads.c b/rts/Threads.c
index 6050549d64..39616655ab 100644
--- a/rts/Threads.c
+++ b/rts/Threads.c
@@ -803,9 +803,14 @@ loop:
// There are takeMVar(s) waiting: wake up the first one
tso = q->tso;
- mvar->head = q->link;
- if (mvar->head == (StgMVarTSOQueue*)&stg_END_TSO_QUEUE_closure) {
+ mvar->head = q = q->link;
+ if (q == (StgMVarTSOQueue*)&stg_END_TSO_QUEUE_closure) {
mvar->tail = (StgMVarTSOQueue*)&stg_END_TSO_QUEUE_closure;
+ } else {
+ if (info == &stg_MVAR_CLEAN_info) {
+ // Resolve #18919.
+ dirty_MVAR(&cap->r, (StgClosure*)mvar, mvar->value);
+ }
}
ASSERT(tso->block_info.closure == (StgClosure*)mvar);
@@ -829,10 +834,8 @@ loop:
// If it was a readMVar, then we can still do work,
// so loop back. (XXX: This could take a while)
- if (why_blocked == BlockedOnMVarRead) {
- q = ((StgMVarTSOQueue*)q)->link;
+ if (why_blocked == BlockedOnMVarRead)
goto loop;
- }
ASSERT(why_blocked == BlockedOnMVar);