#include #include #include #include #define THREADS 8 static DWORD WINAPI test_thread(LPVOID arg) { long timeout = 50 + (rand() % 100); WINPR_UNUSED(arg); Sleep(timeout); ExitThread(0); return 0; } static int start_threads(size_t count, HANDLE* threads) { for (size_t i = 0; i < count; i++) { threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL); if (!threads[i]) { fprintf(stderr, "%s: CreateThread [%" PRIuz "] failure\n", __func__, i); return -1; } } for (size_t i = 0; i < count; i++) ResumeThread(threads[i]); return 0; } static int close_threads(DWORD count, HANDLE* threads) { int rc = 0; for (DWORD i = 0; i < count; i++) { if (!threads[i]) continue; if (!CloseHandle(threads[i])) { fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __func__, i); rc = -1; } threads[i] = NULL; } return rc; } static BOOL TestWaitForAll(void) { BOOL rc = FALSE; HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: start_threads failed\n", __func__); goto fail; } const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, 10); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 10 failed, ret=%d\n", __func__, ret); goto fail; } if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__); goto fail; } rc = TRUE; fail: if (close_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: close_threads failed\n", __func__); return FALSE; } return rc; } static BOOL TestWaitOne(void) { BOOL rc = FALSE; HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: start_threads failed\n", __func__); goto fail; } const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, FALSE, INFINITE); if (ret > (WAIT_OBJECT_0 + ARRAYSIZE(threads))) { fprintf(stderr, "%s: WaitForMultipleObjects INFINITE failed\n", __func__); goto fail; } if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__); goto fail; } rc = TRUE; fail: if (close_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: close_threads failed\n", __func__); return FALSE; } return rc; } static BOOL TestWaitOneTimeout(void) { BOOL rc = FALSE; HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: start_threads failed\n", __func__); goto fail; } const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, FALSE, 1); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __func__, ret); goto fail; } if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__); goto fail; } rc = TRUE; fail: if (close_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: close_threads failed\n", __func__); return FALSE; } return rc; } static BOOL TestWaitOneTimeoutMultijoin(void) { BOOL rc = FALSE; HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: start_threads failed\n", __func__); goto fail; } for (size_t i = 0; i < ARRAYSIZE(threads); i++) { const DWORD ret = WaitForMultipleObjects(ARRAYSIZE(threads), threads, FALSE, 0); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __func__, ret); goto fail; } } if (WaitForMultipleObjects(ARRAYSIZE(threads), threads, TRUE, INFINITE) != WAIT_OBJECT_0) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __func__); goto fail; } rc = TRUE; fail: if (close_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: close_threads failed\n", __func__); return FALSE; } return rc; } static BOOL TestDetach(void) { BOOL rc = FALSE; HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: start_threads failed\n", __func__); goto fail; } rc = TRUE; fail: if (close_threads(ARRAYSIZE(threads), threads)) { fprintf(stderr, "%s: close_threads failed\n", __func__); return FALSE; } return rc; } 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; return 0; }