- // After releasing the lock we cannot access anymore any SplitPoint
- // related data in a safe way becuase it could have been released under
- // our feet by the sp master. Also accessing other Thread objects is
- // unsafe because if we are exiting there is a chance are already freed.
- sp->mutex.unlock();
+ // After releasing the lock we can't access any SplitPoint related data
+ // in a safe way because it could have been released under our feet by
+ // the sp master.
+ sp->spinlock.release();
+
+ // Try to late join to another split point if none of its slaves has
+ // already finished.
+ SplitPoint* bestSp = NULL;
+ int minLevel = INT_MAX;
+
+ for (Thread* th : Threads)
+ {
+ const size_t size = th->splitPointsSize; // Local copy
+ sp = size ? &th->splitPoints[size - 1] : nullptr;
+
+ if ( sp
+ && sp->allSlavesSearching
+ && sp->slavesMask.count() < MAX_SLAVES_PER_SPLITPOINT
+ && can_join(sp))
+ {
+ assert(this != th);
+ assert(!(this_sp && this_sp->slavesMask.none()));
+ assert(Threads.size() > 2);
+
+ // Prefer to join to SP with few parents to reduce the probability
+ // that a cut-off occurs above us, and hence we waste our work.
+ int level = 0;
+ for (SplitPoint* p = th->activeSplitPoint; p; p = p->parentSplitPoint)
+ level++;
+
+ if (level < minLevel)
+ {
+ bestSp = sp;
+ minLevel = level;
+ }
+ }
+ }
+
+ if (bestSp)
+ {
+ sp = bestSp;
+
+ // Recheck the conditions under lock protection
+ Threads.spinlock.acquire();
+ sp->spinlock.acquire();
+
+ if ( sp->allSlavesSearching
+ && sp->slavesMask.count() < MAX_SLAVES_PER_SPLITPOINT
+ && can_join(sp))
+ {
+ sp->slavesMask.set(idx);
+ activeSplitPoint = sp;
+ searching = true;
+ }
+
+ sp->spinlock.release();
+ Threads.spinlock.release();
+ }