2b9fb614556a0236f29cc1d98cb2c523bf1c5644
[platform/framework/web/crosswalk.git] / src / native_client / src / nonsfi / linux / linux_futex.c
1 /*
2  * Copyright 2014 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include <errno.h>
8 #include <sys/time.h>
9 #include <time.h>
10
11 #include "native_client/src/nonsfi/linux/abi_conversion.h"
12 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h"
13 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h"
14 #include "native_client/src/nonsfi/linux/linux_syscalls.h"
15 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
16 #include "native_client/src/untrusted/irt/irt_interfaces.h"
17 #include "native_client/src/untrusted/pthread/pthread_internal.h"
18
19 /*
20  * Converts a pair of timespec of absolute time and host's timespec of
21  * the current time to host's timespec of the relative time between them.
22  * Note that assuming tv_nsec for the both input structs are non-negative,
23  * the returned reltime's tv_nsec is also always non-negative.
24  * (I.e., for -0.1 sec, {tv_sec: -1, tv_nsec: 900000000} will be returned).
25  */
26 static void abs_time_to_linux_rel_time(const struct timespec *nacl_abstime,
27                                        const struct timespec *now,
28                                        struct linux_abi_timespec *reltime) {
29   reltime->tv_sec = nacl_abstime->tv_sec - now->tv_sec;
30   reltime->tv_nsec = nacl_abstime->tv_nsec - now->tv_nsec;
31   if (reltime->tv_nsec < 0) {
32     reltime->tv_sec -= 1;
33     reltime->tv_nsec += 1000000000;
34   }
35 }
36
37 static int nacl_irt_futex_wait_abs(volatile int *addr, int value,
38                                    const struct timespec *abstime) {
39   struct linux_abi_timespec timeout;
40   struct linux_abi_timespec *timeout_ptr = NULL;
41   if (abstime) {
42     /*
43      * futex syscall takes relative timeout, but the ABI for IRT's
44      * futex_wait_abs is absolute timeout. So, here we convert it.
45      */
46     struct timespec now;
47     if (clock_gettime(CLOCK_REALTIME, &now) < 0)
48       return errno;
49     abs_time_to_linux_rel_time(abstime, &now, &timeout);
50
51     /*
52      * Linux's FUTEX_WAIT returns EINVAL for negative timeout, but an absolute
53      * time that is in the past is a valid argument to irt_futex_wait_abs(),
54      * and a caller expects ETIMEDOUT.
55      * Here check only tv_sec since we assume time_t is signed. See also
56      * the comment for abs_time_to_rel_time.
57      */
58     if (timeout.tv_sec < 0)
59       return ETIMEDOUT;
60     timeout_ptr = &timeout;
61   }
62
63   int result = linux_syscall6(__NR_futex, (uintptr_t) addr, FUTEX_WAIT_PRIVATE,
64                               value, (uintptr_t) timeout_ptr, 0, 0);
65   if (result < 0)
66     return -result;
67   return 0;
68 }
69
70 static int nacl_irt_futex_wake(volatile int *addr, int nwake, int *count) {
71   int result = linux_syscall6(__NR_futex, (uintptr_t) addr, FUTEX_WAKE_PRIVATE,
72                               nwake, 0, 0, 0);
73   if (result < 0)
74     return -result;
75   *count = result;
76   return 0;
77 }
78
79 const struct nacl_irt_futex nacl_irt_futex = {
80   nacl_irt_futex_wait_abs,
81   nacl_irt_futex_wake,
82 };
83
84 extern struct nacl_irt_futex __nc_irt_futex
85   __attribute__((alias("nacl_irt_futex")));