FreeRDP/winpr/libwinpr/synch/test/TestSynchTimerQueue.c
Norbert Federa e718fb324b fix race conditions, tests and some invalid return values
Since the current winpr implementation for overlapped operations is
incomplete and buggy, all affected functions will now fail if they are
called with a set FILE_FLAG_OVERLAPPED flag or a non-null pointer to
a OVERLAPPED structure.

winpr/nt:
- use proper one-time initialization on win32
- fix TestNtCreateFile
- fix broken/incomplete _RtlAnsiStringToUnicodeString
- unimplemented functions return appropriate error codes

winpr/pipe:
- improved TestPipeCreateNamedPipe
- rewrite the completely broken TestPipeCreateNamedPipeOverlapped test

rdtk:
- improve test and don't blindly return success

winpr/synch:
- fix race condition in TestSynchTimerQueue

winpr/ssspi:
- fix TestEnumerateSecurityPackages printf output
- fix TestQuerySecurityPackageInfo printf output

winpr/environment:
- fix GetEnvironmentStrings printf output

winpr/comm:
- unimplemented functions return appropriate error codes

winpr/io:
- unimplemented functions return appropriate error codes

winpr/thread:
- implement SwitchToThread() via sched_yield()
2016-06-01 16:26:26 +02:00

119 lines
2.8 KiB
C

#include <winpr/crt.h>
#include <winpr/sysinfo.h>
#include <winpr/file.h>
#include <winpr/synch.h>
#define FIRE_COUNT 5
#define TIMER_COUNT 5
struct apc_data
{
DWORD TimerId;
DWORD FireCount;
DWORD DueTime;
DWORD Period;
UINT32 StartTime;
DWORD MaxFireCount;
HANDLE CompletionEvent;
};
typedef struct apc_data APC_DATA;
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
UINT32 TimerTime;
APC_DATA* apcData;
UINT32 expectedTime;
UINT32 CurrentTime = GetTickCount();
if (!lpParam)
return;
apcData = (APC_DATA*) lpParam;
TimerTime = CurrentTime - apcData->StartTime;
expectedTime = apcData->DueTime + (apcData->Period * apcData->FireCount);
apcData->FireCount++;
printf("TimerRoutine: TimerId: %d FireCount: %d ActualTime: %d ExpectedTime: %d Discrepancy: %d\n",
apcData->TimerId, apcData->FireCount, TimerTime, expectedTime, TimerTime - expectedTime);
Sleep(50);
if (apcData->FireCount == apcData->MaxFireCount)
{
SetEvent(apcData->CompletionEvent);
}
}
int TestSynchTimerQueue(int argc, char* argv[])
{
DWORD index;
HANDLE hTimerQueue;
HANDLE hTimers[TIMER_COUNT];
APC_DATA apcData[TIMER_COUNT];
hTimerQueue = CreateTimerQueue();
if (!hTimerQueue)
{
printf("CreateTimerQueue failed (%u)\n", GetLastError());
return -1;
}
for (index = 0; index < TIMER_COUNT; index++)
{
apcData[index].TimerId = index;
apcData[index].StartTime = GetTickCount();
apcData[index].DueTime = (index * 100) + 500;
apcData[index].Period = 1000;
apcData[index].FireCount = 0;
apcData[index].MaxFireCount = FIRE_COUNT;
if (!(apcData[index].CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
{
printf("Failed to create apcData[%u] event (%u)\n", index, GetLastError());
return -1;
}
if (!CreateTimerQueueTimer(&hTimers[index], hTimerQueue, (WAITORTIMERCALLBACK) TimerRoutine,
&apcData[index], apcData[index].DueTime, apcData[index].Period, 0))
{
printf("CreateTimerQueueTimer failed (%u)\n", GetLastError());
return -1;
}
}
for (index = 0; index < TIMER_COUNT; index++)
{
if (WaitForSingleObject(apcData[index].CompletionEvent, 20000) != WAIT_OBJECT_0)
{
printf("Failed to wait for timer queue timer #%u (%u)\n", index, GetLastError());
return -1;
}
}
for (index = 0; index < TIMER_COUNT; index++)
{
/**
* Note: If the CompletionEvent parameter is INVALID_HANDLE_VALUE, the function waits
* for any running timer callback functions to complete before returning.
*/
if (!DeleteTimerQueueTimer(hTimerQueue, hTimers[index], INVALID_HANDLE_VALUE))
{
printf("DeleteTimerQueueTimer failed (%u)\n", GetLastError());
return -1;
}
CloseHandle(apcData[index].CompletionEvent);
}
if (!DeleteTimerQueue(hTimerQueue))
{
printf("DeleteTimerQueue failed (%u)\n", GetLastError());
return -1;
}
return 0;
}