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.
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"
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 };
18 static int my_thread_create(void (*start_func)(void), void *stack,
20 if (g_activated_env) {
21 __sync_fetch_and_add(&g_activated_env->num_threads_created, 1);
24 return g_irt_thread.thread_create(start_func, stack, thread_ptr);
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);
32 g_irt_thread.thread_exit(stack_flag);
35 static int my_thread_nice(const int nice) {
36 if (g_activated_env) {
37 g_activated_env->last_set_thread_nice = nice;
40 return g_irt_thread.thread_nice(nice);
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);
50 } else if (abstime != NULL) {
51 int previous_time = g_activated_env->current_time;
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.
60 while (previous_time < abstime->tv_sec) {
61 int value = __sync_bool_compare_and_swap(&g_activated_env->current_time,
65 /* If value is equal to previous_time, then compare/swap succeeded. */
66 if (value == previous_time)
69 /* Update new previous_time to the old current_time value. */
70 previous_time = value;
76 return g_irt_futex.futex_wait_abs(addr, value, abstime);
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);
84 return g_irt_futex.futex_wake(addr, nwake, count);
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);
93 struct nacl_irt_thread thread_calls = {
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);
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);
110 struct nacl_irt_futex futex_calls = {
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);
122 void init_threading_environment(struct threading_environment *env) {
126 void activate_threading_env(struct threading_environment *env) {
127 g_activated_env = env;
130 void deactivate_threading_env(void) {
131 g_activated_env = NULL;