if (remainingThreads > 0)
{
- /* TODO: add spincount support */
- WaitForSingleObject(hCurrentEvent, INFINITE);
+ DWORD dwProcessors = lpBarrier->Reserved4;
+ BOOL spinOnly = dwFlags & SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY;
+ BOOL blockOnly = dwFlags & SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY;
+ BOOL block = TRUE;
+
+ /**
+ * If SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY is set we will
+ * always spin and trust that the user knows what he/she/it
+ * is doing. Otherwise we'll only spin if the flag
+ * SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY is not set and
+ * the number of remaining threads is less than the number
+ * of processors.
+ */
+
+ if (spinOnly || (remainingThreads < dwProcessors && !blockOnly))
+ {
+ DWORD dwSpinCount = lpBarrier->Reserved5;
+ DWORD sp = 0;
+ /* we spin until the last thread _completed_ the event switch */
+ while ((block = (lpBarrier->Reserved3[0] == (ULONG_PTR)hCurrentEvent)))
+ if (!spinOnly && ++sp > dwSpinCount)
+ break;
+ }
+
+ if (block)
+ WaitForSingleObject(hCurrentEvent, INFINITE);
+
return FALSE;
}
- /* switch events */
- lpBarrier->Reserved3[0] = (ULONG_PTR)hDormantEvent;
- lpBarrier->Reserved3[1] = (ULONG_PTR)hCurrentEvent;
-
/* reset the dormant event first */
ResetEvent(hDormantEvent);
/* reset the remaining counter */
lpBarrier->Reserved1 = lpBarrier->Reserved2;
+ /* switch events - this will also unblock the spinning threads */
+ lpBarrier->Reserved3[1] = (ULONG_PTR)hCurrentEvent;
+ lpBarrier->Reserved3[0] = (ULONG_PTR)hDormantEvent;
+
/* signal the blocked threads */
SetEvent(hCurrentEvent);
BOOL status = FALSE;
DWORD i, tnum = InterlockedIncrement(&gThreadCount) - 1;
- printf("Thread #%03u entered.\n", tnum);
+ DWORD dwFlags = *(DWORD*)lpParam;
+
+ //printf("Thread #%03u entered.\n", tnum);
/* wait for start event from main */
if (WaitForSingleObject(gStartEvent, INFINITE) != WAIT_OBJECT_0)
goto out;
}
- printf("Thread #%03u unblocked.\n", tnum);
+ //printf("Thread #%03u unblocked.\n", tnum);
for (i = 0; i < LOOP_COUNT && gErrorCount == 0; i++)
{
/* simulate different execution times before the barrier */
Sleep(rand() % MAX_SLEEP_MS);
- status = EnterSynchronizationBarrier(&gBarrier, 0);
+ status = EnterSynchronizationBarrier(&gBarrier, dwFlags);
//printf("Thread #%03u status: %s\n", tnum, status ? "TRUE" : "FALSE");
if (status)
InterlockedIncrement(&gTrueCount);
InterlockedIncrement(&gFalseCount);
}
out:
- printf("Thread #%03u leaving.\n", tnum);
+ //printf("Thread #%03u leaving.\n", tnum);
return 0;
}
-int TestSynchBarrier(int argc, char* argv[])
+BOOL TestSynchBarrierWithFlags(DWORD dwFlags)
{
HANDLE threads[THREAD_COUNT];
DWORD dwStatus;
int i;
- /* Test invalid parameters */
- if (InitializeSynchronizationBarrier(&gBarrier, 0, -1))
- {
- printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = 0\n", __FUNCTION__);
- return -1;
- }
+ gThreadCount = 0;
+ gTrueCount = 0;
+ gFalseCount = 0;
- if (InitializeSynchronizationBarrier(&gBarrier, -1, -1))
- {
- printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = -1\n", __FUNCTION__);
- return -1;
- }
+ printf("%s: >> Testing with EnterSynchronizationBarrier flags 0x%08x\n", __FUNCTION__, dwFlags);
- if (InitializeSynchronizationBarrier(&gBarrier, 1, -2))
- {
- printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lSpinCount = -2\n", __FUNCTION__);
- return -1;
- }
-
-
- /* Functional test */
if (!InitializeSynchronizationBarrier(&gBarrier, THREAD_COUNT, -1))
{
printf("%s: InitializeSynchronizationBarrier failed. GetLastError() = 0x%08x", __FUNCTION__, GetLastError());
DeleteSynchronizationBarrier(&gBarrier);
- return -1;
+ return FALSE;
}
if (!(gStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
{
printf("%s: CreateEvent failed with error 0x%08x", __FUNCTION__, GetLastError());
DeleteSynchronizationBarrier(&gBarrier);
- return -1;
+ return FALSE;
}
for (i = 0; i < THREAD_COUNT; i++)
{
- if (!(threads[i] = CreateThread(NULL, 0, test_synch_barrier_thread, NULL, 0, NULL)))
+ if (!(threads[i] = CreateThread(NULL, 0, test_synch_barrier_thread, &dwFlags, 0, NULL)))
{
printf("%s: CreateThread failed for thread #%u with error 0x%08x\n", __FUNCTION__, i, GetLastError());
InterlockedIncrement(&gErrorCount);
if (gFalseCount != EXPECTED_FALSE_COUNT)
InterlockedIncrement(&gErrorCount);
- printf("%s: gErrorCount: %d (expected 0)\n", __FUNCTION__, gErrorCount);
+ printf("%s: gErrorCount: %d\n", __FUNCTION__, gErrorCount);
printf("%s: gTrueCount: %d (expected %d)\n", __FUNCTION__, gTrueCount, LOOP_COUNT);
printf("%s: gFalseCount: %d (expected %d)\n", __FUNCTION__, gFalseCount, LOOP_COUNT * (THREAD_COUNT - 1));
if (gErrorCount > 0)
{
printf("%s: Error test failed with %d reported errors\n", __FUNCTION__, gErrorCount);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+int TestSynchBarrier(int argc, char* argv[])
+{
+ /* Test invalid parameters */
+ if (InitializeSynchronizationBarrier(&gBarrier, 0, -1))
+ {
+ printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = 0\n", __FUNCTION__);
+ return -1;
+ }
+
+ if (InitializeSynchronizationBarrier(&gBarrier, -1, -1))
+ {
+ printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = -1\n", __FUNCTION__);
+ return -1;
+ }
+
+ if (InitializeSynchronizationBarrier(&gBarrier, 1, -2))
+ {
+ printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lSpinCount = -2\n", __FUNCTION__);
return -1;
}
+ /* Functional tests */
+
+ if (!TestSynchBarrierWithFlags(0))
+ return -1;
+
+ if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY))
+ return -1;
+
+ if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY))
+ return -1;
+
printf("%s: Test successfully completed\n", __FUNCTION__);
return 0;
}
-