2014-07-16 13:58:45 +04:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <winpr/synch.h>
|
|
|
|
#include <winpr/thread.h>
|
|
|
|
|
2021-06-16 15:43:07 +03:00
|
|
|
#define THREADS 8
|
2021-04-27 12:21:16 +03:00
|
|
|
|
2018-03-07 14:03:10 +03:00
|
|
|
static DWORD WINAPI test_thread(LPVOID arg)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-06-02 16:46:27 +03:00
|
|
|
long timeout = 30 + (rand() % 100);
|
2021-04-27 12:21:16 +03:00
|
|
|
WINPR_UNUSED(arg);
|
2014-07-16 13:58:45 +04:00
|
|
|
Sleep(timeout);
|
|
|
|
ExitThread(0);
|
2018-03-07 14:03:10 +03:00
|
|
|
return 0;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static int start_threads(DWORD count, HANDLE* threads)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
for (i = 0; i < count; i++)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-06-16 15:43:07 +03:00
|
|
|
threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL);
|
2014-07-16 13:58:45 +04:00
|
|
|
|
|
|
|
if (!threads[i])
|
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: CreateThread [%" PRIu32 "] failure\n", __FUNCTION__, i);
|
2014-07-16 13:58:45 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-16 15:43:07 +03:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
ResumeThread(threads[i]);
|
2014-07-16 13:58:45 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static int close_threads(DWORD count, HANDLE* threads)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
for (i = 0; i < count; i++)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
|
|
|
if (!CloseHandle(threads[i]))
|
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __FUNCTION__, i);
|
2014-07-16 13:58:45 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
static BOOL TestWaitForAll(void)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
BOOL rc = FALSE;
|
2021-03-24 20:32:43 +03:00
|
|
|
DWORD ret;
|
2021-04-27 13:19:06 +03:00
|
|
|
HANDLE threads[THREADS] = { 0 };
|
2014-07-16 13:58:45 +04:00
|
|
|
/* WaitForAll, timeout */
|
|
|
|
if (start_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-06-02 16:46:27 +03:00
|
|
|
ret = WaitForMultipleObjects(THREADS, threads, TRUE, 10);
|
2021-03-24 20:32:43 +03:00
|
|
|
if (ret != WAIT_TIMEOUT)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 50 failed, ret=%d\n",
|
|
|
|
__FUNCTION__, ret);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
|
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (close_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
rc = TRUE;
|
|
|
|
fail:
|
|
|
|
return rc;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
static BOOL TestWaitOne(void)
|
|
|
|
{
|
|
|
|
BOOL rc = FALSE;
|
|
|
|
DWORD ret;
|
2021-04-27 13:19:06 +03:00
|
|
|
HANDLE threads[THREADS] = { 0 };
|
2021-04-27 12:21:16 +03:00
|
|
|
/* WaitForAll, timeout */
|
2014-07-16 13:58:45 +04:00
|
|
|
if (start_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
ret = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE);
|
|
|
|
if (ret > (WAIT_OBJECT_0 + THREADS))
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects INFINITE failed\n", __FUNCTION__);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
|
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (close_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
rc = TRUE;
|
|
|
|
fail:
|
|
|
|
return rc;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
static BOOL TestWaitOneTimeout(void)
|
|
|
|
{
|
|
|
|
BOOL rc = FALSE;
|
|
|
|
DWORD ret;
|
2021-04-27 13:19:06 +03:00
|
|
|
HANDLE threads[THREADS] = { 0 };
|
2021-04-27 12:21:16 +03:00
|
|
|
/* WaitForAll, timeout */
|
2014-07-16 13:58:45 +04:00
|
|
|
if (start_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-06-16 15:43:07 +03:00
|
|
|
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 1);
|
2021-03-24 20:32:43 +03:00
|
|
|
if (ret != WAIT_TIMEOUT)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__,
|
|
|
|
ret);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
|
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (close_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
rc = TRUE;
|
|
|
|
fail:
|
|
|
|
return rc;
|
|
|
|
}
|
2017-03-28 17:18:00 +03:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
static BOOL TestWaitOneTimeoutMultijoin(void)
|
|
|
|
{
|
|
|
|
BOOL rc = FALSE;
|
|
|
|
DWORD ret, i;
|
2021-04-27 13:19:06 +03:00
|
|
|
HANDLE threads[THREADS] = { 0 };
|
2021-04-27 12:21:16 +03:00
|
|
|
/* WaitForAll, timeout */
|
2014-07-16 13:58:45 +04:00
|
|
|
if (start_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2017-07-10 16:29:09 +03:00
|
|
|
for (i = 0; i < THREADS; i++)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-03-24 20:32:43 +03:00
|
|
|
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 0);
|
|
|
|
if (ret != WAIT_TIMEOUT)
|
2014-07-16 13:58:45 +04:00
|
|
|
{
|
2021-05-25 09:23:24 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __FUNCTION__,
|
2021-04-27 12:21:16 +03:00
|
|
|
ret);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
|
|
|
|
{
|
2021-04-27 12:21:16 +03:00
|
|
|
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
|
|
|
|
goto fail;
|
2014-07-16 13:58:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (close_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
rc = TRUE;
|
|
|
|
fail:
|
|
|
|
return rc;
|
|
|
|
}
|
2017-03-28 17:18:00 +03:00
|
|
|
|
2021-04-27 12:21:16 +03:00
|
|
|
static BOOL TestDetach(void)
|
|
|
|
{
|
2021-04-27 13:19:06 +03:00
|
|
|
HANDLE threads[THREADS] = { 0 };
|
2021-04-27 12:21:16 +03:00
|
|
|
/* WaitForAll, timeout */
|
2014-07-16 13:58:45 +04:00
|
|
|
if (start_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-07-16 13:58:45 +04:00
|
|
|
|
|
|
|
if (close_threads(THREADS, threads))
|
2021-04-27 12:21:16 +03:00
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TestSynchMultipleThreads(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
WINPR_UNUSED(argc);
|
|
|
|
WINPR_UNUSED(argv);
|
|
|
|
|
|
|
|
if (!TestWaitForAll())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!TestWaitOne())
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
if (!TestWaitOneTimeout())
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
if (!TestWaitOneTimeoutMultijoin())
|
|
|
|
return -4;
|
|
|
|
|
|
|
|
if (!TestDetach())
|
|
|
|
return -5;
|
2014-07-16 13:58:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|