Skip to content

Commit

Permalink
Optimization for takeMVar/putMVar when MVar left empty; fixes #7923
Browse files Browse the repository at this point in the history
We only need to apply the write barrier to an MVar when it acquires
a reference to live data; when the MVar is left empty in the case
of a takeMVar/putMVar, we can save a memory reference.

Patch from Edward Z. Yang.
  • Loading branch information
Ian Lynagh committed Jun 15, 2013
1 parent 9e4348e commit 5d9e686
Showing 1 changed file with 29 additions and 20 deletions.
49 changes: 29 additions & 20 deletions rts/PrimOps.cmm
Expand Up @@ -1197,14 +1197,13 @@ stg_takeMVarzh ( P_ mvar /* :: MVar a */ )
info = GET_INFO(mvar);
#endif

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

/* If the MVar is empty, put ourselves on its blocking queue,
* and wait until we're woken up.
*/
if (StgMVar_value(mvar) == stg_END_TSO_QUEUE_closure) {
if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

// We want to put the heap check down here in the slow path,
// but be careful to unlock the closure before returning to
Expand Down Expand Up @@ -1243,7 +1242,9 @@ loop:
if (q == stg_END_TSO_QUEUE_closure) {
/* No further putMVars, MVar is now empty */
StgMVar_value(mvar) = stg_END_TSO_QUEUE_closure;
unlockClosure(mvar, stg_MVAR_DIRTY_info);
// If the MVar is not already dirty, then we don't need to make
// it dirty, as it is empty with nothing blocking on it.
unlockClosure(mvar, info);
return (val);
}
if (StgHeader_info(q) == stg_IND_info ||
Expand All @@ -1254,6 +1255,10 @@ loop:

// There are putMVar(s) waiting... wake up the first thread on the queue

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

tso = StgMVarTSOQueue_tso(q);
StgMVar_head(mvar) = StgMVarTSOQueue_link(q);
if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
Expand Down Expand Up @@ -1300,10 +1305,6 @@ stg_tryTakeMVarzh ( P_ mvar /* :: MVar a */ )
return (0, stg_NO_FINALIZER_closure);
}

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

/* we got the value... */
val = StgMVar_value(mvar);

Expand All @@ -1312,9 +1313,10 @@ loop:
if (q == stg_END_TSO_QUEUE_closure) {
/* No further putMVars, MVar is now empty */
StgMVar_value(mvar) = stg_END_TSO_QUEUE_closure;
unlockClosure(mvar, stg_MVAR_DIRTY_info);
unlockClosure(mvar, info);
return (1, val);
}

if (StgHeader_info(q) == stg_IND_info ||
StgHeader_info(q) == stg_MSG_NULL_info) {
q = StgInd_indirectee(q);
Expand All @@ -1323,6 +1325,10 @@ loop:

// There are putMVar(s) waiting... wake up the first thread on the queue

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

tso = StgMVarTSOQueue_tso(q);
StgMVar_head(mvar) = StgMVarTSOQueue_link(q);
if (StgMVar_head(mvar) == stg_END_TSO_QUEUE_closure) {
Expand Down Expand Up @@ -1359,12 +1365,12 @@ stg_putMVarzh ( P_ mvar, /* :: MVar a */
info = GET_INFO(mvar);
#endif

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

if (StgMVar_value(mvar) != stg_END_TSO_QUEUE_closure) {

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

// We want to put the heap check down here in the slow path,
// but be careful to unlock the closure before returning to
// the RTS if the check fails.
Expand Down Expand Up @@ -1398,6 +1404,9 @@ stg_putMVarzh ( P_ mvar, /* :: MVar a */
loop:
if (q == stg_END_TSO_QUEUE_closure) {
/* No further takes, the MVar is now full. */
if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}
StgMVar_value(mvar) = val;
unlockClosure(mvar, stg_MVAR_DIRTY_info);
return ();
Expand Down Expand Up @@ -1433,7 +1442,7 @@ loop:

ccall tryWakeupThread(MyCapability() "ptr", tso);

unlockClosure(mvar, stg_MVAR_DIRTY_info);
unlockClosure(mvar, info);
return ();
}

Expand All @@ -1456,14 +1465,14 @@ stg_tryPutMVarzh ( P_ mvar, /* :: MVar a */
return (0);
}

if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

q = StgMVar_head(mvar);
loop:
if (q == stg_END_TSO_QUEUE_closure) {
/* No further takes, the MVar is now full. */
if (info == stg_MVAR_CLEAN_info) {
ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
}

StgMVar_value(mvar) = val;
unlockClosure(mvar, stg_MVAR_DIRTY_info);
return (1);
Expand Down Expand Up @@ -1499,7 +1508,7 @@ loop:

ccall tryWakeupThread(MyCapability() "ptr", tso);

unlockClosure(mvar, stg_MVAR_DIRTY_info);
unlockClosure(mvar, info);
return (1);
}

Expand Down

0 comments on commit 5d9e686

Please sign in to comment.