blob: 8c27bf49a653b8168e2eca7ad854b8d49f7b6a9a [file] [log] [blame]
#include "pthread_impl.h"
#include <errno.h>
#include <zircon/syscalls.h>
#include <time.h>
#include "clock_impl.h"
int __timedwait(atomic_int* futex, int val, clockid_t clk, const struct timespec* at) {
struct timespec to;
zx_time_t deadline = ZX_TIME_INFINITE;
if (at) {
if (at->tv_nsec >= ZX_SEC(1))
return EINVAL;
if (__clock_gettime(clk, &to))
return EINVAL;
to.tv_sec = at->tv_sec - to.tv_sec;
if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
to.tv_sec--;
to.tv_nsec += ZX_SEC(1);
}
if (to.tv_sec < 0)
return ETIMEDOUT;
deadline = _zx_deadline_after(ZX_SEC(to.tv_sec) + to.tv_nsec);
}
// zx_futex_wait will return ZX_ERR_BAD_STATE if someone modifying *addr
// races with this call. But this is indistinguishable from
// otherwise being woken up just before someone else changes the
// value. Therefore this functions returns 0 in that case.
switch (_zx_futex_wait(futex, val, deadline)) {
case ZX_OK:
case ZX_ERR_BAD_STATE:
return 0;
case ZX_ERR_TIMED_OUT:
return ETIMEDOUT;
case ZX_ERR_INVALID_ARGS:
default:
__builtin_trap();
}
}