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);
131 winpr_Handle_Release((HANDLE)deleter->timer);
132 deleter->apcItem.markedForFree = TRUE;
133 deleter->apcItem.markedForRemove = TRUE;
136BOOL TimerCloseHandle(HANDLE handle)
138 WINPR_TIMER* timer =
nullptr;
139 timer = (WINPR_TIMER*)handle;
141 if (!TimerIsHandled(handle))
144#ifdef TIMER_IMPL_TIMERFD
149#ifdef TIMER_IMPL_POSIX
150 timer_delete(timer->tid);
153#ifdef TIMER_IMPL_DISPATCH
154 dispatch_release(timer->queue);
155 dispatch_release(timer->source);
158#if defined(TIMER_IMPL_POSIX) || defined(TIMER_IMPL_DISPATCH)
159 winpr_event_uninit(&timer->event);
163 timer->name =
nullptr;
164 if (timer->apcItem.linked)
166 TimerDeleter* deleter =
nullptr;
167 WINPR_APC_ITEM* apcItem =
nullptr;
169 switch (apc_remove(&timer->apcItem))
173 case APC_REMOVE_DELAY_FREE:
175 WINPR_THREAD* thread = winpr_GetCurrentThread();
179 deleter = calloc(1,
sizeof(*deleter));
182 WLog_ERR(TAG,
"unable to allocate a timer deleter");
190 winpr_Handle_AddRef(handle);
191 deleter->timer = timer;
192 apcItem = &deleter->apcItem;
193 apcItem->type = APC_TYPE_HANDLE_FREE;
194 apcItem->alwaysSignaled = TRUE;
195 apcItem->completion = TimerPostDelete_APC;
196 apcItem->completionArgs = deleter;
197 apc_register(thread, apcItem);
200 case APC_REMOVE_ERROR:
202 WLog_ERR(TAG,
"unable to remove timer from APC list");
210#ifdef TIMER_IMPL_POSIX
212static void WaitableTimerSignalHandler(
int signum, siginfo_t* siginfo,
void* arg)
214 WINPR_TIMER* timer = siginfo->si_value.sival_ptr;
218 if (!timer || (signum != SIGALRM))
221 if (!winpr_event_set(&timer->event))
222 WLog_ERR(TAG,
"error when notifying event");
225static INIT_ONCE TimerSignalHandler_InitOnce = INIT_ONCE_STATIC_INIT;
227static BOOL InstallTimerSignalHandler(
PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
229 struct sigaction action;
230 sigemptyset(&action.sa_mask);
231 sigaddset(&action.sa_mask, SIGALRM);
232 action.sa_flags = SA_RESTART | SA_SIGINFO;
233 action.sa_sigaction = WaitableTimerSignalHandler;
234 sigaction(SIGALRM, &action,
nullptr);
239#ifdef TIMER_IMPL_DISPATCH
240static void WaitableTimerHandler(
void* arg)
242 WINPR_TIMER* timer = (WINPR_TIMER*)arg;
247 if (!winpr_event_set(&timer->event))
248 WLog_ERR(TAG,
"failed to write to pipe");
250 if (timer->lPeriod == 0)
253 dispatch_suspend(timer->source);
255 timer->running = FALSE;
260static int InitializeWaitableTimer(WINPR_TIMER* timer)
264#ifdef TIMER_IMPL_TIMERFD
265 timer->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
268#elif defined(TIMER_IMPL_POSIX)
269 struct sigevent sigev = WINPR_C_ARRAY_INIT;
270 if (!InitOnceExecuteOnce(&TimerSignalHandler_InitOnce, InstallTimerSignalHandler,
nullptr,
273 sigev.sigev_notify = SIGEV_SIGNAL;
274 sigev.sigev_signo = SIGALRM;
275 sigev.sigev_value.sival_ptr = (
void*)timer;
277 if ((timer_create(CLOCK_MONOTONIC, &sigev, &(timer->tid))) != 0)
279 WLog_ERR(TAG,
"timer_create");
282#elif !defined(TIMER_IMPL_DISPATCH)
283 WLog_ERR(TAG,
"os specific implementation is missing");
291static BOOL timer_drain_fd(
int fd)
298 ret = read(fd, &expr,
sizeof(expr));
299 }
while (ret < 0 && errno == EINTR);
304static HANDLE_OPS ops = { TimerIsHandled, TimerCloseHandle, TimerGetFd, TimerCleanupHandle,
305 nullptr,
nullptr,
nullptr,
nullptr,
306 nullptr,
nullptr,
nullptr,
nullptr,
307 nullptr,
nullptr,
nullptr,
nullptr,
308 nullptr,
nullptr,
nullptr,
nullptr,
315HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
318 HANDLE handle =
nullptr;
319 WINPR_TIMER* timer =
nullptr;
321 if (lpTimerAttributes)
322 WLog_WARN(TAG,
"[%s] does not support lpTimerAttributes", lpTimerName);
324 timer = (WINPR_TIMER*)calloc(1,
sizeof(WINPR_TIMER));
328 WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER, WINPR_FD_READ);
329 handle = (HANDLE)timer;
332 timer->bManualReset = bManualReset;
333 timer->pfnCompletionRoutine =
nullptr;
334 timer->lpArgToCompletionRoutine =
nullptr;
335 timer->bInit = FALSE;
338 timer->name = strdup(lpTimerName);
340 timer->common.ops = &ops;
341#if defined(TIMER_IMPL_DISPATCH) || defined(TIMER_IMPL_POSIX)
342 if (!winpr_event_init(&timer->event))
344 timer->fd = timer->event.fds[0];
347#if defined(TIMER_IMPL_DISPATCH)
348 timer->queue = dispatch_queue_create(TAG, DISPATCH_QUEUE_SERIAL);
353 timer->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->queue);
358 dispatch_set_context(timer->source, timer);
359 dispatch_source_set_event_handler_f(timer->source, WaitableTimerHandler);
365#if defined(TIMER_IMPL_DISPATCH) || defined(TIMER_IMPL_POSIX)
367 TimerCloseHandle(handle);
373HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
376 HANDLE handle =
nullptr;
377 LPSTR name =
nullptr;
381 name = ConvertWCharToUtf8Alloc(lpTimerName,
nullptr);
386 handle = CreateWaitableTimerA(lpTimerAttributes, bManualReset, name);
391HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName,
392 DWORD dwFlags, DWORD dwDesiredAccess)
394 BOOL bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) != 0;
396 if (dwDesiredAccess != 0)
397 WLog_WARN(TAG,
"[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpTimerName,
400 return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName);
403HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName,
404 DWORD dwFlags, DWORD dwDesiredAccess)
406 HANDLE handle =
nullptr;
407 LPSTR name =
nullptr;
411 name = ConvertWCharToUtf8Alloc(lpTimerName,
nullptr);
416 handle = CreateWaitableTimerExA(lpTimerAttributes, name, dwFlags, dwDesiredAccess);
421static void timerAPC(LPVOID arg)
423 WINPR_TIMER* timer = (WINPR_TIMER*)arg;
429 switch (apc_remove(&timer->apcItem))
432 case APC_REMOVE_DELAY_FREE:
434 case APC_REMOVE_ERROR:
436 WLog_ERR(TAG,
"error removing the APC routine");
440 if (timer->pfnCompletionRoutine)
441 timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
443#ifdef TIMER_IMPL_TIMERFD
444 while (timer_drain_fd(timer->fd))
446#elif defined(TIMER_IMPL_POSIX) || defined(TIMER_IMPL_DISPATCH)
447 winpr_event_reset(&timer->event);
451BOOL SetWaitableTimer(HANDLE hTimer,
const LARGE_INTEGER* lpDueTime, LONG lPeriod,
452 PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
457 WINPR_TIMER* timer =
nullptr;
458 LONGLONG seconds = 0;
459 LONGLONG nanoseconds = 0;
462 if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
465 if (Type != HANDLE_TYPE_TIMER)
476 WLog_ERR(TAG,
"does not support fResume");
480 timer = (WINPR_TIMER*)Object;
481 timer->lPeriod = lPeriod;
482 timer->pfnCompletionRoutine = pfnCompletionRoutine;
483 timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
487 if (InitializeWaitableTimer(timer) < 0)
491#if defined(TIMER_IMPL_TIMERFD) || defined(TIMER_IMPL_POSIX)
492 ZeroMemory(&(timer->timeout),
sizeof(
struct itimerspec));
494 if (lpDueTime->QuadPart < 0)
496 LONGLONG due = lpDueTime->QuadPart * (-1);
498 seconds = (due / 10000000);
499 nanoseconds = ((due % 10000000) * 100);
501 else if (lpDueTime->QuadPart == 0)
503 seconds = nanoseconds = 0;
507 WLog_ERR(TAG,
"absolute time not implemented");
513 timer->timeout.it_interval.tv_sec = (lPeriod / 1000LL);
514 timer->timeout.it_interval.tv_nsec = (1000000LL * (lPeriod % 1000LL));
517 if (lpDueTime->QuadPart != 0)
519 timer->timeout.it_value.tv_sec = seconds;
520 timer->timeout.it_value.tv_nsec = nanoseconds;
524 timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec;
525 timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec;
528#ifdef TIMER_IMPL_TIMERFD
529 status = timerfd_settime(timer->fd, 0, &(timer->timeout),
nullptr);
532 WLog_ERR(TAG,
"timerfd_settime failure: %d", status);
536 status = timer_settime(timer->tid, 0, &(timer->timeout),
nullptr);
539 WLog_ERR(TAG,
"timer_settime failure");
545#ifdef TIMER_IMPL_DISPATCH
546 if (lpDueTime->QuadPart < 0)
548 LONGLONG due = lpDueTime->QuadPart * (-1);
550 seconds = (due / 10000000);
551 nanoseconds = due * 100;
553 else if (lpDueTime->QuadPart == 0)
555 seconds = nanoseconds = 0;
559 WLog_ERR(TAG,
"absolute time not implemented");
563 if (!winpr_event_reset(&timer->event))
565 WLog_ERR(TAG,
"error when resetting timer event");
570 dispatch_suspend(timer->source);
572 dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, nanoseconds);
573 uint64_t interval = DISPATCH_TIME_FOREVER;
576 interval = lPeriod * 1000000;
578 dispatch_source_set_timer(timer->source, start, interval, 0);
579 dispatch_resume(timer->source);
580 timer->running = TRUE;
584 if (pfnCompletionRoutine)
586 WINPR_APC_ITEM* apcItem = &timer->apcItem;
589 apcItem->type = APC_TYPE_TIMER;
590 apcItem->alwaysSignaled = FALSE;
591 apcItem->pollFd = timer->fd;
592 apcItem->pollMode = WINPR_FD_READ;
593 apcItem->completion = timerAPC;
594 apcItem->completionArgs = timer;
596 if (!apcItem->linked)
598 WINPR_THREAD* thread = winpr_GetCurrentThread();
602 apc_register(thread, apcItem);
607 if (timer->apcItem.linked)
609 apc_remove(&timer->apcItem);
615BOOL SetWaitableTimerEx(HANDLE hTimer,
const LARGE_INTEGER* lpDueTime, LONG lPeriod,
616 PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
618 WINPR_ATTR_UNUSED ULONG TolerableDelay)
620 return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine,
621 lpArgToCompletionRoutine, FALSE);
624HANDLE OpenWaitableTimerA(WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
625 WINPR_ATTR_UNUSED BOOL bInheritHandle,
626 WINPR_ATTR_UNUSED LPCSTR lpTimerName)
629 WLog_ERR(TAG,
"not implemented");
633HANDLE OpenWaitableTimerW(WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
634 WINPR_ATTR_UNUSED BOOL bInheritHandle,
635 WINPR_ATTR_UNUSED LPCWSTR lpTimerName)
638 WLog_ERR(TAG,
"not implemented");
642BOOL CancelWaitableTimer(HANDLE hTimer)
647 if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
650 if (Type != HANDLE_TYPE_TIMER)
653#if defined(__APPLE__)
655 WINPR_TIMER* timer = (WINPR_TIMER*)Object;
657 dispatch_suspend(timer->source);
659 timer->running = FALSE;
670int GetTimerFileDescriptor(HANDLE hTimer)
675 if (!winpr_Handle_GetInfo(hTimer, &type, &hdl) || type != HANDLE_TYPE_TIMER)
677 WLog_ERR(TAG,
"GetTimerFileDescriptor: hTimer is not an timer");
678 SetLastError(ERROR_INVALID_PARAMETER);
682 return winpr_Handle_getFd(hTimer);
694static void timespec_add_ms(
struct timespec* tspec, UINT32 ms)
698 ns = tspec->tv_nsec + (ms * 1000000LL);
699 tspec->tv_sec += (ns / 1000000000LL);
700 tspec->tv_nsec = (ns % 1000000000LL);
703static void timespec_gettimeofday(
struct timespec* tspec)
707 const UINT64 ns = winpr_GetUnixTimeNS();
708 tspec->tv_sec = WINPR_TIME_NS_TO_S(ns);
709 tspec->tv_nsec = WINPR_TIME_NS_REM_NS(ns);
712static INT64 timespec_compare(
const struct timespec* tspec1,
const struct timespec* tspec2)
714 WINPR_ASSERT(tspec1);
715 WINPR_ASSERT(tspec2);
716 if (tspec1->tv_sec == tspec2->tv_sec)
717 return (tspec1->tv_nsec - tspec2->tv_nsec);
719 return (tspec1->tv_sec - tspec2->tv_sec);
722static void timespec_copy(
struct timespec* dst,
struct timespec* src)
726 dst->tv_sec = src->tv_sec;
727 dst->tv_nsec = src->tv_nsec;
730static void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
732 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
740 timer->next =
nullptr;
748 if (timespec_compare(&(timer->ExpirationTime), &(node->ExpirationTime)) > 0)
750 if (timespec_compare(&(timer->ExpirationTime), &(node->next->ExpirationTime)) < 0)
759 timer->next = node->next->next;
765 timer->next =
nullptr;
769static void RemoveTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
772 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
773 WINPR_TIMER_QUEUE_TIMER* prevNode =
nullptr;
779 *pHead = timer->next;
780 timer->next =
nullptr;
803 prevNode->next = timer->next;
806 timer->next =
nullptr;
810static int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue)
812 struct timespec CurrentTime;
813 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
815 WINPR_ASSERT(timerQueue);
817 if (!timerQueue->activeHead)
820 timespec_gettimeofday(&CurrentTime);
821 node = timerQueue->activeHead;
825 if (timespec_compare(&CurrentTime, &(node->ExpirationTime)) >= 0)
827 node->Callback(node->Parameter, TRUE);
829 timerQueue->activeHead = node->next;
830 node->next =
nullptr;
834 timespec_add_ms(&(node->ExpirationTime), node->Period);
835 InsertTimerQueueTimer(&(timerQueue->activeHead), node);
839 InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
842 node = timerQueue->activeHead;
853static void* TimerQueueThread(
void* arg)
856 struct timespec timeout;
857 WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*)arg;
859 WINPR_ASSERT(timerQueue);
862 pthread_mutex_lock(&(timerQueue->cond_mutex));
863 timespec_gettimeofday(&timeout);
865 if (!timerQueue->activeHead)
867 timespec_add_ms(&timeout, 50);
871 if (timespec_compare(&timeout, &(timerQueue->activeHead->ExpirationTime)) < 0)
873 timespec_copy(&timeout, &(timerQueue->activeHead->ExpirationTime));
877 status = pthread_cond_timedwait(&(timerQueue->cond), &(timerQueue->cond_mutex), &timeout);
878 FireExpiredTimerQueueTimers(timerQueue);
879 const BOOL bCancelled = timerQueue->bCancelled;
880 pthread_mutex_unlock(&(timerQueue->cond_mutex));
882 if ((status != ETIMEDOUT) && (status != 0))
892static int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
894 WINPR_ASSERT(timerQueue);
895 pthread_cond_init(&(timerQueue->cond),
nullptr);
896 pthread_mutex_init(&(timerQueue->cond_mutex),
nullptr);
897 pthread_mutex_init(&(timerQueue->mutex),
nullptr);
898 pthread_attr_init(&(timerQueue->attr));
899 timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO);
900 pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param));
901 pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO);
902 pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue);
906HANDLE CreateTimerQueue(
void)
908 HANDLE handle =
nullptr;
909 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
910 timerQueue = (WINPR_TIMER_QUEUE*)calloc(1,
sizeof(WINPR_TIMER_QUEUE));
914 WINPR_HANDLE_SET_TYPE_AND_MODE(timerQueue, HANDLE_TYPE_TIMER_QUEUE, WINPR_FD_READ);
915 handle = (HANDLE)timerQueue;
916 timerQueue->activeHead =
nullptr;
917 timerQueue->inactiveHead =
nullptr;
918 timerQueue->bCancelled = FALSE;
919 StartTimerQueueThread(timerQueue);
925BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
927 void* rvalue =
nullptr;
928 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
929 WINPR_TIMER_QUEUE_TIMER* node =
nullptr;
930 WINPR_TIMER_QUEUE_TIMER* nextNode =
nullptr;
935 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
937 pthread_mutex_lock(&(timerQueue->cond_mutex));
938 timerQueue->bCancelled = TRUE;
939 pthread_cond_signal(&(timerQueue->cond));
940 pthread_mutex_unlock(&(timerQueue->cond_mutex));
941 pthread_join(timerQueue->thread, &rvalue);
954 node = timerQueue->activeHead;
958 InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
962 timerQueue->activeHead =
nullptr;
964 node = timerQueue->inactiveHead;
968 nextNode = node->next;
973 timerQueue->inactiveHead =
nullptr;
976 pthread_cond_destroy(&(timerQueue->cond));
977 pthread_mutex_destroy(&(timerQueue->cond_mutex));
978 pthread_mutex_destroy(&(timerQueue->mutex));
979 pthread_attr_destroy(&(timerQueue->attr));
982 if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
983 (void)SetEvent(CompletionEvent);
988BOOL DeleteTimerQueue(HANDLE TimerQueue)
990 return DeleteTimerQueueEx(TimerQueue,
nullptr);
993BOOL CreateTimerQueueTimer(HANDLE* phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback,
994 void* Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
996 struct timespec CurrentTime = WINPR_C_ARRAY_INIT;
1001 timespec_gettimeofday(&CurrentTime);
1002 WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1003 WINPR_TIMER_QUEUE_TIMER* timer = calloc(1,
sizeof(WINPR_TIMER_QUEUE_TIMER));
1008 WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER, WINPR_FD_READ);
1009 *phNewTimer = (HANDLE)timer;
1010 timespec_copy(&(timer->StartTime), &CurrentTime);
1011 timespec_add_ms(&(timer->StartTime), DueTime);
1012 timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
1013 timer->Flags = Flags;
1014 timer->DueTime = DueTime;
1015 timer->Period = Period;
1016 timer->Callback = Callback;
1017 timer->Parameter = Parameter;
1018 timer->timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1019 timer->FireCount = 0;
1020 timer->next =
nullptr;
1021 pthread_mutex_lock(&(timerQueue->cond_mutex));
1022 InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
1023 pthread_cond_signal(&(timerQueue->cond));
1024 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1028BOOL ChangeTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period)
1030 struct timespec CurrentTime;
1031 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
1032 WINPR_TIMER_QUEUE_TIMER* timer =
nullptr;
1034 if (!TimerQueue || !Timer)
1037 timespec_gettimeofday(&CurrentTime);
1038 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1039 timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
1040 pthread_mutex_lock(&(timerQueue->cond_mutex));
1041 RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
1042 RemoveTimerQueueTimer(&(timerQueue->inactiveHead), timer);
1043 timer->DueTime = DueTime;
1044 timer->Period = Period;
1045 timer->next =
nullptr;
1046 timespec_copy(&(timer->StartTime), &CurrentTime);
1047 timespec_add_ms(&(timer->StartTime), DueTime);
1048 timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
1049 InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
1050 pthread_cond_signal(&(timerQueue->cond));
1051 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1055BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
1057 WINPR_TIMER_QUEUE* timerQueue =
nullptr;
1058 WINPR_TIMER_QUEUE_TIMER* timer =
nullptr;
1060 if (!TimerQueue || !Timer)
1063 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1064 timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
1065 pthread_mutex_lock(&(timerQueue->cond_mutex));
1076 RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
1077 pthread_cond_signal(&(timerQueue->cond));
1078 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1081 if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
1082 (void)SetEvent(CompletionEvent);