#endif
#include <assert.h>
+#include <errno.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
+#include <winpr/platform.h>
#include "synch.h"
#include "../thread/thread.h"
#ifndef _WIN32
+#include <time.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
#include "../handle/handle.h"
+#include "../pipe/pipe.h"
+
+#ifdef __MACH__
+
+#include <mach/mach_time.h>
+
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 0
+
+int clock_gettime(int clk_id, struct timespec *t)
+{
+ UINT64 time;
+ double seconds;
+ double nseconds;
+ mach_timebase_info_data_t timebase;
+
+ mach_timebase_info(&timebase);
+ time = mach_absolute_time();
+
+ nseconds = ((double) time * (double) timebase.numer) / ((double) timebase.denom);
+ seconds = ((double) time * (double) timebase.numer) / ((double) timebase.denom * 1e9);
+
+ t->tv_sec = seconds;
+ t->tv_nsec = nseconds;
+
+ return 0;
+}
+
+#endif
+
+/* Drop in replacement for the linux pthread_timedjoin_np and
+ * pthread_mutex_timedlock functions.
+ */
+#if !defined(HAVE_PTHREAD_GNU_EXT)
+#include <pthread.h>
+static int pthread_timedjoin_np(pthread_t td, void **res,
+ struct timespec *timeout)
+{
+ struct timeval timenow;
+ struct timespec sleepytime;
+ /* This is just to avoid a completely busy wait */
+ sleepytime.tv_sec = 0;
+ sleepytime.tv_nsec = 10000000; /* 10ms */
+
+ do
+ {
+ if (pthread_kill(td, 0))
+ return pthread_join(td, res);
+
+ nanosleep(&sleepytime, NULL);
+
+ gettimeofday(&timenow, NULL);
+
+ if (timenow.tv_sec >= timeout->tv_sec &&
+ (timenow.tv_usec * 1000) >= timeout->tv_nsec)
+ {
+ return ETIMEDOUT;
+ }
+ }
+ while (TRUE);
+
+ return ETIMEDOUT;
+}
+
+static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout)
+{
+ struct timeval timenow;
+ struct timespec sleepytime;
+ int retcode;
+
+ /* This is just to avoid a completely busy wait */
+ sleepytime.tv_sec = 0;
+ sleepytime.tv_nsec = 10000000; /* 10ms */
+
+ while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY)
+ {
+ gettimeofday (&timenow, NULL);
+
+ if (timenow.tv_sec >= timeout->tv_sec &&
+ (timenow.tv_usec * 1000) >= timeout->tv_nsec)
+ {
+ return ETIMEDOUT;
+ }
+
+ nanosleep (&sleepytime, NULL);
+ }
+
+ return retcode;
+}
+#endif
+
static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds)
{
ts->tv_sec += dwMilliseconds / 1000L;
if (thread->started)
{
+#ifdef __linux__
if (dwMilliseconds != INFINITE)
{
-#if _GNU_SOURCE
struct timespec timeout;
+ /* pthread_timedjoin_np returns ETIMEDOUT in case the timeout is 0,
+ * so set it to the smallest value to get a proper return value. */
+ if (dwMilliseconds == 0)
+ dwMilliseconds ++;
+
clock_gettime(CLOCK_REALTIME, &timeout);
ts_add_ms(&timeout, dwMilliseconds);
status = pthread_timedjoin_np(thread->thread, &thread_status, &timeout);
-#else
- fprintf(stderr, "[ERROR] %s: Thread timeouts not implemented.\n", __func__);
- assert(0);
-#endif
+
+ if (ETIMEDOUT == status)
+ return WAIT_TIMEOUT;
}
else
+#endif
status = pthread_join(thread->thread, &thread_status);
if (status != 0)
- fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status);
+ {
+ fprintf(stderr, "WaitForSingleObject: pthread_join failure: [%d] %s\n",
+ status, strerror(status));
+ }
if (thread_status)
thread->dwExitCode = ((DWORD) (size_t) thread_status);
}
}
+ else if (Type == HANDLE_TYPE_PROCESS)
+ {
+ WINPR_PROCESS* process;
+
+ process = (WINPR_PROCESS*) Object;
+
+ if (waitpid(process->pid, &(process->status), 0) != -1)
+ {
+ return WAIT_FAILED;
+ }
+
+ process->dwExitCode = (DWORD) process->status;
+ }
else if (Type == HANDLE_TYPE_MUTEX)
{
WINPR_MUTEX* mutex;
mutex = (WINPR_MUTEX*) Object;
+#ifdef __linux__
if (dwMilliseconds != INFINITE)
{
+ int status;
struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout);
ts_add_ms(&timeout, dwMilliseconds);
- pthread_mutex_timedlock(&mutex->mutex, &timeout);
+ status = pthread_mutex_timedlock(&mutex->mutex, &timeout);
+
+ if (ETIMEDOUT == status)
+ return WAIT_TIMEOUT;
}
else
+#endif
pthread_mutex_lock(&mutex->mutex);
}
else if (Type == HANDLE_TYPE_EVENT)
return WAIT_FAILED;
#endif
}
+ else if (Type == HANDLE_TYPE_NAMED_PIPE)
+ {
+ int fd;
+ int status;
+ fd_set rfds;
+ struct timeval timeout;
+ WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object;
+
+ fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
+
+ if (fd == -1)
+ return WAIT_FAILED;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ ZeroMemory(&timeout, sizeof(timeout));
+
+ if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
+ {
+ timeout.tv_usec = dwMilliseconds * 1000;
+ }
+
+ status = select(fd + 1, &rfds, NULL, NULL,
+ (dwMilliseconds == INFINITE) ? NULL : &timeout);
+
+ if (status < 0)
+ return WAIT_FAILED;
+
+ if (status != 1)
+ return WAIT_TIMEOUT;
+ }
else
{
fprintf(stderr, "WaitForSingleObject: unknown handle type %lu\n", Type);
WINPR_TIMER* timer = (WINPR_TIMER*) Object;
fd = timer->fd;
}
+ else if (Type == HANDLE_TYPE_NAMED_PIPE)
+ {
+ WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object;
+ fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
+
+ if (fd == -1)
+ return WAIT_FAILED;
+ }
else
{
return WAIT_FAILED;
WINPR_TIMER* timer = (WINPR_TIMER*) Object;
fd = timer->fd;
}
+ else if (Type == HANDLE_TYPE_NAMED_PIPE)
+ {
+ WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object;
+ fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
+ }
if (FD_ISSET(fd, &fds))
{