diff options
Diffstat (limited to '')
-rw-r--r-- | winpr/libwinpr/synch/test/TestSynchMutex.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/winpr/libwinpr/synch/test/TestSynchMutex.c b/winpr/libwinpr/synch/test/TestSynchMutex.c new file mode 100644 index 0000000..296c371 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchMutex.c @@ -0,0 +1,258 @@ + +#include <winpr/crt.h> +#include <winpr/synch.h> +#include <winpr/thread.h> + +static BOOL test_mutex_basic(void) +{ + HANDLE mutex = NULL; + DWORD rc = 0; + + if (!(mutex = CreateMutex(NULL, FALSE, NULL))) + { + printf("%s: CreateMutex failed\n", __func__); + return FALSE; + } + + rc = WaitForSingleObject(mutex, INFINITE); + + if (rc != WAIT_OBJECT_0) + { + printf("%s: WaitForSingleObject on mutex failed with %" PRIu32 "\n", __func__, rc); + return FALSE; + } + + if (!ReleaseMutex(mutex)) + { + printf("%s: ReleaseMutex failed\n", __func__); + return FALSE; + } + + if (ReleaseMutex(mutex)) + { + printf("%s: ReleaseMutex unexpectedly succeeded on released mutex\n", __func__); + return FALSE; + } + + if (!CloseHandle(mutex)) + { + printf("%s: CloseHandle on mutex failed\n", __func__); + return FALSE; + } + + return TRUE; +} + +static BOOL test_mutex_recursive(void) +{ + HANDLE mutex = NULL; + DWORD rc = 0; + DWORD cnt = 50; + + if (!(mutex = CreateMutex(NULL, TRUE, NULL))) + { + printf("%s: CreateMutex failed\n", __func__); + return FALSE; + } + + for (UINT32 i = 0; i < cnt; i++) + { + rc = WaitForSingleObject(mutex, INFINITE); + + if (rc != WAIT_OBJECT_0) + { + printf("%s: WaitForSingleObject #%" PRIu32 " on mutex failed with %" PRIu32 "\n", + __func__, i, rc); + return FALSE; + } + } + + for (UINT32 i = 0; i < cnt; i++) + { + if (!ReleaseMutex(mutex)) + { + printf("%s: ReleaseMutex #%" PRIu32 " failed\n", __func__, i); + return FALSE; + } + } + + if (!ReleaseMutex(mutex)) + { + /* Note: The mutex was initially owned ! */ + printf("%s: Final ReleaseMutex failed\n", __func__); + return FALSE; + } + + if (ReleaseMutex(mutex)) + { + printf("%s: ReleaseMutex unexpectedly succeeded on released mutex\n", __func__); + return FALSE; + } + + if (!CloseHandle(mutex)) + { + printf("%s: CloseHandle on mutex failed\n", __func__); + return FALSE; + } + + return TRUE; +} + +static HANDLE thread1_mutex1 = NULL; +static HANDLE thread1_mutex2 = NULL; +static BOOL thread1_failed = TRUE; + +static DWORD WINAPI test_mutex_thread1(LPVOID lpParam) +{ + HANDLE hStartEvent = (HANDLE)lpParam; + DWORD rc = 0; + + if (WaitForSingleObject(hStartEvent, INFINITE) != WAIT_OBJECT_0) + { + fprintf(stderr, "%s: failed to wait for start event\n", __func__); + return 0; + } + + /** + * at this point: + * thread1_mutex1 is expected to be locked + * thread1_mutex2 is expected to be unlocked + * defined task: + * try to lock thread1_mutex1 (expected to fail) + * lock and unlock thread1_mutex2 (expected to work) + */ + rc = WaitForSingleObject(thread1_mutex1, 10); + + if (rc != WAIT_TIMEOUT) + { + fprintf(stderr, + "%s: WaitForSingleObject on thread1_mutex1 unexpectedly returned %" PRIu32 + " instead of WAIT_TIMEOUT (%u)\n", + __func__, rc, WAIT_TIMEOUT); + return 0; + } + + rc = WaitForSingleObject(thread1_mutex2, 10); + + if (rc != WAIT_OBJECT_0) + { + fprintf(stderr, + "%s: WaitForSingleObject on thread1_mutex2 unexpectedly returned %" PRIu32 + " instead of WAIT_OBJECT_0\n", + __func__, rc); + return 0; + } + + if (!ReleaseMutex(thread1_mutex2)) + { + fprintf(stderr, "%s: ReleaseMutex failed on thread1_mutex2\n", __func__); + return 0; + } + + thread1_failed = FALSE; + return 0; +} + +static BOOL test_mutex_threading(void) +{ + HANDLE hThread = NULL; + HANDLE hStartEvent = NULL; + + if (!(thread1_mutex1 = CreateMutex(NULL, TRUE, NULL))) + { + printf("%s: CreateMutex thread1_mutex1 failed\n", __func__); + goto fail; + } + + if (!(thread1_mutex2 = CreateMutex(NULL, FALSE, NULL))) + { + printf("%s: CreateMutex thread1_mutex2 failed\n", __func__); + goto fail; + } + + if (!(hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + fprintf(stderr, "%s: error creating start event\n", __func__); + goto fail; + } + + thread1_failed = TRUE; + + if (!(hThread = CreateThread(NULL, 0, test_mutex_thread1, (LPVOID)hStartEvent, 0, NULL))) + { + fprintf(stderr, "%s: error creating test_mutex_thread_1\n", __func__); + goto fail; + } + + Sleep(100); + + if (!thread1_failed) + { + fprintf(stderr, "%s: thread1 premature success\n", __func__); + goto fail; + } + + SetEvent(hStartEvent); + + if (WaitForSingleObject(hThread, 2000) != WAIT_OBJECT_0) + { + fprintf(stderr, "%s: thread1 premature success\n", __func__); + goto fail; + } + + if (thread1_failed) + { + fprintf(stderr, "%s: thread1 has not reported success\n", __func__); + goto fail; + } + + /** + * - thread1 must not have succeeded to lock thread1_mutex1 + * - thread1 must have locked and unlocked thread1_mutex2 + */ + + if (!ReleaseMutex(thread1_mutex1)) + { + printf("%s: ReleaseMutex unexpectedly failed on thread1_mutex1\n", __func__); + goto fail; + } + + if (ReleaseMutex(thread1_mutex2)) + { + printf("%s: ReleaseMutex unexpectedly succeeded on thread1_mutex2\n", __func__); + goto fail; + } + + CloseHandle(hThread); + CloseHandle(hStartEvent); + CloseHandle(thread1_mutex1); + CloseHandle(thread1_mutex2); + return TRUE; +fail: + ReleaseMutex(thread1_mutex1); + ReleaseMutex(thread1_mutex2); + CloseHandle(thread1_mutex1); + CloseHandle(thread1_mutex2); + CloseHandle(hStartEvent); + CloseHandle(hThread); + return FALSE; +} + +int TestSynchMutex(int argc, char* argv[]) +{ + int rc = 0; + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + if (!test_mutex_basic()) + rc += 1; + + if (!test_mutex_recursive()) + rc += 2; + + if (!test_mutex_threading()) + rc += 4; + + printf("TestSynchMutex result %d\n", rc); + return rc; +} |