Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / irt_ext / threading.c
1 /*
2  * Copyright (c) 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 #include <errno.h>
7
8 #include "native_client/src/untrusted/irt/irt.h"
9 #include "native_client/src/untrusted/irt/irt_extension.h"
10 #include "native_client/tests/irt_ext/error_report.h"
11 #include "native_client/tests/irt_ext/threading.h"
12
13 static struct threading_environment *g_activated_env = NULL;
14 static const struct threading_environment g_empty_env = { 0 };
15 static struct nacl_irt_thread g_irt_thread = { NULL };
16 static struct nacl_irt_futex g_irt_futex = { NULL };
17
18 static int my_thread_create(void (*start_func)(void), void *stack,
19                             void *thread_ptr) {
20   if (g_activated_env) {
21     __sync_fetch_and_add(&g_activated_env->num_threads_created, 1);
22   }
23
24   return g_irt_thread.thread_create(start_func, stack, thread_ptr);
25 }
26
27 static void my_thread_exit(int32_t *stack_flag) {
28   if (g_activated_env) {
29     __sync_fetch_and_add(&g_activated_env->num_threads_exited, 1);
30   }
31
32   g_irt_thread.thread_exit(stack_flag);
33 }
34
35 static int my_thread_nice(const int nice) {
36   if (g_activated_env) {
37     g_activated_env->last_set_thread_nice = nice;
38   }
39
40   return g_irt_thread.thread_nice(nice);
41 }
42
43 int my_futex_wait_abs(volatile int *addr, int value,
44                       const struct timespec *abstime) {
45   if (g_activated_env) {
46     __sync_fetch_and_add(&g_activated_env->num_futex_wait_calls, 1);
47
48     if (*addr != value) {
49       return EAGAIN;
50     } else if (abstime != NULL) {
51       int previous_time = g_activated_env->current_time;
52
53       /*
54        * Our futex wait function does not actually wait, it simply fast forwards
55        * the environment's time variable. Because other threads may also be
56        * fast forwarding time, we must be careful to set it atomically. Here we
57        * will continually compare/swap using the previous time, and try again
58        * until the value in current_time is greater than our absolute wait time.
59        */
60       while (previous_time < abstime->tv_sec) {
61         int value = __sync_bool_compare_and_swap(&g_activated_env->current_time,
62                                                  previous_time,
63                                                  abstime->tv_sec);
64
65         /* If value is equal to previous_time, then compare/swap succeeded. */
66         if (value == previous_time)
67           break;
68
69         /* Update new previous_time to the old current_time value. */
70         previous_time = value;
71       }
72       return ETIMEDOUT;
73     }
74   }
75
76   return g_irt_futex.futex_wait_abs(addr, value, abstime);
77 }
78
79 int my_futex_wake(volatile int *addr, int nwake, int *count) {
80   if (g_activated_env) {
81     __sync_fetch_and_add(&g_activated_env->num_futex_wake_calls, 1);
82   }
83
84   return g_irt_futex.futex_wake(addr, nwake, count);
85 }
86
87 void init_threading_module(void) {
88   size_t bytes = nacl_interface_query(NACL_IRT_THREAD_v0_1,
89                                       &g_irt_thread, sizeof(g_irt_thread));
90   IRT_EXT_ASSERT_MSG(bytes == sizeof(g_irt_thread),
91                      "Could not query interface: " NACL_IRT_THREAD_v0_1);
92
93   struct nacl_irt_thread thread_calls = {
94     my_thread_create,
95     my_thread_exit,
96     my_thread_nice,
97   };
98
99   bytes = nacl_interface_ext_supply(NACL_IRT_THREAD_v0_1,
100                                     &thread_calls, sizeof(thread_calls));
101   IRT_EXT_ASSERT_MSG(bytes == sizeof(thread_calls),
102                      "pthreads may not be linked in."
103                      " Could not supply interface: " NACL_IRT_THREAD_v0_1);
104
105   bytes = nacl_interface_query(NACL_IRT_FUTEX_v0_1,
106                                &g_irt_futex, sizeof(g_irt_futex));
107   IRT_EXT_ASSERT_MSG(bytes == sizeof(g_irt_futex),
108                      "Could not query interface: " NACL_IRT_FUTEX_v0_1);
109
110   struct nacl_irt_futex futex_calls = {
111     my_futex_wait_abs,
112     my_futex_wake,
113   };
114
115   bytes = nacl_interface_ext_supply(NACL_IRT_FUTEX_v0_1,
116                                     &futex_calls, sizeof(futex_calls));
117   IRT_EXT_ASSERT_MSG(bytes == sizeof(futex_calls),
118                      "pthreads may not be linked in."
119                      " Could not supply interface: " NACL_IRT_FUTEX_v0_1);
120 }
121
122 void init_threading_environment(struct threading_environment *env) {
123   *env = g_empty_env;
124 }
125
126 void activate_threading_env(struct threading_environment *env) {
127   g_activated_env = env;
128 }
129
130 void deactivate_threading_env(void) {
131   g_activated_env = NULL;
132 }