2014-08-09 01:34:30 +04:00
|
|
|
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <winpr/synch.h>
|
|
|
|
#include <winpr/thread.h>
|
2016-06-03 19:56:36 +03:00
|
|
|
#include <winpr/interlocked.h>
|
2016-06-06 16:33:16 +03:00
|
|
|
#include <winpr/sysinfo.h>
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2015-05-21 09:32:51 +03:00
|
|
|
#include "../synch.h"
|
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
static SYNCHRONIZATION_BARRIER gBarrier;
|
|
|
|
static HANDLE gStartEvent = NULL;
|
|
|
|
static LONG gErrorCount = 0;
|
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
#define MAX_SLEEP_MS 32
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
struct test_params
|
|
|
|
{
|
|
|
|
LONG threadCount;
|
|
|
|
LONG trueCount;
|
|
|
|
LONG falseCount;
|
|
|
|
DWORD loops;
|
|
|
|
DWORD flags;
|
|
|
|
};
|
2014-08-09 01:34:30 +04:00
|
|
|
|
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
DWORD WINAPI test_synch_barrier_thread(LPVOID lpParam)
|
|
|
|
{
|
|
|
|
BOOL status = FALSE;
|
2016-06-06 16:33:16 +03:00
|
|
|
struct test_params* p = (struct test_params*)lpParam;
|
2016-08-10 15:53:03 +03:00
|
|
|
DWORD i;
|
2016-06-04 01:55:27 +03:00
|
|
|
|
2016-08-10 15:53:03 +03:00
|
|
|
InterlockedIncrement(&p->threadCount);
|
2016-08-10 11:29:59 +03:00
|
|
|
|
2016-06-04 01:55:27 +03:00
|
|
|
//printf("Thread #%03u entered.\n", tnum);
|
2016-06-03 19:56:36 +03:00
|
|
|
|
|
|
|
/* wait for start event from main */
|
|
|
|
if (WaitForSingleObject(gStartEvent, INFINITE) != WAIT_OBJECT_0)
|
2014-08-09 01:34:30 +04:00
|
|
|
{
|
2016-06-03 19:56:36 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
goto out;
|
2014-08-09 01:34:30 +04:00
|
|
|
}
|
|
|
|
|
2016-06-04 01:55:27 +03:00
|
|
|
//printf("Thread #%03u unblocked.\n", tnum);
|
2015-05-21 09:32:51 +03:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
for (i = 0; i < p->loops && gErrorCount == 0; i++)
|
2016-06-03 19:56:36 +03:00
|
|
|
{
|
|
|
|
/* simulate different execution times before the barrier */
|
|
|
|
Sleep(rand() % MAX_SLEEP_MS);
|
2016-06-06 16:33:16 +03:00
|
|
|
status = EnterSynchronizationBarrier(&gBarrier, p->flags);
|
2016-08-10 11:29:59 +03:00
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
//printf("Thread #%03u status: %s\n", tnum, status ? "TRUE" : "FALSE");
|
|
|
|
if (status)
|
2016-06-06 16:33:16 +03:00
|
|
|
InterlockedIncrement(&p->trueCount);
|
2016-06-03 19:56:36 +03:00
|
|
|
else
|
2016-06-06 16:33:16 +03:00
|
|
|
InterlockedIncrement(&p->falseCount);
|
2016-06-03 19:56:36 +03:00
|
|
|
}
|
2016-08-10 11:29:59 +03:00
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
out:
|
2016-06-04 01:55:27 +03:00
|
|
|
//printf("Thread #%03u leaving.\n", tnum);
|
2016-06-03 19:56:36 +03:00
|
|
|
return 0;
|
2015-05-21 09:32:51 +03:00
|
|
|
}
|
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
|
2016-08-10 15:53:03 +03:00
|
|
|
static BOOL TestSynchBarrierWithFlags(DWORD dwFlags, DWORD dwThreads, DWORD dwLoops)
|
2014-08-09 01:34:30 +04:00
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
HANDLE* threads;
|
2016-06-06 16:33:16 +03:00
|
|
|
struct test_params p;
|
|
|
|
DWORD dwStatus, expectedTrueCount, expectedFalseCount;
|
2016-08-10 13:39:26 +03:00
|
|
|
DWORD i;
|
2016-06-06 16:33:16 +03:00
|
|
|
p.threadCount = 0;
|
|
|
|
p.trueCount = 0;
|
|
|
|
p.falseCount = 0;
|
|
|
|
p.loops = dwLoops;
|
|
|
|
p.flags = dwFlags;
|
|
|
|
expectedTrueCount = dwLoops;
|
|
|
|
expectedFalseCount = dwLoops * (dwThreads - 1);
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: >> Testing with flags 0x%08"PRIx32". Using %"PRIu32" threads performing %"PRIu32" loops\n",
|
2016-08-10 11:29:59 +03:00
|
|
|
__FUNCTION__, dwFlags, dwThreads, dwLoops);
|
2016-06-06 16:33:16 +03:00
|
|
|
|
|
|
|
if (!(threads = calloc(dwThreads, sizeof(HANDLE))))
|
|
|
|
{
|
|
|
|
printf("%s: error allocatin thread array memory\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (!InitializeSynchronizationBarrier(&gBarrier, dwThreads, -1))
|
2015-04-28 18:00:41 +03:00
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
printf("%s: InitializeSynchronizationBarrier failed. GetLastError() = 0x%08x",
|
|
|
|
__FUNCTION__, GetLastError());
|
2016-06-06 16:33:16 +03:00
|
|
|
free(threads);
|
2016-06-03 19:56:36 +03:00
|
|
|
DeleteSynchronizationBarrier(&gBarrier);
|
2016-06-04 01:55:27 +03:00
|
|
|
return FALSE;
|
2015-04-28 18:00:41 +03:00
|
|
|
}
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
if (!(gStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
2014-08-09 01:34:30 +04:00
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
printf("%s: CreateEvent failed with error 0x%08x", __FUNCTION__,
|
|
|
|
GetLastError());
|
2016-06-06 16:33:16 +03:00
|
|
|
free(threads);
|
2016-06-03 19:56:36 +03:00
|
|
|
DeleteSynchronizationBarrier(&gBarrier);
|
2016-06-04 01:55:27 +03:00
|
|
|
return FALSE;
|
2016-06-03 19:56:36 +03:00
|
|
|
}
|
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
for (i = 0; i < dwThreads; i++)
|
2016-06-03 19:56:36 +03:00
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
if (!(threads[i] = CreateThread(NULL, 0, test_synch_barrier_thread, &p, 0,
|
2016-08-10 15:53:03 +03:00
|
|
|
NULL)))
|
2015-05-05 14:55:48 +03:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: CreateThread failed for thread #%"PRIu32" with error 0x%08x\n",
|
2016-08-10 11:29:59 +03:00
|
|
|
__FUNCTION__, i, GetLastError());
|
2016-06-03 19:56:36 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
break;
|
2015-05-05 14:55:48 +03:00
|
|
|
}
|
2016-06-03 19:56:36 +03:00
|
|
|
}
|
2015-05-21 09:32:51 +03:00
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
if (i > 0)
|
|
|
|
{
|
2016-06-04 14:40:01 +03:00
|
|
|
if (!SetEvent(gStartEvent))
|
|
|
|
{
|
|
|
|
printf("%s: SetEvent(gStartEvent) failed with error = 0x%08x)\n",
|
2016-08-10 11:29:59 +03:00
|
|
|
__FUNCTION__, GetLastError());
|
2016-06-04 14:40:01 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
}
|
2016-06-03 19:56:36 +03:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
while (i--)
|
2015-05-21 09:32:51 +03:00
|
|
|
{
|
2016-06-06 16:33:16 +03:00
|
|
|
if (WAIT_OBJECT_0 != (dwStatus = WaitForSingleObject(threads[i], INFINITE)))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: WaitForSingleObject(thread[%"PRIu32"] unexpectedly returned %"PRIu32" (error = 0x%08x)\n",
|
2016-08-10 11:29:59 +03:00
|
|
|
__FUNCTION__, i, dwStatus, GetLastError());
|
2016-06-06 16:33:16 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
}
|
2016-08-10 11:29:59 +03:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (!CloseHandle(threads[i]))
|
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: CloseHandle(thread[%"PRIu32"]) failed with error = 0x%08x)\n",
|
2016-08-10 11:29:59 +03:00
|
|
|
__FUNCTION__, i, GetLastError());
|
2016-06-06 16:33:16 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
}
|
2015-05-21 09:32:51 +03:00
|
|
|
}
|
2014-08-09 01:34:30 +04:00
|
|
|
}
|
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
free(threads);
|
|
|
|
|
2016-06-04 14:40:01 +03:00
|
|
|
if (!CloseHandle(gStartEvent))
|
|
|
|
{
|
|
|
|
printf("%s: CloseHandle(gStartEvent) failed with error = 0x%08x)\n",
|
2016-08-10 11:29:59 +03:00
|
|
|
__FUNCTION__, GetLastError());
|
2016-06-04 14:40:01 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
}
|
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
DeleteSynchronizationBarrier(&gBarrier);
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (p.threadCount != dwThreads)
|
2016-06-03 19:56:36 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (p.trueCount != expectedTrueCount)
|
2016-06-03 19:56:36 +03:00
|
|
|
InterlockedIncrement(&gErrorCount);
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (p.falseCount != expectedFalseCount)
|
|
|
|
InterlockedIncrement(&gErrorCount);
|
|
|
|
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: error count: %"PRId32"\n", __FUNCTION__, gErrorCount);
|
|
|
|
printf("%s: thread count: %"PRId32" (expected %"PRIu32")\n", __FUNCTION__, p.threadCount,
|
2016-08-10 11:29:59 +03:00
|
|
|
dwThreads);
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: true count: %"PRId32" (expected %"PRIu32")\n", __FUNCTION__, p.trueCount,
|
2016-08-10 11:29:59 +03:00
|
|
|
expectedTrueCount);
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: false count: %"PRId32" (expected %"PRIu32")\n", __FUNCTION__, p.falseCount,
|
2016-08-10 11:29:59 +03:00
|
|
|
expectedFalseCount);
|
2014-08-09 01:34:30 +04:00
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
if (gErrorCount > 0)
|
2014-08-09 01:34:30 +04:00
|
|
|
{
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: Error test failed with %"PRId32" reported errors\n", __FUNCTION__,
|
2016-08-10 11:29:59 +03:00
|
|
|
gErrorCount);
|
2016-06-04 01:55:27 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int TestSynchBarrier(int argc, char* argv[])
|
|
|
|
{
|
2016-06-06 16:33:16 +03:00
|
|
|
SYSTEM_INFO sysinfo;
|
|
|
|
DWORD dwMaxThreads;
|
|
|
|
DWORD dwMinThreads;
|
|
|
|
DWORD dwNumLoops = 200;
|
|
|
|
GetNativeSystemInfo(&sysinfo);
|
2016-12-14 00:47:08 +03:00
|
|
|
printf("%s: Number of processors: %"PRIu32"\n", __FUNCTION__,
|
2016-08-10 11:29:59 +03:00
|
|
|
sysinfo.dwNumberOfProcessors);
|
2016-06-06 16:33:16 +03:00
|
|
|
dwMinThreads = sysinfo.dwNumberOfProcessors;
|
|
|
|
dwMaxThreads = sysinfo.dwNumberOfProcessors * 4;
|
2016-08-10 11:29:59 +03:00
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (dwMaxThreads > 32)
|
|
|
|
dwMaxThreads = 32;
|
|
|
|
|
2016-06-04 01:55:27 +03:00
|
|
|
/* Test invalid parameters */
|
|
|
|
if (InitializeSynchronizationBarrier(&gBarrier, 0, -1))
|
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = 0\n",
|
|
|
|
__FUNCTION__);
|
2016-06-04 01:55:27 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InitializeSynchronizationBarrier(&gBarrier, -1, -1))
|
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lTotalThreads = -1\n",
|
|
|
|
__FUNCTION__);
|
2016-06-04 01:55:27 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InitializeSynchronizationBarrier(&gBarrier, 1, -2))
|
|
|
|
{
|
2016-08-10 11:29:59 +03:00
|
|
|
printf("%s: InitializeSynchronizationBarrier unecpectedly succeeded with lSpinCount = -2\n",
|
|
|
|
__FUNCTION__);
|
2016-06-03 19:56:36 +03:00
|
|
|
return -1;
|
2014-08-09 01:34:30 +04:00
|
|
|
}
|
|
|
|
|
2016-06-04 01:55:27 +03:00
|
|
|
/* Functional tests */
|
|
|
|
|
2016-06-06 16:33:16 +03:00
|
|
|
if (!TestSynchBarrierWithFlags(0, dwMaxThreads, dwNumLoops))
|
2016-06-04 01:55:27 +03:00
|
|
|
return -1;
|
|
|
|
|
2016-08-10 11:29:59 +03:00
|
|
|
if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY,
|
2016-08-10 15:53:03 +03:00
|
|
|
dwMinThreads, dwNumLoops))
|
2016-06-04 01:55:27 +03:00
|
|
|
return -1;
|
|
|
|
|
2016-08-10 11:29:59 +03:00
|
|
|
if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY,
|
2016-08-10 15:53:03 +03:00
|
|
|
dwMaxThreads, dwNumLoops))
|
2016-06-04 01:55:27 +03:00
|
|
|
return -1;
|
|
|
|
|
2016-06-03 19:56:36 +03:00
|
|
|
printf("%s: Test successfully completed\n", __FUNCTION__);
|
2014-08-09 01:34:30 +04:00
|
|
|
return 0;
|
|
|
|
}
|