Blame winpr/libwinpr/synch/timer.c

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