libwinpr-synch: start implementing waitable timers

This commit is contained in:
Marc-André Moreau 2013-07-29 11:57:29 -04:00
parent 7246cf1f8f
commit 007bd87ff4
6 changed files with 226 additions and 21 deletions

View File

@ -209,6 +209,8 @@ WINPR_API DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWait
/* Waitable Timer */
#define CREATE_WAITABLE_TIMER_MANUAL_RESET 0x00000001
typedef struct _REASON_CONTEXT
{
ULONG Version;
@ -230,6 +232,9 @@ typedef struct _REASON_CONTEXT
typedef VOID (*PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue);
WINPR_API HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName);
WINPR_API HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName);
WINPR_API HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess);
WINPR_API HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess);
@ -245,9 +250,11 @@ WINPR_API HANDLE OpenWaitableTimerW(DWORD dwDesiredAccess, BOOL bInheritHandle,
WINPR_API BOOL CancelWaitableTimer(HANDLE hTimer);
#ifdef UNICODE
#define CreateWaitableTimer CreateWaitableTimerW
#define CreateWaitableTimerEx CreateWaitableTimerExW
#define OpenWaitableTimer OpenWaitableTimerW
#else
#define CreateWaitableTimer CreateWaitableTimerA
#define CreateWaitableTimerEx CreateWaitableTimerExA
#define OpenWaitableTimer OpenWaitableTimerA
#endif

View File

@ -122,6 +122,21 @@ BOOL CloseHandle(HANDLE hObject)
return TRUE;
}
else if (Type == HANDLE_TYPE_TIMER)
{
WINPR_TIMER* timer;
timer = (WINPR_TIMER*) Object;
#ifdef __linux__
if (timer->fd != -1)
close(timer->fd);
#endif
free(Object);
return TRUE;
}
else if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{
WINPR_PIPE* pipe;

View File

@ -25,16 +25,6 @@
#include "synch.h"
/**
* CreateMutexA
* CreateMutexW
* CreateMutexExA
* CreateMutexExW
* OpenMutexA
* OpenMutexW
* ReleaseMutex
*/
#ifndef _WIN32
#include "../handle/handle.h"

View File

@ -20,6 +20,8 @@
#ifndef WINPR_SYNCH_PRIVATE_H
#define WINPR_SYNCH_PRIVATE_H
#include <winpr/platform.h>
#include <winpr/synch.h>
#ifndef _WIN32
@ -68,6 +70,29 @@ struct winpr_event
};
typedef struct winpr_event WINPR_EVENT;
#ifdef __linux__
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#endif
struct winpr_timer
{
WINPR_HANDLE_DEF();
int fd;
LONG lPeriod;
BOOL bManualReset;
PTIMERAPCROUTINE pfnCompletionRoutine;
LPVOID lpArgToCompletionRoutine;
#ifdef __linux__
struct itimerspec timeout;
#endif
};
typedef struct winpr_timer WINPR_TIMER;
#endif
#endif /* WINPR_SYNCH_PRIVATE_H */

View File

@ -21,23 +21,66 @@
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/synch.h>
/**
* CreateWaitableTimerExW
* OpenWaitableTimerW
* SetWaitableTimer
* SetWaitableTimerEx
* CancelWaitableTimer
*/
#include "synch.h"
#ifndef _WIN32
HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
#include "../handle/handle.h"
HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName)
{
HANDLE handle = NULL;
WINPR_TIMER* timer;
timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER));
if (timer)
{
int status = 0;
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;
#ifdef __linux__
timer->fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timer->fd <= 0)
return NULL;
status = fcntl(timer->fd, F_SETFL, O_NONBLOCK);
if (status)
return NULL;
#endif
}
return handle;
}
HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName)
{
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);
}
HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess)
{
return NULL;
@ -46,12 +89,82 @@ HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR l
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;
#ifdef __linux__
ZeroMemory(&(timer->timeout), sizeof(struct itimerspec));
if (lpDueTime < 0)
{
LONGLONG due = lpDueTime->QuadPart * (-1);
/* due time is in 100 nanosecond intervals */
seconds = (due / 10000000);
nanoseconds = ((due % 10000000) * 100);
}
else
{
printf("SetWaitableTimer: implement absolute time\n");
}
timer->timeout.it_value.tv_sec = seconds; /* seconds */
timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */
if (lPeriod > 0)
{
timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */
timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */
}
status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
if (status)
return FALSE;
#endif
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;
}
return TRUE;
}

View File

@ -146,7 +146,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
length = read(semaphore->pipe_fd[0], &length, 1);
if (length != 1)
return FALSE;
return WAIT_FAILED;
}
#else
@ -156,6 +156,46 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
sem_wait((winpr_sem_t*) semaphore->sem);
#endif
#endif
}
else if (Type == HANDLE_TYPE_TIMER)
{
WINPR_TIMER* timer;
timer = (WINPR_TIMER*) Object;
#ifdef __linux__
if (timer->fd != -1)
{
int status;
int length;
fd_set rfds;
struct timeval timeout;
FD_ZERO(&rfds);
FD_SET(timer->fd, &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_usec = dwMilliseconds * 1000;
}
status = select(timer->fd + 1, &rfds, 0, 0,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
if (status < 0)
return WAIT_FAILED;
if (status != 1)
return WAIT_TIMEOUT;
}
else
{
return WAIT_FAILED;
}
#else
return WAIT_FAILED;
#endif
}
else
@ -184,6 +224,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (!nCount)
return WAIT_FAILED;
maxfd = 0;
FD_ZERO(&fds);
ZeroMemory(&timeout, sizeof(timeout));
@ -208,13 +249,18 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
return WAIT_FAILED;
#endif
}
else if (Type == HANDLE_TYPE_TIMER)
{
WINPR_TIMER* timer = (WINPR_TIMER*) Object;
fd = timer->fd;
}
else
{
return WAIT_FAILED;
}
if (fd == -1)
return WAIT_FAILED;
if (fd == -1)
return WAIT_FAILED;
FD_SET(fd, &fds);
@ -241,9 +287,18 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
winpr_Handle_GetInfo(lpHandles[index], &Type, &Object);
if (Type == HANDLE_TYPE_EVENT)
{
fd = ((WINPR_EVENT*) Object)->pipe_fd[0];
}
else if (Type == HANDLE_TYPE_SEMAPHORE)
{
fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0];
}
else if (Type == HANDLE_TYPE_TIMER)
{
WINPR_TIMER* timer = (WINPR_TIMER*) Object;
fd = timer->fd;
}
if (FD_ISSET(fd, &fds))
{