#include <winpr/crt.h>
+#include <winpr/sysinfo.h>
+
#include <winpr/synch.h>
-HANDLE gDoneEvent;
+#define FIRE_COUNT 5
+#define TIMER_COUNT 4
+
+static int g_Count = 0;
+static HANDLE g_Event = NULL;
+
+struct apc_data
+{
+ int TimerId;
+ UINT32 StartTime;
+};
+typedef struct apc_data APC_DATA;
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
- int param;
+ UINT32 TimerTime;
+ APC_DATA* apcData;
+ UINT32 CurrentTime = GetTickCount();
if (!lpParam)
return;
- param = *((int*) lpParam);
+ apcData = (APC_DATA*) lpParam;
+
+ TimerTime = CurrentTime - apcData->StartTime;
+
+ printf("TimerRoutine: TimerId: %d Time: %d Discrepancy: %d\n",
+ apcData->TimerId, TimerTime, TimerTime % 100);
- printf("TimerRoutine: Param: %d TimerOrWaitFired: %d\n", param, TimerOrWaitFired);
+ g_Count++;
- SetEvent(gDoneEvent);
+ if (g_Count >= (TIMER_COUNT * FIRE_COUNT))
+ {
+ SetEvent(g_Event);
+ }
}
int TestSynchTimerQueue(int argc, char* argv[])
{
- int arg = 123;
+ int index;
+ DWORD DueTime;
+ DWORD Period;
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
+ APC_DATA apcData[TIMER_COUNT];
- gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ g_Event = CreateEvent(NULL, TRUE, FALSE, NULL);
hTimerQueue = CreateTimerQueue();
return -1;
}
- if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK) TimerRoutine, &arg , 1000, 0, 0))
+ for (index = 0; index < TIMER_COUNT; index++)
{
- printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
- return -1;
+ apcData[index].TimerId = index;
+ apcData[index].StartTime = GetTickCount();
+
+ DueTime = (index * 100) + 500;
+ Period = 1000;
+
+ if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK) TimerRoutine,
+ &apcData[index], DueTime, Period, 0))
+ {
+ printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
+ return -1;
+ }
}
- if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
+ if (WaitForSingleObject(g_Event, INFINITE) != WAIT_OBJECT_0)
{
printf("WaitForSingleObject failed (%d)\n", GetLastError());
return -1;
}
- CloseHandle(gDoneEvent);
-
if (!DeleteTimerQueueTimer(hTimerQueue, hTimer, NULL))
{
printf("DeleteTimerQueueTimer failed (%d)\n", GetLastError());
return -1;
}
+ CloseHandle(g_Event);
+
return 0;
}
#endif
#include <winpr/crt.h>
+#include <winpr/sysinfo.h>
#include <winpr/synch.h>
* http://www.cs.wustl.edu/~schmidt/Timer_Queue.html
*/
-static void* TimerQueueThread(void* arg)
-{
- //WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*) arg;
-
- return NULL;
-}
-
-int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
-{
- pthread_cond_init(&(timerQueue->cond), NULL);
- pthread_mutex_init(&(timerQueue->mutex), NULL);
-
- pthread_attr_init(&(timerQueue->attr));
- timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param));
- pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO);
- pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue);
-
- return 0;
-}
-
int InsertTimerQueueTimer(WINPR_TIMER_QUEUE* timerQueue, WINPR_TIMER_QUEUE_TIMER* timer)
{
WINPR_TIMER_QUEUE_TIMER* node;
node = timerQueue->head;
- do
+ while (node->next)
{
node = node->next;
}
- while (node->next);
node->next = timer;
timer->prev = node;
return 0;
}
+int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue)
+{
+ UINT64 currentTime;
+ WINPR_TIMER_QUEUE_TIMER* node;
+
+ if (!timerQueue->head)
+ return 0;
+
+ currentTime = GetTickCount64();
+
+ node = timerQueue->head;
+
+ while (node)
+ {
+ if (currentTime >= node->ExpirationTime)
+ {
+ node->Callback(node->Parameter, TRUE);
+ node->FireCount++;
+
+ if (node->Period)
+ {
+ node->ExpirationTime = node->StartTime + (node->FireCount * node->Period);
+ }
+ }
+
+ node = node->next;
+ }
+
+ return 0;
+}
+
+static void* TimerQueueThread(void* arg)
+{
+ WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*) arg;
+
+ while (1)
+ {
+ FireExpiredTimerQueueTimers(timerQueue);
+ Sleep(timerQueue->resolution);
+ }
+
+ return NULL;
+}
+
+int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
+{
+ pthread_cond_init(&(timerQueue->cond), NULL);
+ pthread_mutex_init(&(timerQueue->mutex), NULL);
+
+ pthread_attr_init(&(timerQueue->attr));
+ timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param));
+ pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO);
+ pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue);
+
+ return 0;
+}
+
HANDLE CreateTimerQueue(void)
{
HANDLE handle = NULL;
WINPR_HANDLE_SET_TYPE(timerQueue, HANDLE_TYPE_TIMER_QUEUE);
handle = (HANDLE) timerQueue;
+ timerQueue->resolution = 5;
+
StartTimerQueueThread(timerQueue);
}
return handle;
}
-BOOL DeleteTimerQueue(HANDLE TimerQueue)
+BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
{
WINPR_TIMER_QUEUE* timerQueue;
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
+ pthread_cond_destroy(&(timerQueue->cond));
+ pthread_mutex_destroy(&(timerQueue->mutex));
+
free(timerQueue);
return TRUE;
}
-BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
+BOOL DeleteTimerQueue(HANDLE TimerQueue)
{
- WINPR_TIMER_QUEUE* timerQueue;
-
- if (!TimerQueue)
- return FALSE;
-
- timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
-
- free(timerQueue);
-
- return TRUE;
+ return DeleteTimerQueueEx(TimerQueue, NULL);
}
BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue,
WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
{
+ UINT64 currentTime;
WINPR_TIMER_QUEUE* timerQueue;
WINPR_TIMER_QUEUE_TIMER* timer;
+ currentTime = GetTickCount64();
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
timer = (WINPR_TIMER_QUEUE_TIMER*) malloc(sizeof(WINPR_TIMER_QUEUE_TIMER));
- if (timer || !TimerQueue)
+ if (!timer || !TimerQueue)
return FALSE;
WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER);
timer->timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
+ timer->FireCount = 0;
+ timer->StartTime = currentTime + DueTime;
+ timer->ExpirationTime = timer->StartTime;
+
+ InsertTimerQueueTimer(timerQueue, timer);
+
return TRUE;
}