OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 The Native Client Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 | 9 |
10 #include "native_client/src/nonsfi/linux/linux_pthread_private.h" | 10 #include "native_client/src/nonsfi/linux/linux_pthread_private.h" |
11 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h" | 11 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h" |
12 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h" | 12 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h" |
13 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" | 13 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" |
14 #include "native_client/src/nonsfi/linux/linux_sys_private.h" | 14 #include "native_client/src/nonsfi/linux/linux_sys_private.h" |
15 #include "native_client/src/public/linux_syscalls/sched.h" | 15 #include "native_client/src/public/linux_syscalls/sched.h" |
16 #include "native_client/src/public/linux_syscalls/sys/syscall.h" | 16 #include "native_client/src/public/linux_syscalls/sys/syscall.h" |
17 #include "native_client/src/untrusted/nacl/nacl_irt.h" | 17 #include "native_client/src/untrusted/nacl/nacl_irt.h" |
18 #include "native_client/src/untrusted/nacl/nacl_thread.h" | 18 #include "native_client/src/untrusted/nacl/nacl_thread.h" |
19 #include "native_client/src/untrusted/pthread/pthread_internal.h" | 19 #include "native_client/src/untrusted/pthread/pthread_internal.h" |
20 | 20 |
21 /* Convert a return value of a Linux syscall to the one of an IRT call. */ | 21 /* Convert a return value of a Linux syscall to the one of an IRT call. */ |
22 static uint32_t irt_return_call(uintptr_t result) { | 22 static uint32_t irt_return_call(uintptr_t result) { |
23 if (linux_is_error_result(result)) | 23 if (linux_is_error_result(result)) |
24 return -result; | 24 return -result; |
25 return 0; | 25 return 0; |
26 } | 26 } |
27 | 27 |
28 static int nacl_irt_thread_create(void (*start_func)(void), void *stack, | 28 static int nacl_irt_thread_create_v0_2(void (*start_func)(void), void *stack, |
29 void *thread_ptr) { | 29 void *thread_ptr, |
| 30 nacl_irt_tid_t *child_tid) { |
30 /* | 31 /* |
31 * We do not use CLONE_CHILD_CLEARTID as we do not want any | 32 * We do not use CLONE_CHILD_CLEARTID as we do not want any |
32 * non-private futex signaling. Also, NaCl ABI does not require us | 33 * non-private futex signaling. Also, NaCl ABI does not require us |
33 * to signal the futex on stack_flag. | 34 * to signal the futex on stack_flag. |
34 */ | 35 */ |
35 int flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | | 36 int flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | |
36 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS); | 37 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | |
| 38 CLONE_PARENT_SETTID); |
| 39 /* |
| 40 * In order to avoid allowing clone with and without CLONE_PARENT_SETTID, if |
| 41 * |child_tid| is NULL, we provide a valid pointer whose value will be |
| 42 * ignored. |
| 43 */ |
| 44 nacl_irt_tid_t ignored; |
| 45 void *ptid = (child_tid != NULL) ? child_tid : &ignored; |
| 46 |
37 /* | 47 /* |
38 * linux_clone_wrapper expects start_func's type is "int (*)(void *)". | 48 * linux_clone_wrapper expects start_func's type is "int (*)(void *)". |
39 * Although |start_func| has type "void (*)(void)", the type mismatching | 49 * Although |start_func| has type "void (*)(void)", the type mismatching |
40 * will not cause a problem. Passing a dummy |arg| (= 0) does nothing there. | 50 * will not cause a problem. Passing a dummy |arg| (= 0) does nothing there. |
41 * Also, start_func will never return. | 51 * Also, start_func will never return. |
42 */ | 52 */ |
43 return irt_return_call(linux_clone_wrapper( | 53 return irt_return_call(linux_clone_wrapper( |
44 (uintptr_t) start_func, /* arg */ 0, flags, stack, | 54 (uintptr_t) start_func, /* arg */ 0, flags, stack, |
45 /* ptid */ NULL, thread_ptr, /* ctid */ NULL)); | 55 ptid, thread_ptr, /* ctid */ NULL)); |
| 56 } |
| 57 |
| 58 static int nacl_irt_thread_create(void (*start_func)(void), void *stack, |
| 59 void *thread_ptr) { |
| 60 nacl_irt_tid_t child_tid; |
| 61 return nacl_irt_thread_create_v0_2(start_func, stack, thread_ptr, &child_tid); |
46 } | 62 } |
47 | 63 |
48 static void nacl_irt_thread_exit(int32_t *stack_flag) { | 64 static void nacl_irt_thread_exit(int32_t *stack_flag) { |
49 /* | 65 /* |
50 * We fill zero to stack_flag by ourselves instead of relying | 66 * We fill zero to stack_flag by ourselves instead of relying |
51 * on CLONE_CHILD_CLEARTID. We do everything in the following inline | 67 * on CLONE_CHILD_CLEARTID. We do everything in the following inline |
52 * assembly because we need to make sure we will never touch stack. | 68 * assembly because we need to make sure we will never touch stack. |
53 * | 69 * |
54 * We will set the stack pointer to zero at the beginning of the | 70 * We will set the stack pointer to zero at the beginning of the |
55 * assembly code just in case an async signal arrives after setting | 71 * assembly code just in case an async signal arrives after setting |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 * That should never return. Crash hard if it does. | 129 * That should never return. Crash hard if it does. |
114 */ | 130 */ |
115 __builtin_trap(); | 131 __builtin_trap(); |
116 } | 132 } |
117 | 133 |
118 /* | 134 /* |
119 * Creates a thread and initializes the IRT-private TLS area. | 135 * Creates a thread and initializes the IRT-private TLS area. |
120 * Based on code from src/untrusted/irt/irt_thread.c | 136 * Based on code from src/untrusted/irt/irt_thread.c |
121 */ | 137 */ |
122 int nacl_user_thread_create(void *(*start_func)(void *), void *stack, | 138 int nacl_user_thread_create(void *(*start_func)(void *), void *stack, |
123 void *thread_ptr) { | 139 void *thread_ptr, nacl_irt_tid_t *child_tid) { |
124 struct nc_combined_tdb *tdb; | 140 struct nc_combined_tdb *tdb; |
125 | 141 |
126 /* | 142 /* |
127 * Before we start the thread, allocate the IRT-private TLS area for it. | 143 * Before we start the thread, allocate the IRT-private TLS area for it. |
128 */ | 144 */ |
129 size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); | 145 size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); |
130 void *combined_area = malloc(combined_size); | 146 void *combined_area = malloc(combined_size); |
131 if (combined_area == NULL) | 147 if (combined_area == NULL) |
132 return EAGAIN; | 148 return EAGAIN; |
133 | 149 |
134 /* | 150 /* |
135 * Note that __nacl_tls_initialize_memory() is not reversible, | 151 * Note that __nacl_tls_initialize_memory() is not reversible, |
136 * because it takes a pointer that need not be aligned and can | 152 * because it takes a pointer that need not be aligned and can |
137 * return a pointer that is aligned. In order to | 153 * return a pointer that is aligned. In order to |
138 * free(combined_area) later, we must save the value of | 154 * free(combined_area) later, we must save the value of |
139 * combined_area. | 155 * combined_area. |
140 */ | 156 */ |
141 void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); | 157 void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); |
142 tdb = get_irt_tdb(irt_tp); | 158 tdb = get_irt_tdb(irt_tp); |
143 __nc_initialize_unjoinable_thread(tdb); | 159 __nc_initialize_unjoinable_thread(tdb); |
144 tdb->tdb.irt_thread_data = combined_area; | 160 tdb->tdb.irt_thread_data = combined_area; |
145 tdb->tdb.start_func = start_func; | 161 tdb->tdb.start_func = start_func; |
146 tdb->tdb.state = thread_ptr; | 162 tdb->tdb.state = thread_ptr; |
147 | 163 |
148 return nacl_irt_thread_create(irt_start_thread, stack, irt_tp); | 164 return nacl_irt_thread_create_v0_2(irt_start_thread, stack, irt_tp, |
| 165 child_tid); |
149 } | 166 } |
150 | 167 |
151 /* | 168 /* |
152 * Destroys a thread created by nacl_user_thread_create. | 169 * Destroys a thread created by nacl_user_thread_create. |
153 * Based on code from src/untrusted/irt/irt_thread.c | 170 * Based on code from src/untrusted/irt/irt_thread.c |
154 */ | 171 */ |
155 void nacl_user_thread_exit(int32_t *stack_flag) { | 172 void nacl_user_thread_exit(int32_t *stack_flag) { |
156 struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); | 173 struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); |
157 | 174 |
158 __nc_tsd_exit(); | 175 __nc_tsd_exit(); |
(...skipping 11 matching lines...) Expand all Loading... |
170 } | 187 } |
171 | 188 |
172 void __nc_initialize_interfaces(void) { | 189 void __nc_initialize_interfaces(void) { |
173 const struct nacl_irt_thread init = { | 190 const struct nacl_irt_thread init = { |
174 nacl_irt_thread_create, | 191 nacl_irt_thread_create, |
175 nacl_irt_thread_exit, | 192 nacl_irt_thread_exit, |
176 nacl_irt_thread_nice, | 193 nacl_irt_thread_nice, |
177 }; | 194 }; |
178 __libnacl_irt_thread = init; | 195 __libnacl_irt_thread = init; |
179 } | 196 } |
OLD | NEW |