// New best move?
if (value > sp->bestValue) // Less then 2% of cases
{
- lock_grab(&(sp->lock));
+ // Recursive locking, lock current split point and its ancestors to
+ // guarantee thread_should_stop() and sp_update_pv() are race free.
+ SplitPoint* spChain[MAX_THREADS * ACTIVE_SPLIT_POINTS_MAX];
+ int cnt = 0;
+ for (spChain[cnt] = sp; spChain[cnt]; )
+ {
+ lock_grab(&(spChain[cnt++]->lock));
+ spChain[cnt] = spChain[cnt - 1]->parent;
+ }
+
if (value > sp->bestValue && !TM.thread_should_stop(threadID))
{
sp->bestValue = value;
if (sp->bestValue >= sp->beta)
{
- sp_update_pv(sp->parentSstack, ss, sp->ply);
sp->stopRequest = true;
+ sp_update_pv(sp->parentSstack, ss, sp->ply);
}
}
- lock_release(&(sp->lock));
+
+ // Release locks in reverse order
+ while (cnt > 0)
+ lock_release(&(spChain[--cnt]->lock));
}
}
// New best move?
if (value > sp->bestValue) // Less then 2% of cases
{
- lock_grab(&(sp->lock));
+ // Recursive locking, lock current split point and its ancestors to
+ // guarantee thread_should_stop() and sp_update_pv() are race free.
+ SplitPoint* spChain[MAX_THREADS * ACTIVE_SPLIT_POINTS_MAX];
+ int cnt = 0;
+ for (spChain[cnt] = sp; spChain[cnt]; )
+ {
+ lock_grab(&(spChain[cnt++]->lock));
+ spChain[cnt] = spChain[cnt - 1]->parent;
+ }
+
if (value > sp->bestValue && !TM.thread_should_stop(threadID))
{
sp->bestValue = value;
ss[sp->ply].mateKiller = move;
}
}
- lock_release(&(sp->lock));
+
+ // Release locks in reverse order
+ while (cnt > 0)
+ lock_release(&(spChain[--cnt]->lock));
}
}