|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* WinPR: Windows Portable Runtime
|
|
Packit |
1fb8d4 |
* Synchronization Functions
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
1fb8d4 |
* you may not use this file except in compliance with the License.
|
|
Packit |
1fb8d4 |
* You may obtain a copy of the License at
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
1fb8d4 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
1fb8d4 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
1fb8d4 |
* See the License for the specific language governing permissions and
|
|
Packit |
1fb8d4 |
* limitations under the License.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
1fb8d4 |
#include "config.h"
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <winpr/crt.h>
|
|
Packit |
1fb8d4 |
#include <winpr/file.h>
|
|
Packit |
1fb8d4 |
#include <winpr/sysinfo.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <winpr/synch.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifndef _WIN32
|
|
Packit |
1fb8d4 |
#include <unistd.h>
|
|
Packit |
1fb8d4 |
#include <errno.h>
|
|
Packit |
1fb8d4 |
#include <sys/time.h>
|
|
Packit |
1fb8d4 |
#include <signal.h>
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "synch.h"
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifndef _WIN32
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "../handle/handle.h"
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "../log.h"
|
|
Packit |
1fb8d4 |
#define TAG WINPR_TAG("synch.timer")
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static BOOL TimerCloseHandle(HANDLE handle);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static BOOL TimerIsHandled(HANDLE handle)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
WINPR_TIMER* pTimer = (WINPR_TIMER*)handle;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!pTimer || (pTimer->Type != HANDLE_TYPE_TIMER))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SetLastError(ERROR_INVALID_HANDLE);
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int TimerGetFd(HANDLE handle)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer = (WINPR_TIMER*)handle;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerIsHandled(handle))
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return timer->fd;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
static DWORD TimerCleanupHandle(HANDLE handle)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int length;
|
|
Packit |
1fb8d4 |
UINT64 expirations;
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer = (WINPR_TIMER*)handle;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerIsHandled(handle))
|
|
Packit |
1fb8d4 |
return WAIT_FAILED;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->bManualReset)
|
|
Packit |
1fb8d4 |
return WAIT_OBJECT_0;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
length = read(timer->fd, (void*)&expirations, sizeof(UINT64));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (length != 8)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (length == -1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
switch (errno)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
case ETIMEDOUT:
|
|
Packit |
1fb8d4 |
case EAGAIN:
|
|
Packit |
1fb8d4 |
return WAIT_TIMEOUT;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
default:
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "timer read() failure [%d] %s", errno, strerror(errno));
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "timer read() failure - incorrect number of bytes read");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return WAIT_FAILED;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return WAIT_OBJECT_0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL TimerCloseHandle(HANDLE handle)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer;
|
|
Packit Service |
5a9772 |
timer = (WINPR_TIMER*)handle;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerIsHandled(handle))
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer->lpArgToCompletionRoutine)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
#ifdef HAVE_SYS_TIMERFD_H
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->fd != -1)
|
|
Packit |
1fb8d4 |
close(timer->fd);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
#ifdef WITH_POSIX_TIMER
|
|
Packit |
1fb8d4 |
timer_delete(timer->tid);
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#if defined(__APPLE__)
|
|
Packit |
1fb8d4 |
dispatch_release(timer->queue);
|
|
Packit |
1fb8d4 |
dispatch_release(timer->source);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->pipe[0] != -1)
|
|
Packit |
1fb8d4 |
close(timer->pipe[0]);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->pipe[1] != -1)
|
|
Packit |
1fb8d4 |
close(timer->pipe[1]);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit Service |
5a9772 |
free(timer->name);
|
|
Packit |
1fb8d4 |
free(timer);
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef WITH_POSIX_TIMER
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static BOOL g_WaitableTimerSignalHandlerInstalled = FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void WaitableTimerHandler(void* arg)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer = (WINPR_TIMER*)arg;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer)
|
|
Packit |
1fb8d4 |
return;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->pfnCompletionRoutine)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->lPeriod)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
timer->timeout.it_interval.tv_sec = (timer->lPeriod / 1000); /* seconds */
|
|
Packit Service |
5a9772 |
timer->timeout.it_interval.tv_nsec =
|
|
Packit Service |
5a9772 |
((timer->lPeriod % 1000) * 1000000); /* nanoseconds */
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "timer_settime");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
static void WaitableTimerSignalHandler(int signum, siginfo_t* siginfo, void* arg)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer = siginfo->si_value.sival_ptr;
|
|
Packit Service |
5a9772 |
WINPR_UNUSED(arg);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer || (signum != SIGALRM))
|
|
Packit |
1fb8d4 |
return;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WaitableTimerHandler(timer);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int InstallWaitableTimerSignalHandler(void)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!g_WaitableTimerSignalHandlerInstalled)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
struct sigaction action;
|
|
Packit |
1fb8d4 |
sigemptyset(&action.sa_mask);
|
|
Packit |
1fb8d4 |
sigaddset(&action.sa_mask, SIGALRM);
|
|
Packit |
1fb8d4 |
action.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
Packit |
1fb8d4 |
action.sa_sigaction = WaitableTimerSignalHandler;
|
|
Packit |
1fb8d4 |
sigaction(SIGALRM, &action, NULL);
|
|
Packit |
1fb8d4 |
g_WaitableTimerSignalHandlerInstalled = TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#if defined(__APPLE__)
|
|
Packit |
1fb8d4 |
static void WaitableTimerHandler(void* arg)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT64 data = 1;
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer = (WINPR_TIMER*)arg;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer)
|
|
Packit |
1fb8d4 |
return;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->pfnCompletionRoutine)
|
|
Packit |
1fb8d4 |
timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (write(timer->pipe[1], &data, sizeof(data)) != sizeof(data))
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "failed to write to pipe");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->lPeriod == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (timer->running)
|
|
Packit |
1fb8d4 |
dispatch_suspend(timer->source);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer->running = FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int InitializeWaitableTimer(WINPR_TIMER* timer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int result = 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer->lpArgToCompletionRoutine)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
#ifdef HAVE_SYS_TIMERFD_H
|
|
Packit |
1fb8d4 |
timer->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->fd <= 0)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#elif defined(__APPLE__)
|
|
Packit |
1fb8d4 |
#else
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "%s: os specific implementation is missing", __FUNCTION__);
|
|
Packit |
1fb8d4 |
result = -1;
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
#ifdef WITH_POSIX_TIMER
|
|
Packit |
1fb8d4 |
struct sigevent sigev;
|
|
Packit |
1fb8d4 |
InstallWaitableTimerSignalHandler();
|
|
Packit |
1fb8d4 |
ZeroMemory(&sigev, sizeof(struct sigevent));
|
|
Packit |
1fb8d4 |
sigev.sigev_notify = SIGEV_SIGNAL;
|
|
Packit |
1fb8d4 |
sigev.sigev_signo = SIGALRM;
|
|
Packit Service |
5a9772 |
sigev.sigev_value.sival_ptr = (void*)timer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((timer_create(CLOCK_MONOTONIC, &sigev, &(timer->tid))) != 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "timer_create");
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#elif defined(__APPLE__)
|
|
Packit |
1fb8d4 |
#else
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "%s: os specific implementation is missing", __FUNCTION__);
|
|
Packit |
1fb8d4 |
result = -1;
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer->bInit = TRUE;
|
|
Packit |
1fb8d4 |
return result;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
static HANDLE_OPS ops = { TimerIsHandled, TimerCloseHandle,
|
|
Packit Service |
5a9772 |
TimerGetFd, TimerCleanupHandle,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL,
|
|
Packit Service |
5a9772 |
NULL, NULL };
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Waitable Timer
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
|
|
Packit |
1fb8d4 |
LPCSTR lpTimerName)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
HANDLE handle = NULL;
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (lpTimerAttributes)
|
|
Packit Service |
5a9772 |
WLog_WARN(TAG, "%s [%s] does not support lpTimerAttributes", __FUNCTION__, lpTimerName);
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
timer = (WINPR_TIMER*)calloc(1, sizeof(WINPR_TIMER));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER, WINPR_FD_READ);
|
|
Packit Service |
5a9772 |
handle = (HANDLE)timer;
|
|
Packit |
1fb8d4 |
timer->fd = -1;
|
|
Packit |
1fb8d4 |
timer->lPeriod = 0;
|
|
Packit |
1fb8d4 |
timer->bManualReset = bManualReset;
|
|
Packit |
1fb8d4 |
timer->pfnCompletionRoutine = NULL;
|
|
Packit |
1fb8d4 |
timer->lpArgToCompletionRoutine = NULL;
|
|
Packit |
1fb8d4 |
timer->bInit = FALSE;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (lpTimerName)
|
|
Packit Service |
5a9772 |
timer->name = strdup(lpTimerName);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
timer->ops = &ops;
|
|
Packit |
1fb8d4 |
#if defined(__APPLE__)
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (pipe(timer->pipe) != 0)
|
|
Packit |
1fb8d4 |
goto fail;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer->queue = dispatch_queue_create(TAG, DISPATCH_QUEUE_SERIAL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer->queue)
|
|
Packit |
1fb8d4 |
goto fail;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->queue);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer->source)
|
|
Packit |
1fb8d4 |
goto fail;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
dispatch_set_context(timer->source, timer);
|
|
Packit |
1fb8d4 |
dispatch_source_set_event_handler_f(timer->source, WaitableTimerHandler);
|
|
Packit |
1fb8d4 |
timer->fd = timer->pipe[0];
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (fcntl(timer->fd, F_SETFL, O_NONBLOCK) < 0)
|
|
Packit |
1fb8d4 |
goto fail;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return handle;
|
|
Packit |
1fb8d4 |
#if defined(__APPLE__)
|
|
Packit |
1fb8d4 |
fail:
|
|
Packit |
1fb8d4 |
TimerCloseHandle(handle);
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset,
|
|
Packit |
1fb8d4 |
LPCWSTR lpTimerName)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int rc;
|
|
Packit |
1fb8d4 |
HANDLE handle;
|
|
Packit |
1fb8d4 |
LPSTR name = NULL;
|
|
Packit |
1fb8d4 |
rc = ConvertFromUnicode(CP_UTF8, 0, lpTimerName, -1, &name, 0, NULL, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (rc < 0)
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
handle = CreateWaitableTimerA(lpTimerAttributes, bManualReset, name);
|
|
Packit |
1fb8d4 |
free(name);
|
|
Packit |
1fb8d4 |
return handle;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName,
|
|
Packit |
1fb8d4 |
DWORD dwFlags, DWORD dwDesiredAccess)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
BOOL bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
if (dwDesiredAccess != 0)
|
|
Packit Service |
5a9772 |
WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
|
|
Packit Service |
5a9772 |
lpTimerName, dwDesiredAccess);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName,
|
|
Packit |
1fb8d4 |
DWORD dwFlags, DWORD dwDesiredAccess)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int rc;
|
|
Packit |
1fb8d4 |
HANDLE handle;
|
|
Packit |
1fb8d4 |
LPSTR name = NULL;
|
|
Packit |
1fb8d4 |
rc = ConvertFromUnicode(CP_UTF8, 0, lpTimerName, -1, &name, 0, NULL, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (rc < 0)
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
handle = CreateWaitableTimerExA(lpTimerAttributes, name, dwFlags, dwDesiredAccess);
|
|
Packit |
1fb8d4 |
free(name);
|
|
Packit |
1fb8d4 |
return handle;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
|
|
Packit Service |
5a9772 |
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
|
|
Packit Service |
5a9772 |
BOOL fResume)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
ULONG Type;
|
|
Packit |
1fb8d4 |
WINPR_HANDLE* Object;
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer;
|
|
Packit |
1fb8d4 |
#if defined(WITH_POSIX_TIMER) || defined(__APPLE__)
|
|
Packit |
1fb8d4 |
LONGLONG seconds = 0;
|
|
Packit |
1fb8d4 |
LONGLONG nanoseconds = 0;
|
|
Packit |
1fb8d4 |
#ifdef HAVE_SYS_TIMERFD_H
|
|
Packit |
1fb8d4 |
int status = 0;
|
|
Packit |
1fb8d4 |
#endif /* HAVE_SYS_TIMERFD_H */
|
|
Packit |
1fb8d4 |
#endif /* WITH_POSIX_TIMER */
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Type != HANDLE_TYPE_TIMER)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!lpDueTime)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lPeriod < 0)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
if (fResume)
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG, "%s does not support fResume", __FUNCTION__);
|
|
Packit Service |
5a9772 |
return FALSE;
|
|
Packit Service |
5a9772 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
timer = (WINPR_TIMER*)Object;
|
|
Packit |
1fb8d4 |
timer->lPeriod = lPeriod; /* milliseconds */
|
|
Packit |
1fb8d4 |
timer->pfnCompletionRoutine = pfnCompletionRoutine;
|
|
Packit |
1fb8d4 |
timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer->bInit)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (InitializeWaitableTimer(timer) < 0)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef WITH_POSIX_TIMER
|
|
Packit |
1fb8d4 |
ZeroMemory(&(timer->timeout), sizeof(struct itimerspec));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lpDueTime->QuadPart < 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
LONGLONG due = lpDueTime->QuadPart * (-1);
|
|
Packit |
1fb8d4 |
/* due time is in 100 nanosecond intervals */
|
|
Packit |
1fb8d4 |
seconds = (due / 10000000);
|
|
Packit |
1fb8d4 |
nanoseconds = ((due % 10000000) * 100);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else if (lpDueTime->QuadPart == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
seconds = nanoseconds = 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "absolute time not implemented");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lPeriod > 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */
|
|
Packit |
1fb8d4 |
timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lpDueTime->QuadPart != 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
timer->timeout.it_value.tv_sec = seconds; /* seconds */
|
|
Packit |
1fb8d4 |
timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec; /* seconds */
|
|
Packit |
1fb8d4 |
timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer->pfnCompletionRoutine)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
#ifdef HAVE_SYS_TIMERFD_H
|
|
Packit |
1fb8d4 |
status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (status)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "timerfd_settime failure: %d", status);
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "timer_settime");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#elif defined(__APPLE__)
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lpDueTime->QuadPart < 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
LONGLONG due = lpDueTime->QuadPart * (-1);
|
|
Packit |
1fb8d4 |
/* due time is in 100 nanosecond intervals */
|
|
Packit |
1fb8d4 |
seconds = (due / 10000000);
|
|
Packit |
1fb8d4 |
nanoseconds = due * 100;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else if (lpDueTime->QuadPart == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
seconds = nanoseconds = 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "absolute time not implemented");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Clean out old data from FD */
|
|
Packit |
1fb8d4 |
BYTE buffer[32];
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
while (read(timer->fd, buffer, sizeof(buffer)) > 0)
|
|
Packit Service |
5a9772 |
;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (timer->running)
|
|
Packit |
1fb8d4 |
dispatch_suspend(timer->source);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, nanoseconds);
|
|
Packit |
1fb8d4 |
uint64_t interval = DISPATCH_TIME_FOREVER;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lPeriod > 0)
|
|
Packit |
1fb8d4 |
interval = lPeriod * 1000000;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
dispatch_source_set_timer(timer->source, start, interval, 0);
|
|
Packit |
1fb8d4 |
dispatch_resume(timer->source);
|
|
Packit |
1fb8d4 |
timer->running = TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
|
|
Packit Service |
5a9772 |
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine,
|
|
Packit Service |
5a9772 |
PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine,
|
|
Packit Service |
5a9772 |
lpArgToCompletionRoutine, FALSE);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE OpenWaitableTimerA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
/* TODO: Implement */
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE OpenWaitableTimerW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
/* TODO: Implement */
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL CancelWaitableTimer(HANDLE hTimer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
ULONG Type;
|
|
Packit |
1fb8d4 |
WINPR_HANDLE* Object;
|
|
Packit |
1fb8d4 |
WINPR_TIMER* timer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Type != HANDLE_TYPE_TIMER)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer = (WINPR_TIMER*)Object;
|
|
Packit |
1fb8d4 |
#if defined(__APPLE__)
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer->running)
|
|
Packit |
1fb8d4 |
dispatch_suspend(timer->source);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer->running = FALSE;
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Timer-Queue Timer
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Design, Performance, and Optimization of Timer Strategies for Real-time ORBs:
|
|
Packit |
1fb8d4 |
* http://www.cs.wustl.edu/~schmidt/Timer_Queue.html
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void timespec_add_ms(struct timespec* tspec, UINT32 ms)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT64 ns = tspec->tv_nsec + (ms * 1000000);
|
|
Packit |
1fb8d4 |
tspec->tv_sec += (ns / 1000000000);
|
|
Packit |
1fb8d4 |
tspec->tv_nsec = (ns % 1000000000);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void timespec_gettimeofday(struct timespec* tspec)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
struct timeval tval;
|
|
Packit |
1fb8d4 |
gettimeofday(&tval, NULL);
|
|
Packit |
1fb8d4 |
tspec->tv_sec = tval.tv_sec;
|
|
Packit |
1fb8d4 |
tspec->tv_nsec = tval.tv_usec * 1000;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int timespec_compare(const struct timespec* tspec1, const struct timespec* tspec2)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (tspec1->tv_sec == tspec2->tv_sec)
|
|
Packit |
1fb8d4 |
return (tspec1->tv_nsec - tspec2->tv_nsec);
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
return (tspec1->tv_sec - tspec2->tv_sec);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void timespec_copy(struct timespec* dst, struct timespec* src)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
dst->tv_sec = src->tv_sec;
|
|
Packit |
1fb8d4 |
dst->tv_nsec = src->tv_nsec;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void InsertTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* node;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!(*pHead))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
*pHead = timer;
|
|
Packit |
1fb8d4 |
timer->next = NULL;
|
|
Packit |
1fb8d4 |
return;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
node = *pHead;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (node->next)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (timespec_compare(&(timer->ExpirationTime), &(node->ExpirationTime)) > 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (timespec_compare(&(timer->ExpirationTime), &(node->next->ExpirationTime)) < 0)
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
node = node->next;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (node->next)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
timer->next = node->next->next;
|
|
Packit |
1fb8d4 |
node->next = timer;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
node->next = timer;
|
|
Packit |
1fb8d4 |
timer->next = NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void RemoveTimerQueueTimer(WINPR_TIMER_QUEUE_TIMER** pHead, WINPR_TIMER_QUEUE_TIMER* timer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
BOOL found = FALSE;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* node;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* prevNode;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timer == *pHead)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
*pHead = timer->next;
|
|
Packit |
1fb8d4 |
timer->next = NULL;
|
|
Packit |
1fb8d4 |
return;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
node = *pHead;
|
|
Packit |
1fb8d4 |
prevNode = NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (node)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (node == timer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
found = TRUE;
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
prevNode = node;
|
|
Packit |
1fb8d4 |
node = node->next;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (found)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (prevNode)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
prevNode->next = timer->next;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timer->next = NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int FireExpiredTimerQueueTimers(WINPR_TIMER_QUEUE* timerQueue)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
struct timespec CurrentTime;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* node;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timerQueue->activeHead)
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timespec_gettimeofday(&CurrentTime);
|
|
Packit |
1fb8d4 |
node = timerQueue->activeHead;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (node)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (timespec_compare(&CurrentTime, &(node->ExpirationTime)) >= 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
node->Callback(node->Parameter, TRUE);
|
|
Packit |
1fb8d4 |
node->FireCount++;
|
|
Packit |
1fb8d4 |
timerQueue->activeHead = node->next;
|
|
Packit |
1fb8d4 |
node->next = NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (node->Period)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
timespec_add_ms(&(node->ExpirationTime), node->Period);
|
|
Packit |
1fb8d4 |
InsertTimerQueueTimer(&(timerQueue->activeHead), node);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
node = timerQueue->activeHead;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void* TimerQueueThread(void* arg)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int status;
|
|
Packit |
1fb8d4 |
struct timespec timeout;
|
|
Packit Service |
5a9772 |
WINPR_TIMER_QUEUE* timerQueue = (WINPR_TIMER_QUEUE*)arg;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
pthread_mutex_lock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
timespec_gettimeofday(&timeout);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timerQueue->activeHead)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
timespec_add_ms(&timeout, 50);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (timespec_compare(&timeout, &(timerQueue->activeHead->ExpirationTime)) < 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
timespec_copy(&timeout, &(timerQueue->activeHead->ExpirationTime));
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
status = pthread_cond_timedwait(&(timerQueue->cond), &(timerQueue->cond_mutex), &timeout);
|
|
Packit |
1fb8d4 |
FireExpiredTimerQueueTimers(timerQueue);
|
|
Packit |
1fb8d4 |
pthread_mutex_unlock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((status != ETIMEDOUT) && (status != 0))
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timerQueue->bCancelled)
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int StartTimerQueueThread(WINPR_TIMER_QUEUE* timerQueue)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
pthread_cond_init(&(timerQueue->cond), NULL);
|
|
Packit |
1fb8d4 |
pthread_mutex_init(&(timerQueue->cond_mutex), NULL);
|
|
Packit |
1fb8d4 |
pthread_mutex_init(&(timerQueue->mutex), NULL);
|
|
Packit |
1fb8d4 |
pthread_attr_init(&(timerQueue->attr));
|
|
Packit |
1fb8d4 |
timerQueue->param.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
Packit |
1fb8d4 |
pthread_attr_setschedparam(&(timerQueue->attr), &(timerQueue->param));
|
|
Packit |
1fb8d4 |
pthread_attr_setschedpolicy(&(timerQueue->attr), SCHED_FIFO);
|
|
Packit |
1fb8d4 |
pthread_create(&(timerQueue->thread), &(timerQueue->attr), TimerQueueThread, timerQueue);
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
HANDLE CreateTimerQueue(void)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
HANDLE handle = NULL;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE* timerQueue;
|
|
Packit Service |
5a9772 |
timerQueue = (WINPR_TIMER_QUEUE*)calloc(1, sizeof(WINPR_TIMER_QUEUE));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (timerQueue)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_HANDLE_SET_TYPE_AND_MODE(timerQueue, HANDLE_TYPE_TIMER_QUEUE, WINPR_FD_READ);
|
|
Packit Service |
5a9772 |
handle = (HANDLE)timerQueue;
|
|
Packit |
1fb8d4 |
timerQueue->activeHead = NULL;
|
|
Packit |
1fb8d4 |
timerQueue->inactiveHead = NULL;
|
|
Packit |
1fb8d4 |
timerQueue->bCancelled = FALSE;
|
|
Packit |
1fb8d4 |
StartTimerQueueThread(timerQueue);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return handle;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
void* rvalue;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE* timerQueue;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* node;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* nextNode;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerQueue)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
|
|
Packit |
1fb8d4 |
/* Cancel and delete timer queue timers */
|
|
Packit |
1fb8d4 |
pthread_mutex_lock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
timerQueue->bCancelled = TRUE;
|
|
Packit |
1fb8d4 |
pthread_cond_signal(&(timerQueue->cond));
|
|
Packit |
1fb8d4 |
pthread_mutex_unlock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
pthread_join(timerQueue->thread, &rvalue);
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Quote from MSDN regarding CompletionEvent:
|
|
Packit |
1fb8d4 |
* If this parameter is INVALID_HANDLE_VALUE, the function waits for
|
|
Packit |
1fb8d4 |
* all callback functions to complete before returning.
|
|
Packit |
1fb8d4 |
* If this parameter is NULL, the function marks the timer for
|
|
Packit |
1fb8d4 |
* deletion and returns immediately.
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Note: The current WinPR implementation implicitly waits for any
|
|
Packit |
1fb8d4 |
* callback functions to complete (see pthread_join above)
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Move all active timers to the inactive timer list */
|
|
Packit |
1fb8d4 |
node = timerQueue->activeHead;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (node)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
InsertTimerQueueTimer(&(timerQueue->inactiveHead), node);
|
|
Packit |
1fb8d4 |
node = node->next;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timerQueue->activeHead = NULL;
|
|
Packit |
1fb8d4 |
/* Once all timers are inactive, free them */
|
|
Packit |
1fb8d4 |
node = timerQueue->inactiveHead;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
while (node)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
nextNode = node->next;
|
|
Packit |
1fb8d4 |
free(node);
|
|
Packit |
1fb8d4 |
node = nextNode;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timerQueue->inactiveHead = NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
/* Delete timer queue */
|
|
Packit |
1fb8d4 |
pthread_cond_destroy(&(timerQueue->cond));
|
|
Packit |
1fb8d4 |
pthread_mutex_destroy(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
pthread_mutex_destroy(&(timerQueue->mutex));
|
|
Packit |
1fb8d4 |
pthread_attr_destroy(&(timerQueue->attr));
|
|
Packit |
1fb8d4 |
free(timerQueue);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
|
|
Packit |
1fb8d4 |
SetEvent(CompletionEvent);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL DeleteTimerQueue(HANDLE TimerQueue)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return DeleteTimerQueueEx(TimerQueue, NULL);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback,
|
|
Packit Service |
5a9772 |
PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
struct timespec CurrentTime;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE* timerQueue;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* timer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerQueue)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timespec_gettimeofday(&CurrentTime);
|
|
Packit Service |
5a9772 |
timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
|
|
Packit Service |
5a9772 |
timer = (WINPR_TIMER_QUEUE_TIMER*)malloc(sizeof(WINPR_TIMER_QUEUE_TIMER));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!timer)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WINPR_HANDLE_SET_TYPE_AND_MODE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER, WINPR_FD_READ);
|
|
Packit Service |
5a9772 |
*((UINT_PTR*)phNewTimer) = (UINT_PTR)(HANDLE)timer;
|
|
Packit |
1fb8d4 |
timespec_copy(&(timer->StartTime), &CurrentTime);
|
|
Packit |
1fb8d4 |
timespec_add_ms(&(timer->StartTime), DueTime);
|
|
Packit |
1fb8d4 |
timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
|
|
Packit |
1fb8d4 |
timer->Flags = Flags;
|
|
Packit |
1fb8d4 |
timer->DueTime = DueTime;
|
|
Packit |
1fb8d4 |
timer->Period = Period;
|
|
Packit |
1fb8d4 |
timer->Callback = Callback;
|
|
Packit |
1fb8d4 |
timer->Parameter = Parameter;
|
|
Packit Service |
5a9772 |
timer->timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
|
|
Packit |
1fb8d4 |
timer->FireCount = 0;
|
|
Packit |
1fb8d4 |
timer->next = NULL;
|
|
Packit |
1fb8d4 |
pthread_mutex_lock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
|
|
Packit |
1fb8d4 |
pthread_cond_signal(&(timerQueue->cond));
|
|
Packit |
1fb8d4 |
pthread_mutex_unlock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL ChangeTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
struct timespec CurrentTime;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE* timerQueue;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* timer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerQueue || !Timer)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
timespec_gettimeofday(&CurrentTime);
|
|
Packit Service |
5a9772 |
timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
|
|
Packit Service |
5a9772 |
timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
|
|
Packit |
1fb8d4 |
pthread_mutex_lock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
|
|
Packit |
1fb8d4 |
RemoveTimerQueueTimer(&(timerQueue->inactiveHead), timer);
|
|
Packit |
1fb8d4 |
timer->DueTime = DueTime;
|
|
Packit |
1fb8d4 |
timer->Period = Period;
|
|
Packit |
1fb8d4 |
timer->next = NULL;
|
|
Packit |
1fb8d4 |
timespec_copy(&(timer->StartTime), &CurrentTime);
|
|
Packit |
1fb8d4 |
timespec_add_ms(&(timer->StartTime), DueTime);
|
|
Packit |
1fb8d4 |
timespec_copy(&(timer->ExpirationTime), &(timer->StartTime));
|
|
Packit |
1fb8d4 |
InsertTimerQueueTimer(&(timerQueue->activeHead), timer);
|
|
Packit |
1fb8d4 |
pthread_cond_signal(&(timerQueue->cond));
|
|
Packit |
1fb8d4 |
pthread_mutex_unlock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE* timerQueue;
|
|
Packit |
1fb8d4 |
WINPR_TIMER_QUEUE_TIMER* timer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!TimerQueue || !Timer)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
timerQueue = (WINPR_TIMER_QUEUE*)TimerQueue;
|
|
Packit Service |
5a9772 |
timer = (WINPR_TIMER_QUEUE_TIMER*)Timer;
|
|
Packit |
1fb8d4 |
pthread_mutex_lock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Quote from MSDN regarding CompletionEvent:
|
|
Packit |
1fb8d4 |
* If this parameter is INVALID_HANDLE_VALUE, the function waits for
|
|
Packit |
1fb8d4 |
* all callback functions to complete before returning.
|
|
Packit |
1fb8d4 |
* If this parameter is NULL, the function marks the timer for
|
|
Packit |
1fb8d4 |
* deletion and returns immediately.
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Note: The current WinPR implementation implicitly waits for any
|
|
Packit |
1fb8d4 |
* callback functions to complete (see cond_mutex usage)
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
RemoveTimerQueueTimer(&(timerQueue->activeHead), timer);
|
|
Packit |
1fb8d4 |
pthread_cond_signal(&(timerQueue->cond));
|
|
Packit |
1fb8d4 |
pthread_mutex_unlock(&(timerQueue->cond_mutex));
|
|
Packit |
1fb8d4 |
free(timer);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (CompletionEvent && (CompletionEvent != INVALID_HANDLE_VALUE))
|
|
Packit |
1fb8d4 |
SetEvent(CompletionEvent);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|