From 9150cfffa8a124a4080211ec5cb9d6332a99e739 Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni Date: Sat, 14 Nov 2020 17:50:26 -0800 Subject: [PATCH] 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 --- rts/PrimOps.cmm | 30 ++++++++++++++++++++---------- rts/Threads.c | 13 ++++++++----- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm index 7767ead2d8d..a6b60ae1cc5 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 6050549d643..39616655abd 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); -- GitLab