#include <winpr/synch.h>
#define FIRE_COUNT 5
-#define TIMER_COUNT 4
+#define TIMER_COUNT 5
static int g_Count = 0;
static HANDLE g_Event = NULL;
struct apc_data
{
int TimerId;
+ int FireCount;
+ DWORD DueTime;
+ DWORD Period;
UINT32 StartTime;
};
typedef struct apc_data APC_DATA;
{
UINT32 TimerTime;
APC_DATA* apcData;
+ UINT32 expectedTime;
UINT32 CurrentTime = GetTickCount();
if (!lpParam)
apcData = (APC_DATA*) lpParam;
TimerTime = CurrentTime - apcData->StartTime;
+ expectedTime = apcData->DueTime + (apcData->Period * apcData->FireCount);
- printf("TimerRoutine: TimerId: %d Time: %d Discrepancy: %d\n",
- apcData->TimerId, TimerTime, TimerTime % 100);
+ printf("TimerRoutine: TimerId: %d ActualTime: %d ExpectedTime: %d Discrepancy: %d\n",
+ apcData->TimerId, TimerTime, expectedTime, TimerTime - expectedTime);
+ apcData->FireCount++;
g_Count++;
if (g_Count >= (TIMER_COUNT * FIRE_COUNT))
int TestSynchTimerQueue(int argc, char* argv[])
{
int index;
- DWORD DueTime;
- DWORD Period;
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
APC_DATA apcData[TIMER_COUNT];
{
apcData[index].TimerId = index;
apcData[index].StartTime = GetTickCount();
-
- DueTime = (index * 100) + 500;
- Period = 1000;
+ apcData[index].DueTime = (index * 100) + 500;
+ apcData[index].Period = 1000;
+ apcData[index].FireCount = 0;
if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, (WAITORTIMERCALLBACK) TimerRoutine,
- &apcData[index], DueTime, Period, 0))
+ &apcData[index], apcData[index].DueTime, apcData[index].Period, 0))
{
printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
return -1;
* http://www.cs.wustl.edu/~schmidt/Timer_Queue.html
*/
-int InsertTimerQueueTimer(WINPR_TIMER_QUEUE* timerQueue, WINPR_TIMER_QUEUE_TIMER* timer)
+static void timespec_add_ms(struct timespec* tspec, UINT32 ms)
+{
+ UINT64 ns = tspec->tv_nsec + (ms * 1000000);
+ tspec->tv_sec += (ns / 1000000000);
+ tspec->tv_nsec = (ns % 1000000000);
+}
+
+static void timespec_gettimeofday(struct timespec* tspec)
+{
+ struct timeval tval;
+ gettimeofday(&tval, NULL);
+ tspec->tv_sec = tval.tv_sec;
+ tspec->tv_nsec = tval.tv_usec * 1000;
+}
+
+static int timespec_compare(const struct timespec* tspec1, const struct timespec* tspec2)
+{
+ if (tspec1->tv_sec < tspec2->tv_sec)
+ return -1;
+
+ if (tspec1->tv_sec > tspec2->tv_sec)
+ return 1;
+
+ return tspec1->tv_nsec - tspec2->tv_nsec;
+}
+
+static void timespec_copy(struct timespec* dst, struct timespec* src)
+{
+ dst->tv_sec = src->tv_sec;
+ dst->tv_nsec = src->tv_nsec;
+}
+
+void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
{
WINPR_TIMER_QUEUE_TIMER* node;
-
- if (!timerQueue->head)
+
+ if (!(*pHead))
{
- timerQueue->head = timer;
- timer->prev = NULL;
- timer->next = NULL;
- return 0;
+ *pHead = timer;
+ return;
}
-
- node = timerQueue->head;
-
+
+ node = *pHead;
+
while (node->next)
{
+ if (timespec_compare(&(timer->ExpirationTime), &(node->ExpirationTime)) < 0)
+ break;
+
node = node->next;
}
-
+
+ if (node->next)
+ timer->next = node->next->next;
+
node->next = timer;
- timer->prev = node;
- timer->next = NULL;
-
- return 0;
}
int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue)
{
- UINT64 currentTime;
+ struct timespec CurrentTime;
WINPR_TIMER_QUEUE_TIMER* node;
if (!timerQueue->head)
return 0;
- currentTime = GetTickCount64();
+ timespec_gettimeofday(&CurrentTime);
node = timerQueue->head;
while (node)
{
- if (currentTime >= node->ExpirationTime)
+ if (timespec_compare(&CurrentTime, &(node->ExpirationTime)) >= 0)
{
node->Callback(node->Parameter, TRUE);
node->FireCount++;
if (node->Period)
{
- node->ExpirationTime = node->StartTime + (node->FireCount * node->Period);
+ timespec_add_ms(&(node->ExpirationTime), node->Period);
}
}
static void* TimerQueueThread(void* arg)
{
+ int status;
+ struct timespec tspec;
WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*) arg;
while (1)
{
+ pthread_mutex_lock(&(timerQueue->cond_mutex));
+
+ timespec_gettimeofday(&tspec);
+ timespec_add_ms(&tspec, 23);
+
+ status = pthread_cond_timedwait(&(timerQueue->cond), &(timerQueue->cond_mutex), &tspec);
+
FireExpiredTimerQueueTimers(timerQueue);
- Sleep(timerQueue->resolution);
+
+ pthread_mutex_unlock(&(timerQueue->cond_mutex));
}
return NULL;
int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
{
pthread_cond_init(&(timerQueue->cond), NULL);
+ pthread_mutex_init(&(timerQueue->cond_mutex), NULL);
+
pthread_mutex_init(&(timerQueue->mutex), NULL);
pthread_attr_init(&(timerQueue->attr));
{
WINPR_HANDLE_SET_TYPE(timerQueue, HANDLE_TYPE_TIMER_QUEUE);
handle = (HANDLE) timerQueue;
-
- timerQueue->resolution = 5;
StartTimerQueueThread(timerQueue);
}
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
pthread_cond_destroy(&(timerQueue->cond));
+ pthread_mutex_destroy(&(timerQueue->cond_mutex));
+
pthread_mutex_destroy(&(timerQueue->mutex));
+ pthread_attr_destroy(&(timerQueue->attr));
+
free(timerQueue);
return TRUE;
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));
WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER);
*((UINT_PTR*) phNewTimer) = (UINT_PTR) (HANDLE) timer;
+ timespec_gettimeofday(&(timer->StartTime));
+ timespec_add_ms(&(timer->StartTime), DueTime);
+ timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
+
timer->Flags = Flags;
timer->DueTime = DueTime;
timer->Period = Period;
timer->timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
timer->FireCount = 0;
- timer->StartTime = currentTime + DueTime;
- timer->ExpirationTime = timer->StartTime;
- InsertTimerQueueTimer(timerQueue, timer);
+ InsertTimerQueueTimer(&(timerQueue->head), timer);
return TRUE;
}