| 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 |