Chromium Code Reviews| 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 <errno.h> | 8 #include <errno.h> |
| 8 | 9 |
| 10 #include "native_client/src/nonsfi/linux/linux_pthread_private.h" | |
| 9 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h" | 11 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h" |
| 10 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h" | 12 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h" |
| 11 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" | 13 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h" |
| 12 #include "native_client/src/nonsfi/linux/linux_sys_private.h" | 14 #include "native_client/src/nonsfi/linux/linux_sys_private.h" |
| 13 #include "native_client/src/public/linux_syscalls/sched.h" | 15 #include "native_client/src/public/linux_syscalls/sched.h" |
| 14 #include "native_client/src/public/linux_syscalls/sys/syscall.h" | 16 #include "native_client/src/public/linux_syscalls/sys/syscall.h" |
| 15 #include "native_client/src/untrusted/nacl/nacl_irt.h" | 17 #include "native_client/src/untrusted/nacl/nacl_irt.h" |
| 16 #include "native_client/src/untrusted/nacl/nacl_thread.h" | 18 #include "native_client/src/untrusted/nacl/nacl_thread.h" |
| 17 #include "native_client/src/untrusted/pthread/pthread_internal.h" | 19 #include "native_client/src/untrusted/pthread/pthread_internal.h" |
| 18 | 20 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 72 : "r7"); | 74 : "r7"); |
| 73 #else | 75 #else |
| 74 # error Unsupported architecture | 76 # error Unsupported architecture |
| 75 #endif | 77 #endif |
| 76 } | 78 } |
| 77 | 79 |
| 78 static int nacl_irt_thread_nice(const int nice) { | 80 static int nacl_irt_thread_nice(const int nice) { |
| 79 return 0; | 81 return 0; |
| 80 } | 82 } |
| 81 | 83 |
| 84 static struct nc_combined_tdb *get_irt_tdb(void *thread_ptr) { | |
| 85 struct nc_combined_tdb *tdb = (void *) ((uintptr_t) thread_ptr + | |
| 86 __nacl_tp_tdb_offset(sizeof(*tdb))); | |
| 87 return tdb; | |
| 88 } | |
| 89 | |
| 90 /* Initialize a newly allocated TDB to some default values. */ | |
| 91 static void nc_tdb_init(nc_thread_descriptor_t *tdb, | |
|
Mark Seaborn
2015/07/08 04:11:21
Rather than duplicating this from pthread/nc_threa
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
| 92 nc_basic_thread_data_t *basic_data) { | |
| 93 tdb->tls_base = tdb; | |
| 94 tdb->joinable = PTHREAD_CREATE_JOINABLE; | |
| 95 tdb->join_waiting = 0; | |
| 96 tdb->rdlock_count = 0; | |
| 97 tdb->stack_node = NULL; | |
| 98 tdb->tls_node = NULL; | |
| 99 tdb->start_func = NULL; | |
| 100 tdb->state = NULL; | |
| 101 tdb->irt_thread_data = NULL; | |
| 102 tdb->basic_data = basic_data; | |
| 103 | |
| 104 basic_data->retval = NULL; | |
| 105 basic_data->status = THREAD_RUNNING; | |
| 106 if (pthread_cond_init(&basic_data->join_condvar, NULL) != 0) | |
| 107 __builtin_trap(); | |
| 108 basic_data->tdb = tdb; | |
| 109 } | |
| 110 | |
| 111 /* | |
| 112 * This is used by the IRT for user threads. We initialize all fields | |
| 113 * so that we get predictable behaviour in case some IRT code does an | |
| 114 * unsupported pthread operation on a user thread. | |
| 115 */ | |
| 116 void __nc_initialize_unjoinable_thread(struct nc_combined_tdb *tdb) { | |
| 117 nc_tdb_init(&tdb->tdb, &tdb->basic_data); | |
| 118 tdb->tdb.joinable = 0; | |
| 119 } | |
| 120 | |
| 121 /* | |
| 122 * This is the real first entry point for new threads. | |
| 123 */ | |
| 124 static void irt_start_thread() { | |
|
Mark Seaborn
2015/07/08 04:11:21
Can you add a comment saying that this is based on
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
| 125 struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); | |
| 126 | |
| 127 /* | |
| 128 * Fetch the user's start routine. | |
| 129 */ | |
| 130 void *(*user_start)(void *) = tdb->tdb.start_func; | |
| 131 | |
| 132 /* | |
| 133 * Now do per-thread initialization for the IRT-private C library state. | |
| 134 */ | |
| 135 __newlib_thread_init(); | |
| 136 | |
| 137 /* | |
| 138 * Finally, run the user code. | |
| 139 */ | |
| 140 (*user_start)(tdb->tdb.state); | |
| 141 | |
| 142 /* | |
| 143 * That should never return. Crash hard if it does. | |
| 144 */ | |
| 145 __builtin_trap(); | |
| 146 } | |
| 147 | |
| 148 int nacl_user_thread_create(void *(*start_func)(void *), void *stack, | |
| 149 void *thread_ptr) { | |
| 150 struct nc_combined_tdb *tdb; | |
| 151 | |
| 152 /* | |
| 153 * Before we start the thread, allocate the IRT-private TLS area for it. | |
| 154 */ | |
| 155 size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); | |
| 156 void *combined_area = malloc(combined_size); | |
| 157 if (combined_area == NULL) | |
| 158 return EAGAIN; | |
| 159 | |
| 160 /* | |
|
Mark Seaborn
2015/07/08 04:11:21
Nit: fix indentation
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
| 161 * Note that __nacl_tls_initialize_memory() is not reversible, | |
| 162 * because it takes a pointer that need not be aligned and can | |
| 163 * return a pointer that is aligned. In order to | |
| 164 * free(combined_area) later, we must save the value of | |
| 165 * combined_area. | |
| 166 */ | |
| 167 void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); | |
|
Mark Seaborn
2015/07/08 04:11:21
Nit: fix indentation
Luis Héctor Chávez
2015/07/08 16:42:13
Done.
| |
| 168 tdb = get_irt_tdb(irt_tp); | |
| 169 __nc_initialize_unjoinable_thread(tdb); | |
| 170 tdb->tdb.irt_thread_data = combined_area; | |
| 171 tdb->tdb.start_func = start_func; | |
| 172 tdb->tdb.state = thread_ptr; | |
| 173 | |
| 174 return nacl_irt_thread_create(irt_start_thread, stack, irt_tp); | |
| 175 } | |
| 176 | |
| 177 void nacl_user_thread_exit(int32_t *stack_flag) { | |
| 178 struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp()); | |
| 179 | |
| 180 __nc_tsd_exit(); | |
| 181 | |
| 182 /* | |
| 183 * Sanity check: Check that this function was not called on a thread | |
| 184 * created by the IRT's internal pthread_create(). For such | |
| 185 * threads, irt_thread_data == NULL. | |
| 186 */ | |
| 187 assert(tdb->tdb.irt_thread_data != NULL); | |
| 188 | |
| 189 free(tdb->tdb.irt_thread_data); | |
| 190 | |
| 191 nacl_irt_thread_exit(stack_flag); | |
| 192 } | |
| 193 | |
| 82 void __nc_initialize_interfaces(void) { | 194 void __nc_initialize_interfaces(void) { |
| 83 const struct nacl_irt_thread init = { | 195 const struct nacl_irt_thread init = { |
| 84 nacl_irt_thread_create, | 196 nacl_irt_thread_create, |
| 85 nacl_irt_thread_exit, | 197 nacl_irt_thread_exit, |
| 86 nacl_irt_thread_nice, | 198 nacl_irt_thread_nice, |
| 87 }; | 199 }; |
| 88 __libnacl_irt_thread = init; | 200 __libnacl_irt_thread = init; |
| 89 } | 201 } |
| OLD | NEW |