| // 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); |
| } |