FreeRDP/winpr/libwinpr/synch/timer.c

410 lines
8.4 KiB
C
Raw Normal View History

2012-09-18 23:51:33 +04:00
/**
* WinPR: Windows Portable Runtime
* Synchronization Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
2012-09-18 23:51:33 +04:00
#include <winpr/synch.h>
#ifndef _WIN32
#include <sys/time.h>
#include <signal.h>
#endif
#include "synch.h"
2012-09-18 23:51:33 +04:00
#ifndef _WIN32
#include "../handle/handle.h"
static BOOL g_WaitableTimerSignalHandlerInstalled = FALSE;
2014-01-25 02:48:55 +04:00
void WaitableTimerSignalHandler(int signum, siginfo_t* siginfo, void* arg)
{
WINPR_TIMER* timer = siginfo->si_value.sival_ptr;
if (!timer || (signum != SIGALRM))
return;
if (timer->pfnCompletionRoutine)
{
timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
if (timer->lPeriod)
{
timer->timeout.it_interval.tv_sec = (timer->lPeriod / 1000); /* seconds */
timer->timeout.it_interval.tv_nsec = ((timer->lPeriod % 1000) * 1000000); /* nanoseconds */
if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0)
{
perror("timer_settime");
}
}
}
}
int InstallWaitableTimerSignalHandler()
{
if (!g_WaitableTimerSignalHandlerInstalled)
{
struct sigaction action;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGALRM);
action.sa_flags = SA_RESTART | SA_SIGINFO;
action.sa_sigaction = (void*) &WaitableTimerSignalHandler;
sigaction(SIGALRM, &action, NULL);
g_WaitableTimerSignalHandlerInstalled = TRUE;
}
return 0;
}
int InitializeWaitableTimer(WINPR_TIMER* timer)
{
int status;
if (!timer->lpArgToCompletionRoutine)
{
#ifdef HAVE_TIMERFD_H
timer->fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timer->fd <= 0)
2013-08-29 17:30:22 +04:00
{
free(timer);
return -1;
2013-08-29 17:30:22 +04:00
}
status = fcntl(timer->fd, F_SETFL, O_NONBLOCK);
if (status)
2013-08-29 17:30:22 +04:00
{
close(timer->fd);
return -1;
2013-08-29 17:30:22 +04:00
}
#endif
}
else
{
struct sigevent sigev;
InstallWaitableTimerSignalHandler();
ZeroMemory(&sigev, sizeof(struct sigevent));
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGALRM;
sigev.sigev_value.sival_ptr = (void*) timer;
if ((timer_create(CLOCK_MONOTONIC, &sigev, &(timer->tid))) != 0)
{
perror("timer_create");
return -1;
}
}
timer->bInit = TRUE;
return 0;
}
/**
* Waitable Timer
*/
HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName)
{
HANDLE handle = NULL;
WINPR_TIMER* timer;
timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER));
if (timer)
{
WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER);
handle = (HANDLE) timer;
timer->fd = -1;
timer->lPeriod = 0;
timer->bManualReset = bManualReset;
timer->pfnCompletionRoutine = NULL;
timer->lpArgToCompletionRoutine = NULL;
timer->bInit = FALSE;
}
return handle;
}
HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName)
2012-09-18 23:51:33 +04:00
{
return NULL;
}
HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
{
BOOL bManualReset;
bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE;
return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName);
}
2012-09-18 23:51:33 +04:00
HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
{
return NULL;
}
BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume)
{
ULONG Type;
PVOID Object;
int status = 0;
WINPR_TIMER* timer;
LONGLONG seconds = 0;
LONGLONG nanoseconds = 0;
if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
return FALSE;
if (Type != HANDLE_TYPE_TIMER)
return FALSE;
if (!lpDueTime)
return FALSE;
if (lPeriod < 0)
return FALSE;
timer = (WINPR_TIMER*) Object;
timer->lPeriod = lPeriod; /* milliseconds */
timer->pfnCompletionRoutine = pfnCompletionRoutine;
timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
if (!timer->bInit)
{
if (InitializeWaitableTimer(timer) < 0)
return FALSE;
}
ZeroMemory(&(timer->timeout), sizeof(struct itimerspec));
if (lpDueTime->QuadPart < 0)
{
LONGLONG due = lpDueTime->QuadPart * (-1);
/* due time is in 100 nanosecond intervals */
seconds = (due / 10000000);
nanoseconds = ((due % 10000000) * 100);
}
else if (lpDueTime->QuadPart == 0)
{
seconds = nanoseconds = 0;
}
else
{
printf("SetWaitableTimer: implement absolute time\n");
return FALSE;
}
if (lPeriod > 0)
{
timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */
timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */
}
if (lpDueTime->QuadPart != 0)
{
timer->timeout.it_value.tv_sec = seconds; /* seconds */
timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */
}
else
{
timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec; /* seconds */
timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */
}
if (!timer->pfnCompletionRoutine)
{
#ifdef HAVE_TIMERFD_H
status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
if (status)
{
printf("SetWaitableTimer timerfd_settime failure: %d\n", status);
return FALSE;
}
#endif
}
else
{
if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0)
{
perror("timer_settime");
return FALSE;
}
}
2012-09-18 23:51:33 +04:00
return TRUE;
}
BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
{
ULONG Type;
PVOID Object;
WINPR_TIMER* timer;
if (!winpr_Handle_GetInfo(hTimer, &Type, &Object))
return FALSE;
if (Type == HANDLE_TYPE_TIMER)
{
timer = (WINPR_TIMER*) Object;
return TRUE;
}
2012-09-18 23:51:33 +04:00
return TRUE;
}
HANDLE OpenWaitableTimerA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName)
{
return NULL;
}
HANDLE OpenWaitableTimerW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName)
{
return NULL;
}
BOOL CancelWaitableTimer(HANDLE hTimer)
{
return TRUE;
}
2014-01-25 02:48:55 +04:00
/**
* Timer-Queue Timer
*/
HANDLE CreateTimerQueue(void)
{
HANDLE handle = NULL;
WINPR_TIMER_QUEUE* timerQueue;
timerQueue = (WINPR_TIMER_QUEUE*) malloc(sizeof(WINPR_TIMER_QUEUE));
if (timerQueue)
{
WINPR_HANDLE_SET_TYPE(timerQueue, HANDLE_TYPE_TIMER_QUEUE);
handle = (HANDLE) timerQueue;
}
return handle;
}
BOOL DeleteTimerQueue(HANDLE TimerQueue)
{
WINPR_TIMER_QUEUE* timerQueue;
if (!TimerQueue)
return FALSE;
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
free(timerQueue);
return TRUE;
}
BOOL DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
{
WINPR_TIMER_QUEUE* timerQueue;
if (!TimerQueue)
return FALSE;
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
free(timerQueue);
return TRUE;
}
BOOL CreateTimerQueueTimer(PHANDLE phNewTimer, HANDLE TimerQueue,
WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
{
WINPR_TIMER_QUEUE_TIMER* timer;
timer = (WINPR_TIMER_QUEUE_TIMER*) malloc(sizeof(WINPR_TIMER_QUEUE_TIMER));
if (!timer)
return FALSE;
WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER_QUEUE_TIMER);
*((UINT_PTR*) phNewTimer) = (UINT_PTR) (HANDLE) timer;
timer->Flags = Flags;
timer->DueTime = DueTime;
timer->Period = Period;
timer->Callback = Callback;
timer->Parameter = Parameter;
2014-01-25 02:48:55 +04:00
return TRUE;
}
BOOL ChangeTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period)
{
WINPR_TIMER_QUEUE* timerQueue;
WINPR_TIMER_QUEUE_TIMER* timer;
if (!TimerQueue || !Timer)
return FALSE;
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
timer = (WINPR_TIMER_QUEUE_TIMER*) Timer;
return TRUE;
}
BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
{
WINPR_TIMER_QUEUE* timerQueue;
WINPR_TIMER_QUEUE_TIMER* timer;
if (!TimerQueue || !Timer)
return FALSE;
timerQueue = (WINPR_TIMER_QUEUE*) TimerQueue;
timer = (WINPR_TIMER_QUEUE_TIMER*) Timer;
free(timer);
return TRUE;
}
#endif