#include <winpr/crt.h>
#include <winpr/synch.h>
+#include <winpr/sysinfo.h>
-HANDLE gDoneEvent;
+static int g_Count = 0;
+static HANDLE g_Event = NULL;
+
+struct apc_data
+{
+ UINT32 StartTime;
+};
+typedef struct apc_data APC_DATA;
VOID CALLBACK TimerAPCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
- int param;
+ APC_DATA* apcData;
+ UINT32 CurrentTime = GetTickCount();
if (!lpArg)
return;
- param = *((int*) lpArg);
+ apcData = (APC_DATA*) lpArg;
+
+ printf("TimerAPCProc: time: %d\n", CurrentTime - apcData->StartTime);
- printf("TimerAPCProc: %d\n", param);
+ g_Count++;
- SetEvent(gDoneEvent);
+ if (g_Count >= 5)
+ {
+ SetEvent(g_Event);
+ }
}
int TestSynchWaitableTimerAPC(int argc, char* argv[])
{
- int arg = 123;
HANDLE hTimer;
BOOL bSuccess;
- INT64 qwDueTime;
- LARGE_INTEGER liDueTime;
+ LARGE_INTEGER due;
+ APC_DATA* apcData;
+ apcData = (APC_DATA*) malloc(sizeof(APC_DATA));
+ g_Event = CreateEvent(NULL, TRUE, FALSE, NULL);
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
if (!hTimer)
return -1;
- qwDueTime = -5 * 10000000;
- liDueTime.LowPart = (DWORD) (qwDueTime & 0xFFFFFFFF);
- liDueTime.HighPart = (LONG) (qwDueTime >> 32);
+ due.QuadPart = -15000000LL; /* 1.5 seconds */
- bSuccess = SetWaitableTimer(hTimer, &liDueTime, 2000, TimerAPCProc, &arg, FALSE);
+ apcData->StartTime = GetTickCount();
+ bSuccess = SetWaitableTimer(hTimer, &due, 2000, TimerAPCProc, apcData, FALSE);
if (!bSuccess)
return -1;
- if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
+ if (WaitForSingleObject(g_Event, INFINITE) != WAIT_OBJECT_0)
{
printf("WaitForSingleObject failed (%d)\n", GetLastError());
return -1;
}
- CloseHandle(gDoneEvent);
-
CloseHandle(hTimer);
+ CloseHandle(g_Event);
+ free(apcData);
return 0;
}
#include <winpr/synch.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <signal.h>
+#endif
+
#include "synch.h"
#ifndef _WIN32
#include "../handle/handle.h"
-/**
- * Waitable Timer
- */
+static BOOL g_WaitableTimerSignalHandlerInstalled = FALSE;
-HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName)
+void WaitableTimerSignalHandler(int signum, siginfo_t* siginfo, void* arg)
{
- HANDLE handle = NULL;
- WINPR_TIMER* timer;
+ WINPR_TIMER* timer = siginfo->si_value.sival_ptr;
- timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER));
+ if (!timer || (signum != SIGALRM))
+ return;
- if (timer)
+ if (timer->pfnCompletionRoutine)
{
- int status = 0;
+ timer->pfnCompletionRoutine(timer->lpArgToCompletionRoutine, 0, 0);
- WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER);
- handle = (HANDLE) timer;
+ if (timer->lPeriod)
+ {
+ timer->timeout.it_interval.tv_sec = (timer->lPeriod / 1000); /* seconds */
+ timer->timeout.it_interval.tv_nsec = ((timer->lPeriod % 1000) * 1000000); /* nanoseconds */
- timer->fd = -1;
- timer->lPeriod = 0;
- timer->bManualReset = bManualReset;
- timer->pfnCompletionRoutine = NULL;
- timer->lpArgToCompletionRoutine = NULL;
+ 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)
{
free(timer);
- return NULL;
+ return -1;
}
status = fcntl(timer->fd, F_SETFL, O_NONBLOCK);
if (status)
{
close(timer->fd);
- free(timer);
- return NULL;
+ return -1;
}
#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;
}
timer->pfnCompletionRoutine = pfnCompletionRoutine;
timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine;
-#ifdef HAVE_TIMERFD_H
+ if (!timer->bInit)
+ {
+ if (InitializeWaitableTimer(timer) < 0)
+ return FALSE;
+ }
+
ZeroMemory(&(timer->timeout), sizeof(struct itimerspec));
if (lpDueTime->QuadPart < 0)
timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */
}
- status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
+ if (!timer->pfnCompletionRoutine)
+ {
+#ifdef HAVE_TIMERFD_H
+ status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
- if (status)
+ if (status)
+ {
+ printf("SetWaitableTimer timerfd_settime failure: %d\n", status);
+ return FALSE;
+ }
+#endif
+ }
+ else
{
- printf("SetWaitableTimer timerfd_settime failure: %d\n", status);
- return FALSE;
+ if ((timer_settime(timer->tid, 0, &(timer->timeout), NULL)) != 0)
+ {
+ perror("timer_settime");
+ return FALSE;
+ }
}
-#endif
return TRUE;
}
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;
+
return TRUE;
}
return WAIT_TIMEOUT;
}
else
+ {
pthread_mutex_lock(&mutex->mutex);
+ }
}
else if (Type == HANDLE_TYPE_EVENT)
{
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
- status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL,
- (dwMilliseconds == INFINITE) ? NULL : &timeout);
+ do
+ {
+ status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL,
+ (dwMilliseconds == INFINITE) ? NULL : &timeout);
+ }
+ while (status < 0 && (errno == EINTR));
if (status < 0)
{
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
- status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0,
- (dwMilliseconds == INFINITE) ? NULL : &timeout);
+ do
+ {
+ status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0,
+ (dwMilliseconds == INFINITE) ? NULL : &timeout);
+ }
+ while (status < 0 && (errno == EINTR));
if (status < 0)
{
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
- status = select(timer->fd + 1, &rfds, 0, 0,
- (dwMilliseconds == INFINITE) ? NULL : &timeout);
+ do
+ {
+ status = select(timer->fd + 1, &rfds, 0, 0,
+ (dwMilliseconds == INFINITE) ? NULL : &timeout);
+ }
+ while (status < 0 && (errno == EINTR));
if (status < 0)
{
status = select(fd + 1, &rfds, NULL, NULL,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
}
- while (status < 0 && errno == EINTR);
+ while (status < 0 && (errno == EINTR));
if (status < 0)
{
return WAIT_FAILED;
}
-
maxfd = 0;
FD_ZERO(&fds);
ZeroMemory(&timeout, sizeof(timeout));