blob: f959703bc6dcdc487aaa4f4071be26f65875085c [file] [log] [blame]
// Copyright 2013 Google Inc. All Rights Reserved.
// Add futex interface for Bionic.
#include <irt_syscalls.h>
#include <bionic_futex.h>
#include <errno.h>
#include <nacl_timespec.h>
#include <nacl_timeval.h>
#include <unistd.h>
int __futex_syscall4(volatile void *ftx, int op, int val,
const struct timespec *timeout) {
/* FUTEX_FD, FUTEX_REQUEUE, and FUTEX_CMP_REQUEUE are not used
* by android.
* TODO(crbug.com/243244): Support these operations. In theory, NDK
* apps can call this for the operations we do not support. */
switch (op) {
case FUTEX_WAIT:
case FUTEX_WAIT_PRIVATE: {
// We need to convert the ABI of timespec from bionic's to NaCl's.
struct nacl_abi_timespec nacl_timeout;
struct nacl_abi_timespec *nacl_timeout_ptr = NULL;
if (timeout) {
// Functions from nacl-glibc expects absolute time for this.
struct nacl_abi_timeval tv;
int r = __nacl_irt_gettod(&tv);
if (r != 0) {
// Maybe this should not happen.
errno = EFAULT;
return -1;
}
static const int kNanosecondsPerSecond = 1000000000;
// NaClCommonSysCond_Timed_Wait_Abs does not validate timeout
// and it has a TODO instead. So we should check the value.
if (timeout->tv_nsec >= kNanosecondsPerSecond) {
errno = EINVAL;
return -1;
}
long sec = timeout->tv_sec + tv.tv_sec;
long nsec = timeout->tv_nsec + tv.tv_usec * 1000;
sec += nsec / kNanosecondsPerSecond;
if (sec < 0 || nsec < 0) {
errno = EINVAL;
return -1;
}
nsec %= kNanosecondsPerSecond;
nacl_timeout.tv_sec = sec;
nacl_timeout.tv_nsec = nsec;
nacl_timeout_ptr = &nacl_timeout;
}
return __nacl_irt_futex_wait_abs(ftx, val, nacl_timeout_ptr);
}
case FUTEX_WAKE:
case FUTEX_WAKE_PRIVATE: {
int count;
return __nacl_irt_futex_wake(ftx, val, &count);
}
default: {
static const int kStderrFd = 2;
static const char kMsg[] = "futex syscall called with unexpected op!";
write(kStderrFd, kMsg, sizeof(kMsg) - 1);
abort();
}
}
}
int __futex_syscall3(volatile void *ftx, int op, int val) {
return __futex_syscall4(ftx, op, val, NULL);
}