|
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 |
}
|