21 #include <winpr/config.h>
23 #include <winpr/crt.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")
48 static BOOL TimerCloseHandle(HANDLE handle);
50 static BOOL TimerIsHandled(HANDLE handle)
52 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_TIMER, FALSE);
55 static int TimerGetFd(HANDLE handle)
57 WINPR_TIMER* timer = (WINPR_TIMER*)handle;
59 if (!TimerIsHandled(handle))
65 static 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] = { 0 };
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;
125 static 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;
134 BOOL TimerCloseHandle(HANDLE handle)
136 WINPR_TIMER* timer = NULL;
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 = NULL;
164 WINPR_APC_ITEM* apcItem = NULL;
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
205 static 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");
218 static INIT_ONCE TimerSignalHandler_InitOnce = INIT_ONCE_STATIC_INIT;
220 static 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, NULL);
232 #ifdef TIMER_IMPL_DISPATCH
233 static 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;
253 static 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 = { 0 };
263 InitOnceExecuteOnce(&TimerSignalHandler_InitOnce, InstallTimerSignalHandler, NULL, NULL);
264 sigev.sigev_notify = SIGEV_SIGNAL;
265 sigev.sigev_signo = SIGALRM;
266 sigev.sigev_value.sival_ptr = (
void*)timer;
268 if ((timer_create(CLOCK_MONOTONIC, &sigev, &(timer->tid))) != 0)
270 WLog_ERR(TAG,
"timer_create");
273 #elif !defined(TIMER_IMPL_DISPATCH)
274 WLog_ERR(TAG,
"os specific implementation is missing");
282 static BOOL timer_drain_fd(
int fd)
289 ret = read(fd, &expr,
sizeof(expr));
290 }
while (ret < 0 && errno == EINTR);
321 HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
324 HANDLE handle = NULL;
325 WINPR_TIMER* timer = NULL;
327 if (lpTimerAttributes)
328 WLog_WARN(TAG,
"[%s] does not support lpTimerAttributes", lpTimerName);
330 timer = (WINPR_TIMER*)calloc(1,
sizeof(WINPR_TIMER));
334 WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER, WINPR_FD_READ);
335 handle = (HANDLE)timer;
338 timer->bManualReset = bManualReset;
339 timer->pfnCompletionRoutine = NULL;
340 timer->lpArgToCompletionRoutine = NULL;
341 timer->bInit = FALSE;
344 timer->name = strdup(lpTimerName);
346 timer->common.ops = &ops;
347 #if defined(TIMER_IMPL_DISPATCH) || defined(TIMER_IMPL_POSIX)
348 if (!winpr_event_init(&timer->event))
350 timer->fd = timer->event.fds[0];
353 #if defined(TIMER_IMPL_DISPATCH)
354 timer->queue = dispatch_queue_create(TAG, DISPATCH_QUEUE_SERIAL);
359 timer->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->queue);
364 dispatch_set_context(timer->source, timer);
365 dispatch_source_set_event_handler_f(timer->source, WaitableTimerHandler);
371 #if defined(TIMER_IMPL_DISPATCH) || defined(TIMER_IMPL_POSIX)
373 TimerCloseHandle(handle);
378 HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
381 HANDLE handle = NULL;
386 name = ConvertWCharToUtf8Alloc(lpTimerName, NULL);
391 handle = CreateWaitableTimerA(lpTimerAttributes, bManualReset, name);
396 HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName,
397 DWORD dwFlags, DWORD dwDesiredAccess)
399 BOOL bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE;
401 if (dwDesiredAccess != 0)
402 WLog_WARN(TAG,
"[%s] does not support dwDesiredAccess 0x%08" PRIx32, lpTimerName,
405 return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName);
408 HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName,
409 DWORD dwFlags, DWORD dwDesiredAccess)
411 HANDLE handle = NULL;
416 name = ConvertWCharToUtf8Alloc(lpTimerName, NULL);
421 handle = CreateWaitableTimerExA(lpTimerAttributes, name, dwFlags, dwDesiredAccess);
426 static void timerAPC(LPVOID arg)
428 WINPR_TIMER* timer = (WINPR_TIMER*)arg;
434 switch (apc_remove(&timer->apcItem))
437 case APC_REMOVE_DELAY_FREE:
439 case APC_REMOVE_ERROR:
441 WLog_ERR(TAG,
"error removing the APC routine");
445 if (timer->pfnCompletionRoutine)
446 timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
448 #ifdef TIMER_IMPL_TIMERFD
449 while (timer_drain_fd(timer->fd))
451 #elif defined(TIMER_IMPL_POSIX) || defined(TIMER_IMPL_DISPATCH)
452 winpr_event_reset(&timer->event);
456 BOOL SetWaitableTimer(HANDLE hTimer,
const LARGE_INTEGER* lpDueTime, LONG lPeriod,
457 PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
462 WINPR_TIMER* timer = NULL;
463 LONGLONG seconds = 0;
464 LONGLONG nanoseconds = 0;
467 if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
470 if (Type != HANDLE_TYPE_TIMER)
481 WLog_ERR(TAG,
"does not support fResume");
485 timer = (WINPR_TIMER*)Object;
486 timer->lPeriod = lPeriod;
487 timer->pfnCompletionRoutine = pfnCompletionRoutine;
488 timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
492 if (InitializeWaitableTimer(timer) < 0)
496 #if defined(TIMER_IMPL_TIMERFD) || defined(TIMER_IMPL_POSIX)
497 ZeroMemory(&(timer->timeout),
sizeof(
struct itimerspec));
499 if (lpDueTime->QuadPart < 0)
501 LONGLONG due = lpDueTime->QuadPart * (-1);
503 seconds = (due / 10000000);
504 nanoseconds = ((due % 10000000) * 100);
506 else if (lpDueTime->QuadPart == 0)
508 seconds = nanoseconds = 0;
512 WLog_ERR(TAG,
"absolute time not implemented");
518 timer->timeout.it_interval.tv_sec = (lPeriod / 1000LL);
519 timer->timeout.it_interval.tv_nsec = (1000000LL * (lPeriod % 1000LL));
522 if (lpDueTime->QuadPart != 0)
524 timer->timeout.it_value.tv_sec = seconds;
525 timer->timeout.it_value.tv_nsec = nanoseconds;
529 timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec;
530 timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec;
533 #ifdef TIMER_IMPL_TIMERFD
534 status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
537 WLog_ERR(TAG,
"timerfd_settime failure: %d", status);
541 status = timer_settime(timer->tid, 0, &(timer->timeout), NULL);
544 WLog_ERR(TAG,
"timer_settime failure");
550 #ifdef TIMER_IMPL_DISPATCH
551 if (lpDueTime->QuadPart < 0)
553 LONGLONG due = lpDueTime->QuadPart * (-1);
555 seconds = (due / 10000000);
556 nanoseconds = due * 100;
558 else if (lpDueTime->QuadPart == 0)
560 seconds = nanoseconds = 0;
564 WLog_ERR(TAG,
"absolute time not implemented");
568 if (!winpr_event_reset(&timer->event))
570 WLog_ERR(TAG,
"error when resetting timer event");
575 dispatch_suspend(timer->source);
577 dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, nanoseconds);
578 uint64_t interval = DISPATCH_TIME_FOREVER;
581 interval = lPeriod * 1000000;
583 dispatch_source_set_timer(timer->source, start, interval, 0);
584 dispatch_resume(timer->source);
585 timer->running = TRUE;
589 if (pfnCompletionRoutine)
591 WINPR_APC_ITEM* apcItem = &timer->apcItem;
594 apcItem->type = APC_TYPE_TIMER;
595 apcItem->alwaysSignaled = FALSE;
596 apcItem->pollFd = timer->fd;
597 apcItem->pollMode = WINPR_FD_READ;
598 apcItem->completion = timerAPC;
599 apcItem->completionArgs = timer;
601 if (!apcItem->linked)
603 WINPR_THREAD* thread = winpr_GetCurrentThread();
607 apc_register(thread, apcItem);
612 if (timer->apcItem.linked)
614 apc_remove(&timer->apcItem);
620 BOOL SetWaitableTimerEx(HANDLE hTimer,
const LARGE_INTEGER* lpDueTime, LONG lPeriod,
621 PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
624 return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine,
625 lpArgToCompletionRoutine, FALSE);
628 HANDLE OpenWaitableTimerA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName)
631 WLog_ERR(TAG,
"not implemented");
635 HANDLE OpenWaitableTimerW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName)
638 WLog_ERR(TAG,
"not implemented");
642 BOOL 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;
670 int 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);
694 static 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);
703 static 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);
712 static 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);
722 static void timespec_copy(
struct timespec* dst,
struct timespec* src)
726 dst->tv_sec = src->tv_sec;
727 dst->tv_nsec = src->tv_nsec;
730 static void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
732 WINPR_TIMER_QUEUE_TIMER* node = NULL;
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;
769 static void RemoveTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
772 WINPR_TIMER_QUEUE_TIMER* node = NULL;
773 WINPR_TIMER_QUEUE_TIMER* prevNode = NULL;
779 *pHead = timer->next;
803 prevNode->next = timer->next;
810 static int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue)
812 struct timespec CurrentTime;
813 WINPR_TIMER_QUEUE_TIMER* node = NULL;
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;
834 timespec_add_ms(&(node->ExpirationTime), node->Period);
835 InsertTimerQueueTimer(&(timerQueue->activeHead), node);
839 InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
842 node = timerQueue->activeHead;
853 static 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))
892 static int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
894 WINPR_ASSERT(timerQueue);
895 pthread_cond_init(&(timerQueue->cond), NULL);
896 pthread_mutex_init(&(timerQueue->cond_mutex), NULL);
897 pthread_mutex_init(&(timerQueue->mutex), NULL);
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);
906 HANDLE CreateTimerQueue(
void)
908 HANDLE handle = NULL;
909 WINPR_TIMER_QUEUE* timerQueue = NULL;
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 = NULL;
917 timerQueue->inactiveHead = NULL;
918 timerQueue->bCancelled = FALSE;
919 StartTimerQueueThread(timerQueue);
925 BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
928 WINPR_TIMER_QUEUE* timerQueue = NULL;
929 WINPR_TIMER_QUEUE_TIMER* node = NULL;
930 WINPR_TIMER_QUEUE_TIMER* nextNode = NULL;
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 = NULL;
964 node = timerQueue->inactiveHead;
968 nextNode = node->next;
973 timerQueue->inactiveHead = NULL;
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);
988 BOOL DeleteTimerQueue(HANDLE TimerQueue)
990 return DeleteTimerQueueEx(TimerQueue, NULL);
993 BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback,
994 PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
996 struct timespec CurrentTime;
997 WINPR_TIMER_QUEUE* timerQueue = NULL;
998 WINPR_TIMER_QUEUE_TIMER* timer = NULL;
1003 timespec_gettimeofday(&CurrentTime);
1004 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1005 timer = (WINPR_TIMER_QUEUE_TIMER*)malloc(
sizeof(WINPR_TIMER_QUEUE_TIMER));
1010 WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER, WINPR_FD_READ);
1011 *((UINT_PTR*)phNewTimer) = (UINT_PTR)(HANDLE)timer;
1012 timespec_copy(&(timer->StartTime), &CurrentTime);
1013 timespec_add_ms(&(timer->StartTime), DueTime);
1014 timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
1015 timer->Flags = Flags;
1016 timer->DueTime = DueTime;
1017 timer->Period = Period;
1018 timer->Callback = Callback;
1019 timer->Parameter = Parameter;
1020 timer->timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1021 timer->FireCount = 0;
1023 pthread_mutex_lock(&(timerQueue->cond_mutex));
1024 InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
1025 pthread_cond_signal(&(timerQueue->cond));
1026 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1030 BOOL ChangeTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period)
1032 struct timespec CurrentTime;
1033 WINPR_TIMER_QUEUE* timerQueue = NULL;
1034 WINPR_TIMER_QUEUE_TIMER* timer = NULL;
1036 if (!TimerQueue || !Timer)
1039 timespec_gettimeofday(&CurrentTime);
1040 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1041 timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
1042 pthread_mutex_lock(&(timerQueue->cond_mutex));
1043 RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
1044 RemoveTimerQueueTimer(&(timerQueue->inactiveHead), timer);
1045 timer->DueTime = DueTime;
1046 timer->Period = Period;
1048 timespec_copy(&(timer->StartTime), &CurrentTime);
1049 timespec_add_ms(&(timer->StartTime), DueTime);
1050 timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
1051 InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
1052 pthread_cond_signal(&(timerQueue->cond));
1053 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1057 BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
1059 WINPR_TIMER_QUEUE* timerQueue = NULL;
1060 WINPR_TIMER_QUEUE_TIMER* timer = NULL;
1062 if (!TimerQueue || !Timer)
1065 timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
1066 timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
1067 pthread_mutex_lock(&(timerQueue->cond_mutex));
1078 RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
1079 pthread_cond_signal(&(timerQueue->cond));
1080 pthread_mutex_unlock(&(timerQueue->cond_mutex));
1083 if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
1084 (void)SetEvent(CompletionEvent);