Blame winpr/libwinpr/synch/test/TestSynchMutex.c

Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/thread.h>
Packit 1fb8d4
Packit 1fb8d4
static BOOL test_mutex_basic(void)
Packit 1fb8d4
{
Packit 1fb8d4
	HANDLE mutex;
Packit 1fb8d4
	DWORD rc;
Packit 1fb8d4
Packit 1fb8d4
	if (!(mutex = CreateMutex(NULL, FALSE, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: CreateMutex failed\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rc = WaitForSingleObject(mutex, INFINITE);
Packit Service 5a9772
Packit 1fb8d4
	if (rc != WAIT_OBJECT_0)
Packit 1fb8d4
	{
Packit Service 5a9772
		printf("%s: WaitForSingleObject on mutex failed with %" PRIu32 "\n", __FUNCTION__, rc);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!ReleaseMutex(mutex))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: ReleaseMutex failed\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (ReleaseMutex(mutex))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: ReleaseMutex unexpectedly succeeded on released mutex\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!CloseHandle(mutex))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: CloseHandle on mutex failed\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL test_mutex_recursive(void)
Packit 1fb8d4
{
Packit 1fb8d4
	HANDLE mutex;
Packit 1fb8d4
	DWORD rc, i, cnt = 50;
Packit 1fb8d4
Packit 1fb8d4
	if (!(mutex = CreateMutex(NULL, TRUE, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: CreateMutex failed\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < cnt; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		rc = WaitForSingleObject(mutex, INFINITE);
Packit Service 5a9772
Packit 1fb8d4
		if (rc != WAIT_OBJECT_0)
Packit 1fb8d4
		{
Packit Service 5a9772
			printf("%s: WaitForSingleObject #%" PRIu32 " on mutex failed with %" PRIu32 "\n",
Packit Service 5a9772
			       __FUNCTION__, i, rc);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < cnt; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!ReleaseMutex(mutex))
Packit 1fb8d4
		{
Packit Service 5a9772
			printf("%s: ReleaseMutex #%" PRIu32 " failed\n", __FUNCTION__, i);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!ReleaseMutex(mutex))
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Note: The mutex was initially owned ! */
Packit 1fb8d4
		printf("%s: Final ReleaseMutex failed\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (ReleaseMutex(mutex))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: ReleaseMutex unexpectedly succeeded on released mutex\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!CloseHandle(mutex))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: CloseHandle on mutex failed\n", __FUNCTION__);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static HANDLE thread1_mutex1 = NULL;
Packit 1fb8d4
static HANDLE thread1_mutex2 = NULL;
Packit Service 5a9772
static BOOL thread1_failed = TRUE;
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI test_mutex_thread1(LPVOID lpParam)
Packit 1fb8d4
{
Packit 1fb8d4
	HANDLE hStartEvent = (HANDLE)lpParam;
Packit 1fb8d4
	DWORD rc = 0;
Packit Service 5a9772
Packit 1fb8d4
	if (WaitForSingleObject(hStartEvent, INFINITE) != WAIT_OBJECT_0)
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "%s: failed to wait for start event\n", __FUNCTION__);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * at this point:
Packit 1fb8d4
	 * thread1_mutex1 is expected to be locked
Packit 1fb8d4
	 * thread1_mutex2 is expected to be unlocked
Packit 1fb8d4
	 * defined task:
Packit 1fb8d4
	 * try to lock thread1_mutex1 (expected to fail)
Packit 1fb8d4
	 * lock and unlock thread1_mutex2 (expected to work)
Packit 1fb8d4
	 */
Packit 1fb8d4
	rc = WaitForSingleObject(thread1_mutex1, 10);
Packit Service 5a9772
Packit 1fb8d4
	if (rc != WAIT_TIMEOUT)
Packit 1fb8d4
	{
Packit Service 5a9772
		fprintf(stderr,
Packit Service 5a9772
		        "%s: WaitForSingleObject on thread1_mutex1 unexpectedly returned %" PRIu32
Packit Service 5a9772
		        " instead of WAIT_TIMEOUT (%u)\n",
Packit Service 5a9772
		        __FUNCTION__, rc, WAIT_TIMEOUT);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rc = WaitForSingleObject(thread1_mutex2, 10);
Packit Service 5a9772
Packit 1fb8d4
	if (rc != WAIT_OBJECT_0)
Packit 1fb8d4
	{
Packit Service 5a9772
		fprintf(stderr,
Packit Service 5a9772
		        "%s: WaitForSingleObject on thread1_mutex2 unexpectedly returned %" PRIu32
Packit Service 5a9772
		        " instead of WAIT_OBJECT_0\n",
Packit Service 5a9772
		        __FUNCTION__, rc);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!ReleaseMutex(thread1_mutex2))
Packit Service 5a9772
	{
Packit Service 5a9772
		fprintf(stderr, "%s: ReleaseMutex failed on thread1_mutex2\n", __FUNCTION__);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	thread1_failed = FALSE;
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL test_mutex_threading(void)
Packit 1fb8d4
{
Packit 1fb8d4
	HANDLE hThread = NULL;
Packit 1fb8d4
	HANDLE hStartEvent = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!(thread1_mutex1 = CreateMutex(NULL, TRUE, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: CreateMutex thread1_mutex1 failed\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(thread1_mutex2 = CreateMutex(NULL, FALSE, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: CreateMutex thread1_mutex2 failed\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "%s: error creating start event\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	thread1_failed = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (!(hThread = CreateThread(NULL, 0, test_mutex_thread1, (LPVOID)hStartEvent, 0, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "%s: error creating test_mutex_thread_1\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Sleep(100);
Packit 1fb8d4
Packit 1fb8d4
	if (!thread1_failed)
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "%s: thread1 premature success\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SetEvent(hStartEvent);
Packit 1fb8d4
Packit 1fb8d4
	if (WaitForSingleObject(hThread, 2000) != WAIT_OBJECT_0)
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "%s: thread1 premature success\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (thread1_failed)
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "%s: thread1 has not reported success\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/**
Packit 1fb8d4
	 * - thread1 must not have succeeded to lock thread1_mutex1
Packit 1fb8d4
	 * - thread1 must have locked and unlocked thread1_mutex2
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	if (!ReleaseMutex(thread1_mutex1))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: ReleaseMutex unexpectedly failed on thread1_mutex1\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (ReleaseMutex(thread1_mutex2))
Packit 1fb8d4
	{
Packit 1fb8d4
		printf("%s: ReleaseMutex unexpectedly succeeded on thread1_mutex2\n", __FUNCTION__);
Packit 1fb8d4
		goto fail;
Packit Service 5a9772
	}
Packit 1fb8d4
Packit 1fb8d4
	CloseHandle(hThread);
Packit 1fb8d4
	CloseHandle(hStartEvent);
Packit 1fb8d4
	CloseHandle(thread1_mutex1);
Packit 1fb8d4
	CloseHandle(thread1_mutex2);
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
fail:
Packit 1fb8d4
	ReleaseMutex(thread1_mutex1);
Packit 1fb8d4
	ReleaseMutex(thread1_mutex2);
Packit 1fb8d4
	CloseHandle(thread1_mutex1);
Packit 1fb8d4
	CloseHandle(thread1_mutex2);
Packit 1fb8d4
	CloseHandle(hStartEvent);
Packit 1fb8d4
	CloseHandle(hThread);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int TestSynchMutex(int argc, char* argv[])
Packit 1fb8d4
{
Packit Service 5a9772
	int rc = 0;
Packit Service 5a9772
	WINPR_UNUSED(argc);
Packit Service 5a9772
	WINPR_UNUSED(argv);
Packit Service 5a9772
Packit 1fb8d4
	if (!test_mutex_basic())
Packit Service 5a9772
		rc += 1;
Packit 1fb8d4
Packit 1fb8d4
	if (!test_mutex_recursive())
Packit Service 5a9772
		rc += 2;
Packit 1fb8d4
Packit 1fb8d4
	if (!test_mutex_threading())
Packit Service 5a9772
		rc += 4;
Packit 1fb8d4
Packit Service 5a9772
	printf("TestSynchMutex result %d\n", rc);
Packit Service 5a9772
	return rc;
Packit 1fb8d4
}