#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 HAVE_PTHREAD_GNU_EXT
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] %s\n",
status, strerror(status));
+ }
if (thread_status)
thread->dwExitCode = ((DWORD) (size_t) thread_status);
{
return WAIT_FAILED;
}
+
+ process->dwExitCode = (DWORD) process->status;
}
else if (Type == HANDLE_TYPE_MUTEX)
{
mutex = (WINPR_MUTEX*) Object;
-#if HAVE_PTHREAD_GNU_EXT
+#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)
{
}
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(pipe->clientfd, &rfds);
+ FD_SET(fd, &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
timeout.tv_usec = dwMilliseconds * 1000;
}
- status = select(pipe->clientfd + 1, &rfds, NULL, NULL,
+ status = select(fd + 1, &rfds, NULL, NULL,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
if (status < 0)
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object;
- fd = pipe->clientfd;
+ fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
+
+ if (fd == -1)
+ return WAIT_FAILED;
}
else
{
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object;
- fd = pipe->clientfd;
+ fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
}
if (FD_ISSET(fd, &fds))