21#include <winpr/config.h>
24#include <winpr/file.h>
25#include <winpr/assert.h>
26#include <winpr/sysinfo.h>
28#include <winpr/synch.h>
42#include "../handle/handle.h"
43#include "../thread/thread.h"
46#define TAG WINPR_TAG("synch.timer")
48static BOOL TimerCloseHandle(HANDLE handle);
50static BOOL TimerIsHandled(HANDLE handle)
52 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_TIMER, FALSE);
55static int TimerGetFd(HANDLE handle)
57 WINPR_TIMER* timer = (WINPR_TIMER*)handle;
59 if (!TimerIsHandled(handle))
65static DWORD TimerCleanupHandle(HANDLE handle)
67 WINPR_TIMER* timer = (WINPR_TIMER*)handle;
69 if (!TimerIsHandled(handle))
72 if (timer->bManualReset)
75#ifdef TIMER_IMPL_TIMERFD
79 UINT64 expirations = 0;
80 length = read(timer->fd, (
void*)&expirations,
sizeof(UINT64));
81 }
while (length < 0 && errno == EINTR);
87 char ebuffer[256] = WINPR_C_ARRAY_INIT;
98 WLog_ERR(TAG,
"timer read() failure [%d] %s", errno,
99 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
103 WLog_ERR(TAG,
"timer read() failure - incorrect number of bytes read");
108#elif defined(TIMER_IMPL_POSIX) || defined(TIMER_IMPL_DISPATCH)
109 if (!winpr_event_reset(&timer->event))
111 WLog_ERR(TAG,
"timer reset() failure");
116 return WAIT_OBJECT_0;
121 WINPR_APC_ITEM apcItem;
125static void TimerPostDelete_APC(LPVOID arg)
127 TimerDeleter* deleter = (TimerDeleter*)arg;
128 WINPR_ASSERT(deleter);
129 free(deleter->timer);
130 deleter->apcItem.markedForFree = TRUE;
131 deleter->apcItem.markedForRemove = TRUE;
134BOOL TimerCloseHandle(HANDLE handle)
136 WINPR_TIMER* timer =
nullptr;
137 timer = (WINPR_TIMER*)handle;
139 if (!TimerIsHandled(handle))
142#ifdef TIMER_IMPL_TIMERFD
147#ifdef TIMER_IMPL_POSIX
148 timer_delete(timer->tid);
151#ifdef TIMER_IMPL_DISPATCH
152 dispatch_release(timer->queue);
153 dispatch_release(timer->source);
156#if defined(TIMER_IMPL_POSIX) || defined(TIMER_IMPL_DISPATCH)
157 winpr_event_uninit(&timer->event);
161 if (timer->apcItem.linked)
163 TimerDeleter* deleter =
nullptr;
164 WINPR_APC_ITEM* apcItem =
nullptr;
166 switch (apc_remove(&timer->apcItem))
170 case APC_REMOVE_DELAY_FREE:
172 WINPR_THREAD* thread = winpr_GetCurrentThread();
176 deleter = calloc(1,
sizeof(*deleter));
179 WLog_ERR(TAG,
"unable to allocate a timer deleter");
183 deleter->timer = timer;
184 apcItem = &deleter->apcItem;
185 apcItem->type = APC_TYPE_HANDLE_FREE;
186 apcItem->alwaysSignaled = TRUE;
187 apcItem->completion = TimerPostDelete_APC;
188 apcItem->completionArgs = deleter;
189 apc_register(thread, apcItem);
192 case APC_REMOVE_ERROR:
194 WLog_ERR(TAG,
"unable to remove timer from APC list");
203#ifdef TIMER_IMPL_POSIX
205static void WaitableTimerSignalHandler(
int signum, siginfo_t* siginfo,
void* arg)
207 WINPR_TIMER* timer = siginfo->si_value.sival_ptr;
211 if (!timer || (signum != SIGALRM))
214 if (!winpr_event_set(&timer->event))
215 WLog_ERR(TAG,
"error when notifying event");
218static INIT_ONCE TimerSignalHandler_InitOnce = INIT_ONCE_STATIC_INIT;
220static BOOL InstallTimerSignalHandler(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
222 struct sigaction action;
223 sigemptyset(&action.sa_mask);
224 sigaddset(&action.sa_mask, SIGALRM);
225 action.sa_flags = SA_RESTART | SA_SIGINFO;
226 action.sa_sigaction = WaitableTimerSignalHandler;
227 sigaction(SIGALRM, &action,
nullptr);
232#ifdef TIMER_IMPL_DISPATCH
233static void WaitableTimerHandler(
void* arg)
235 WINPR_TIMER* timer = (WINPR_TIMER*)arg;
240 if (!winpr_event_set(&timer->event))
241 WLog_ERR(TAG,
"failed to write to pipe");
243 if (timer->lPeriod == 0)
246 dispatch_suspend(timer->source);
248 timer->running = FALSE;
253static int InitializeWaitableTimer(WINPR_TIMER* timer)
257#ifdef TIMER_IMPL_TIMERFD
258 timer->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
261#elif defined(TIMER_IMPL_POSIX)
262 struct sigevent sigev = WINPR_C_ARRAY_INIT;
263 if (!InitOnceExecuteOnce(&TimerSignalHandler_InitOnce, InstallTimerSignalHandler,
nullptr,
266 sigev.sigev_notify = SIGEV_SIGNAL;
267 sigev.sigev_signo = SIGALRM;
268 sigev.sigev_value.sival_ptr = (
void*)timer;
270 if ((timer_create(CLOCK_MONOTONIC, &sigev, &(timer->tid))) != 0)
272 WLog_ERR(TAG,
"timer_create");
275#elif !defined(TIMER_IMPL_DISPATCH)
276 WLog_ERR(TAG,
"os specific implementation is missing");
284static BOOL timer_drain_fd(
int fd)
291 ret = read(fd, &expr,
sizeof(expr));
292 }
while (ret < 0 && errno == EINTR);
297static HANDLE_OPS ops = { TimerIsHandled, TimerCloseHandle, TimerGetFd, TimerCleanupHandle,
298 nullptr,
nullptr,
nullptr,
nullptr,
299 nullptr,
nullptr,
nullptr,
nullptr,
300 nullptr,
nullptr,
nullptr,
nullptr,
301 nullptr,
nullptr,
nullptr,
nullptr,
308HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
311 HANDLE handle =
nullptr;
312 WINPR_TIMER* timer =
nullptr;
314 if (lpTimerAttributes)
315 WLog_WARN(TAG,
"[%s] does not support lpTimerAttributes", lpTimerName);
317 timer = (WINPR_TIMER*)calloc(1,
sizeof(WINPR_TIMER));
321 WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER, WINPR_FD_READ);
322 handle = (HANDLE)timer;
325 timer->bManualReset = bManualReset;
326 timer->pfnCompletionRoutine =
nullptr;
327 timer->lpArgToCompletionRoutine =
nullptr;
328 timer->bInit = FALSE;
331 timer->name = strdup(lpTimerName);
333 timer->common.ops = &ops;
334#if defined(TIMER_IMPL_DISPATCH) || defined(TIMER_IMPL_POSIX)
335 if (!winpr_event_init(&timer->event))
337 timer->fd = timer->event.fds[0];
340#if defined(TIMER_IMPL_DISPATCH)
341 timer->queue = dispatch_queue_create(TAG, DISPATCH_QUEUE_SERIAL);
346 timer->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->queue);
351 dispatch_set_context(timer->source, timer);
352 dispatch_source_set_event_handler_f(timer->source, WaitableTimerHandler);
358#if defined(TIMER_IMPL_DISPATCH) || defined(TIMER_IMPL_POSIX)
360 TimerCloseHandle(handle);
365HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
368 HANDLE handle =
nullptr;
369 LPSTR name =
nullptr;
373 name = ConvertWCharToUtf8Alloc(lpTimerName,
nullptr);
378 handle = CreateWaitableTimerA(lpTimerAttributes, bManualReset, name);
383HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName,
384 DWORD dwFlags, DWORD dwDesiredAccess)
386 BOOL bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) != 0;
388 if (dwDesiredAccess != 0)
389 WLog_WARN(TAG,
"[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpTimerName,
392 return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName);
395HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName,
396 DWORD dwFlags, DWORD dwDesiredAccess)
398 HANDLE handle =
nullptr;
399 LPSTR name =
nullptr;
403 name = ConvertWCharToUtf8Alloc(lpTimerName,
nullptr);
408 handle = CreateWaitableTimerExA(lpTimerAttributes, name, dwFlags, dwDesiredAccess);
413static void timerAPC(LPVOID arg)
415 WINPR_TIMER* timer = (WINPR_TIMER*)arg;
421 switch (apc_remove(&timer->apcItem))
424 case APC_REMOVE_DELAY_FREE:
426 case APC_REMOVE_ERROR:
428 WLog_ERR(TAG,
"error removing the APC routine");
432 if (timer->pfnCompletionRoutine)
433 timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
435#ifdef TIMER_IMPL_TIMERFD
436 while (timer_drain_fd(timer->fd))
438#elif defined(TIMER_IMPL_POSIX) || defined(TIMER_IMPL_DISPATCH)
439 winpr_event_reset(&timer->event);
443BOOL SetWaitableTimer(HANDLE hTimer,
const LARGE_INTEGER* lpDueTime, LONG lPeriod,
444 PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
449 WINPR_TIMER* timer =
nullptr;
450 LONGLONG seconds = 0;
451 LONGLONG nanoseconds = 0;
454 if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
457 if (Type != HANDLE_TYPE_TIMER)
468 WLog_ERR(TAG,
"does not support fResume");
472 timer = (WINPR_TIMER*)Object;
473 timer->lPeriod = lPeriod;
474 timer->pfnCompletionRoutine = pfnCompletionRoutine;
475 timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
479 if (InitializeWaitableTimer(timer) < 0)
483#if defined(TIMER_IMPL_TIMERFD) || defined(TIMER_IMPL_POSIX)
484 ZeroMemory(&(timer->timeout),
sizeof(
struct itimerspec));
486 if (lpDueTime->QuadPart < 0)
488 LONGLONG due = lpDueTime->QuadPart * (-1);
490 seconds = (due / 10000000);
491 nanoseconds = ((due % 10000000) * 100);
493 else if (lpDueTime->QuadPart == 0)
495 seconds = nanoseconds = 0;
499 WLog_ERR(TAG,
"absolute time not implemented");
505 timer->timeout.it_interval.tv_sec = (lPeriod / 1000LL);
506 timer->timeout.it_interval.tv_nsec = (1000000LL * (lPeriod % 1000LL));
509 if (lpDueTime->QuadPart != 0)
511 timer->timeout.it_value.tv_sec = seconds;
512 timer->timeout.it_value.tv_nsec = nanoseconds;
516 timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec;
517 timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec;
520#ifdef TIMER_IMPL_TIMERFD
521 status = timerfd_settime(timer->fd, 0, &(timer->timeout),
nullptr);
524 WLog_ERR(TAG,
"timerfd_settime failure: %d", status);
528 status = timer_settime(timer->tid, 0, &(timer->timeout),
nullptr);
531 WLog_ERR(TAG,
"timer_settime failure");
537#ifdef TIMER_IMPL_DISPATCH
538 if (lpDueTime->QuadPart < 0)
540 LONGLONG due = lpDueTime->QuadPart * (-1);
542 seconds = (due / 10000000);
543 nanoseconds = due * 100;
545 else if (lpDueTime->QuadPart == 0)
547 seconds = nanoseconds = 0;
551 WLog_ERR(TAG,
"absolute time not implemented");
555 if (!winpr_event_reset(&timer->event))
557 WLog_ERR(TAG,
"error when resetting timer event");
562 dispatch_suspend(timer->source);
564 dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, nanoseconds);
565 uint64_t interval = DISPATCH_TIME_FOREVER;
568 interval = lPeriod * 1000000;
570 dispatch_source_set_timer(timer->source, start, interval, 0);
571 dispatch_resume(timer->source);
572 timer->running = TRUE;
576 if (pfnCompletionRoutine)
578 WINPR_APC_ITEM* apcItem = &timer->apcItem;
581 apcItem->type = APC_TYPE_TIMER;
582 apcItem->alwaysSignaled = FALSE;
583 apcItem->pollFd = timer->fd;
584 apcItem->pollMode = WINPR_FD_READ;
585 apcItem->completion = timerAPC;
586 apcItem->completionArgs = timer;
588 if (!apcItem->linked)
590 WINPR_THREAD* thread = winpr_GetCurrentThread();
594 apc_register(thread, apcItem);
599 if (timer->apcItem.linked)
601 apc_remove(&timer->apcItem);
607BOOL SetWaitableTimerEx(HANDLE hTimer,
const LARGE_INTEGER* lpDueTime, LONG lPeriod,
608 PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
610 WINPR_ATTR_UNUSED ULONG TolerableDelay)
612 return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine,
613 lpArgToCompletionRoutine, FALSE);
616HANDLE OpenWaitableTimerA(WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
617 WINPR_ATTR_UNUSED BOOL bInheritHandle,
618 WINPR_ATTR_UNUSED LPCSTR lpTimerName)
621 WLog_ERR(TAG,
"not implemented");
625HANDLE OpenWaitableTimerW(WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
626 WINPR_ATTR_UNUSED BOOL bInheritHandle,
627 WINPR_ATTR_UNUSED LPCWSTR lpTimerName)
630 WLog_ERR(TAG,
"not implemented");
634BOOL CancelWaitableTimer(HANDLE hTimer)
639 if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
642 if (Type != HANDLE_TYPE_TIMER)
645#if defined(__APPLE__)
647 WINPR_TIMER* timer = (WINPR_TIMER*)Object;
649 dispatch_suspend(timer->source);
651 timer->running = FALSE;
662int GetTimerFileDescriptor(HANDLE hTimer)
667 if (!winpr_Handle_GetInfo(hTimer, &type, &hdl) || type != HANDLE_TYPE_TIMER)
669 WLog_ERR(TAG,
"GetTimerFileDescriptor: hTimer is not an timer");
670 SetLastError(ERROR_INVALID_PARAMETER);
674 return winpr_Handle_getFd(hTimer);
686static void timespec_add_ms(
struct timespec* tspec, UINT32 ms)
690 ns = tspec->tv_nsec + (ms * 1000000LL);
691 tspec->tv_sec += (ns / 1000000000LL);
692 tspec->tv_nsec = (ns % 1000000000LL);
695static void timespec_gettimeofday(
struct timespec* tspec)
699 const UINT64 ns = winpr_GetUnixTimeNS();
700 tspec->tv_sec = WINPR_TIME_NS_TO_S(ns);
701 tspec->tv_nsec = WINPR_TIME_NS_REM_NS(ns);
704static INT64 timespec_compare(
const struct timespec* tspec1,
const struct timespec* tspec2)
706 WINPR_ASSERT(tspec1);
707 WINPR_ASSERT(tspec2);
708 if (tspec1->tv_sec == tspec2->tv_sec)
709 return (tspec1->tv_nsec - tspec2->tv_nsec);
711 return (tspec1->tv_sec - tspec2->tv_sec);
714static void timespec_copy(
struct timespec* dst,
struct timespec* src)
718 dst->tv_sec = src->tv_sec;
719 dst->tv_nsec = src->tv_nsec;
722static void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
724 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
732 timer->next =
nullptr;
740 if (timespec_compare(&(timer->ExpirationTime), &(node->ExpirationTime)) > 0)
742 if (timespec_compare(&(timer->ExpirationTime), &(node->next->ExpirationTime)) < 0)
751 timer->next = node->next->next;
757 timer->next =
nullptr;
761static void RemoveTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
764 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
765 WINPR_TIMER_QUEUE_TIMER* prevNode =
nullptr;
771 *pHead = timer->next;
772 timer->next =
nullptr;
795 prevNode->next = timer->next;
798 timer->next =
nullptr;
802static int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue)
804 struct timespec CurrentTime;
805 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
807 WINPR_ASSERT(timerQueue);
809 if (!timerQueue->activeHead)
812 timespec_gettimeofday(&CurrentTime);
813 node = timerQueue->activeHead;
817 if (timespec_compare(&CurrentTime, &(node->ExpirationTime)) >= 0)
819 node->Callback(node->Parameter, TRUE);
821 timerQueue->activeHead = node->next;
822 node->next =
nullptr;
826 timespec_add_ms(&(node->ExpirationTime), node->Period);
827 InsertTimerQueueTimer(&(timerQueue->activeHead), node);
831 InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
834 node = timerQueue->activeHead;
845static void* TimerQueueThread(
void* arg)
848 struct timespec timeout;
849 WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*)arg;
851 WINPR_ASSERT(timerQueue);
854 pthread_mutex_lock(&(timerQueue->cond_mutex));
855 timespec_gettimeofday(&timeout);
857 if (!timerQueue->activeHead)
859 timespec_add_ms(&timeout, 50);
863 if (timespec_compare(&timeout, &(timerQueue->activeHead->ExpirationTime)) < 0)
865 timespec_copy(&timeout, &(timerQueue->activeHead->ExpirationTime));
869 status = pthread_cond_timedwait(&(timerQueue->cond), &(timerQueue->cond_mutex), &timeout);
870 FireExpiredTimerQueueTimers(timerQueue);
871 const BOOL bCancelled = timerQueue->bCancelled;
872 pthread_mutex_unlock(&(timerQueue->cond_mutex));
874 if ((status != ETIMEDOUT) && (status != 0))
884static int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
886 WINPR_ASSERT(timerQueue);
887 pthread_cond_init(&(timerQueue->cond),
nullptr);
888 pthread_mutex_init(&(timerQueue->cond_mutex),
nullptr);
889 pthread_mutex_init(&(timerQueue->mutex),
nullptr);
890 pthread_attr_init(&(timerQueue->attr));
891 timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO);
892 pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param));
893 pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO);
894 pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue);
898HANDLE CreateTimerQueue(
void)
900 HANDLE handle =
nullptr;
901 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
902 timerQueue = (WINPR_TIMER_QUEUE*)calloc(1,
sizeof(WINPR_TIMER_QUEUE));
906 WINPR_HANDLE_SET_TYPE_AND_MODE(timerQueue, HANDLE_TYPE_TIMER_QUEUE, WINPR_FD_READ);
907 handle = (HANDLE)timerQueue;
908 timerQueue->activeHead =
nullptr;
909 timerQueue->inactiveHead =
nullptr;
910 timerQueue->bCancelled = FALSE;
911 StartTimerQueueThread(timerQueue);
917BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
919 void* rvalue =
nullptr;
920 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
921 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
922 WINPR_TIMER_QUEUE_TIMER* nextNode =
nullptr;
927 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
929 pthread_mutex_lock(&(timerQueue->cond_mutex));
930 timerQueue->bCancelled = TRUE;
931 pthread_cond_signal(&(timerQueue->cond));
932 pthread_mutex_unlock(&(timerQueue->cond_mutex));
933 pthread_join(timerQueue->thread, &rvalue);
946 node = timerQueue->activeHead;
950 InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
954 timerQueue->activeHead =
nullptr;
956 node = timerQueue->inactiveHead;
960 nextNode = node->next;
965 timerQueue->inactiveHead =
nullptr;
968 pthread_cond_destroy(&(timerQueue->cond));
969 pthread_mutex_destroy(&(timerQueue->cond_mutex));
970 pthread_mutex_destroy(&(timerQueue->mutex));
971 pthread_attr_destroy(&(timerQueue->attr));
974 if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
975 (void)SetEvent(CompletionEvent);
980BOOL DeleteTimerQueue(HANDLE TimerQueue)
982 return DeleteTimerQueueEx(TimerQueue,
nullptr);
985BOOL CreateTimerQueueTimer(HANDLE* phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback,
986 void* Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
988 struct timespec CurrentTime = WINPR_C_ARRAY_INIT;
993 timespec_gettimeofday(&CurrentTime);
994 WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
995 WINPR_TIMER_QUEUE_TIMER* timer = calloc(1,
sizeof(WINPR_TIMER_QUEUE_TIMER));
1000 WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER, WINPR_FD_READ);
1001 *phNewTimer = (HANDLE)timer;
1002 timespec_copy(&(timer->StartTime), &CurrentTime);
1003 timespec_add_ms(&(timer->StartTime), DueTime);
1004 timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
1005 timer->Flags = Flags;
1006 timer->DueTime = DueTime;
1007 timer->Period = Period;
1008 timer->Callback = Callback;
1009 timer->Parameter = Parameter;
1010 timer->timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1011 timer->FireCount = 0;
1012 timer->next =
nullptr;
1013 pthread_mutex_lock(&(timerQueue->cond_mutex));
1014 InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
1015 pthread_cond_signal(&(timerQueue->cond));
1016 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1020BOOL ChangeTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period)
1022 struct timespec CurrentTime;
1023 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
1024 WINPR_TIMER_QUEUE_TIMER* timer =
nullptr;
1026 if (!TimerQueue || !Timer)
1029 timespec_gettimeofday(&CurrentTime);
1030 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1031 timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
1032 pthread_mutex_lock(&(timerQueue->cond_mutex));
1033 RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
1034 RemoveTimerQueueTimer(&(timerQueue->inactiveHead), timer);
1035 timer->DueTime = DueTime;
1036 timer->Period = Period;
1037 timer->next =
nullptr;
1038 timespec_copy(&(timer->StartTime), &CurrentTime);
1039 timespec_add_ms(&(timer->StartTime), DueTime);
1040 timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
1041 InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
1042 pthread_cond_signal(&(timerQueue->cond));
1043 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1047BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
1049 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
1050 WINPR_TIMER_QUEUE_TIMER* timer =
nullptr;
1052 if (!TimerQueue || !Timer)
1055 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1056 timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
1057 pthread_mutex_lock(&(timerQueue->cond_mutex));
1068 RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
1069 pthread_cond_signal(&(timerQueue->cond));
1070 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1073 if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
1074 (void)SetEvent(CompletionEvent);