summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/synch/test/TestSynchTimerQueue.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--winpr/libwinpr/synch/test/TestSynchTimerQueue.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/winpr/libwinpr/synch/test/TestSynchTimerQueue.c b/winpr/libwinpr/synch/test/TestSynchTimerQueue.c
new file mode 100644
index 0000000..08cc957
--- /dev/null
+++ b/winpr/libwinpr/synch/test/TestSynchTimerQueue.c
@@ -0,0 +1,125 @@
+
+#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;
+
+static VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
+{
+ UINT32 TimerTime = 0;
+ APC_DATA* apcData = NULL;
+ UINT32 expectedTime = 0;
+ UINT32 CurrentTime = GetTickCount();
+
+ WINPR_UNUSED(TimerOrWaitFired);
+
+ if (!lpParam)
+ return;
+
+ apcData = (APC_DATA*)lpParam;
+
+ TimerTime = CurrentTime - apcData->StartTime;
+ expectedTime = apcData->DueTime + (apcData->Period * apcData->FireCount);
+
+ apcData->FireCount++;
+
+ printf("TimerRoutine: TimerId: %" PRIu32 " FireCount: %" PRIu32 " ActualTime: %" PRIu32
+ " ExpectedTime: %" PRIu32 " Discrepancy: %" PRIu32 "\n",
+ apcData->TimerId, apcData->FireCount, TimerTime, expectedTime, TimerTime - expectedTime);
+
+ Sleep(11);
+
+ if (apcData->FireCount == apcData->MaxFireCount)
+ {
+ SetEvent(apcData->CompletionEvent);
+ }
+}
+
+int TestSynchTimerQueue(int argc, char* argv[])
+{
+ HANDLE hTimerQueue = NULL;
+ HANDLE hTimers[TIMER_COUNT];
+ APC_DATA apcData[TIMER_COUNT];
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ hTimerQueue = CreateTimerQueue();
+
+ if (!hTimerQueue)
+ {
+ printf("CreateTimerQueue failed (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+
+ for (DWORD index = 0; index < TIMER_COUNT; index++)
+ {
+ apcData[index].TimerId = index;
+ apcData[index].StartTime = GetTickCount();
+ apcData[index].DueTime = (index * 10) + 50;
+ apcData[index].Period = 100;
+ apcData[index].FireCount = 0;
+ apcData[index].MaxFireCount = FIRE_COUNT;
+
+ if (!(apcData[index].CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
+ {
+ printf("Failed to create apcData[%" PRIu32 "] event (%" PRIu32 ")\n", index,
+ GetLastError());
+ return -1;
+ }
+
+ if (!CreateTimerQueueTimer(&hTimers[index], hTimerQueue, TimerRoutine, &apcData[index],
+ apcData[index].DueTime, apcData[index].Period, 0))
+ {
+ printf("CreateTimerQueueTimer failed (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+ }
+
+ for (DWORD index = 0; index < TIMER_COUNT; index++)
+ {
+ if (WaitForSingleObject(apcData[index].CompletionEvent, 2000) != WAIT_OBJECT_0)
+ {
+ printf("Failed to wait for timer queue timer #%" PRIu32 " (%" PRIu32 ")\n", index,
+ GetLastError());
+ return -1;
+ }
+ }
+
+ for (DWORD 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 (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+ CloseHandle(apcData[index].CompletionEvent);
+ }
+
+ if (!DeleteTimerQueue(hTimerQueue))
+ {
+ printf("DeleteTimerQueue failed (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+
+ return 0;
+}