1 : /*
2 : * Copyright (c) 2012 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 :
7 : /*
8 : * NaCl Server Runtime user thread state.
9 : */
10 : #include "native_client/src/shared/platform/nacl_check.h"
11 : #include "native_client/src/shared/platform/nacl_exit.h"
12 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
13 :
14 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
15 : #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
16 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
17 : #include "native_client/src/trusted/service_runtime/nacl_oop_debugger_hooks.h"
18 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
19 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
20 : #include "native_client/src/trusted/service_runtime/nacl_stack_safety.h"
21 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
22 :
23 :
24 : void NaClAppThreadSetSuspendState(struct NaClAppThread *natp,
25 : enum NaClSuspendState old_state,
26 1124 : enum NaClSuspendState new_state) {
27 : #if NACL_WINDOWS
28 : NaClXMutexLock(&natp->mu);
29 : while ((natp->suspend_state & NACL_APP_THREAD_SUSPENDING) != 0) {
30 : /*
31 : * We are being suspended, but SuspendThread() has not taken effect yet.
32 : */
33 : NaClXCondVarWait(&natp->cv, &natp->mu);
34 : }
35 : DCHECK(natp->suspend_state == old_state);
36 : natp->suspend_state = new_state;
37 : NaClXMutexUnlock(&natp->mu);
38 : #else
39 : UNREFERENCED_PARAMETER(natp);
40 : UNREFERENCED_PARAMETER(old_state);
41 : UNREFERENCED_PARAMETER(new_state);
42 : #endif
43 1124 : }
44 :
45 :
46 3 : void WINAPI NaClThreadLauncher(void *state) {
47 3 : struct NaClAppThread *natp = (struct NaClAppThread *) state;
48 : uint32_t thread_idx;
49 3 : NaClLog(4, "NaClThreadLauncher: entered\n");
50 :
51 3 : NaClSignalStackRegister(natp->signal_stack);
52 :
53 3 : NaClLog(4, " natp = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) natp);
54 3 : NaClLog(4, " prog_ctr = 0x%016"NACL_PRIxNACL_REG"\n", natp->user.prog_ctr);
55 3 : NaClLog(4, "stack_ptr = 0x%016"NACL_PRIxPTR"\n",
56 : NaClGetThreadCtxSp(&natp->user));
57 :
58 3 : thread_idx = NaClGetThreadIdx(natp);
59 3 : CHECK(0 < thread_idx);
60 3 : CHECK(thread_idx < NACL_THREAD_MAX);
61 3 : NaClTlsSetIdx(thread_idx);
62 3 : nacl_thread[thread_idx] = natp;
63 3 : nacl_user[thread_idx] = &natp->user;
64 3 : nacl_sys[thread_idx] = &natp->sys;
65 : #if NACL_WINDOWS
66 : nacl_thread_ids[thread_idx] = GetCurrentThreadId();
67 : #endif
68 3 : nacl_tls[thread_idx] = (uint32_t) NaClSysToUser(natp->nap, natp->sys_tls);
69 3 : natp->usr_tlsp = &nacl_tls[thread_idx];
70 :
71 : /*
72 : * We have to hold the threads_mu lock until after thread_num field
73 : * in this thread has been initialized. All other threads can only
74 : * find and examine this natp through the threads table, so the fact
75 : * that natp is not consistent (no thread_num) will not be visible.
76 : */
77 3 : NaClXMutexLock(&natp->nap->threads_mu);
78 3 : natp->thread_num = NaClAddThreadMu(natp->nap, natp);
79 3 : NaClXMutexUnlock(&natp->nap->threads_mu);
80 :
81 3 : NaClVmHoleThreadStackIsSafe(natp->nap);
82 :
83 3 : NaClStackSafetyNowOnUntrustedStack();
84 :
85 : /*
86 : * Notify the debug stub, that a new thread is availible.
87 : */
88 3 : if (NULL != natp->nap->debug_stub_callbacks) {
89 0 : natp->nap->debug_stub_callbacks->thread_create_hook(natp);
90 : }
91 :
92 3 : NaClOopDebuggerThreadCreateHook(natp);
93 :
94 : /*
95 : * After this NaClAppThreadSetSuspendState() call, we should not
96 : * claim any mutexes, otherwise we risk deadlock.
97 : */
98 3 : NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
99 : NACL_APP_THREAD_UNTRUSTED);
100 :
101 3 : NaClStartThreadInApp(natp, natp->user.prog_ctr);
102 : }
103 :
104 :
105 : /*
106 : * natp should be thread_self(), called while holding no locks.
107 : */
108 3 : void NaClAppThreadTeardown(struct NaClAppThread *natp) {
109 : struct NaClApp *nap;
110 : size_t thread_idx;
111 : int process_exit_status;
112 :
113 : /*
114 : * mark this thread as dead; doesn't matter if some other thread is
115 : * asking us to commit suicide.
116 : */
117 3 : NaClLog(3, "NaClAppThreadTeardown(0x%08"NACL_PRIxPTR")\n",
118 : (uintptr_t) natp);
119 3 : nap = natp->nap;
120 3 : NaClLog(3, " getting thread table lock\n");
121 3 : NaClXMutexLock(&nap->threads_mu);
122 3 : NaClLog(3, " getting thread lock\n");
123 3 : NaClXMutexLock(&natp->mu);
124 3 : natp->state = NACL_APP_THREAD_DEAD;
125 : /*
126 : * Remove ourselves from the ldt-indexed global tables. The ldt
127 : * entry is released as part of NaClAppThreadDtor (via
128 : * NaClAppThreadDecRef), and if another thread is immediately
129 : * created (from some other running thread) we want to be sure that
130 : * any ldt-based lookups will not reach this dying thread's data.
131 : */
132 3 : thread_idx = NaClGetThreadIdx(natp);
133 3 : nacl_sys[thread_idx] = NULL;
134 3 : nacl_user[thread_idx] = NULL;
135 3 : nacl_thread[thread_idx] = NULL;
136 : #if NACL_WINDOWS
137 : nacl_thread_ids[thread_idx] = 0;
138 : #endif
139 3 : NaClLog(3, " removing thread from thread table\n");
140 3 : NaClRemoveThreadMu(nap, natp->thread_num);
141 3 : NaClLog(3, " unlocking thread\n");
142 3 : NaClXMutexUnlock(&natp->mu);
143 3 : NaClLog(3, " announcing thread count change\n");
144 3 : NaClXCondVarBroadcast(&nap->threads_cv);
145 3 : NaClLog(3, " unlocking thread table\n");
146 3 : NaClXMutexUnlock(&nap->threads_mu);
147 3 : if (NULL != nap->debug_stub_callbacks) {
148 0 : NaClLog(3, " notifying the debug stub of the thread exit\n");
149 0 : nap->debug_stub_callbacks->thread_exit_hook(natp);
150 : }
151 3 : NaClLog(3, " unregistering signal stack\n");
152 3 : NaClSignalStackUnregister();
153 3 : NaClLog(3, " freeing thread object\n");
154 3 : NaClAppThreadDtor(natp);
155 3 : NaClLog(3, " NaClThreadExit\n");
156 :
157 3 : NaClXMutexLock(&nap->mu);
158 3 : process_exit_status = nap->exit_status;
159 3 : NaClXMutexUnlock(&nap->mu);
160 : /*
161 : * There appears to be a race on Windows where the process can sometimes
162 : * return a thread exit status instead of the process exit status when
163 : * they occur near simultaneously on two separate threads. Since this is
164 : * non-deterministic, we always exit a thread with the current value of the
165 : * process exit status to mitigate the possibility of exiting with an
166 : * incorrect value.
167 : * See http://code.google.com/p/nativeclient/issues/detail?id=1715
168 : */
169 3 : NaClThreadExit(process_exit_status);
170 0 : NaClLog(LOG_FATAL,
171 : "NaClAppThreadTeardown: NaClThreadExit() should not return\n");
172 : /* NOTREACHED */
173 0 : }
174 :
175 :
176 : int NaClAppThreadCtor(struct NaClAppThread *natp,
177 : struct NaClApp *nap,
178 : uintptr_t usr_entry,
179 : uintptr_t usr_stack_ptr,
180 : uint32_t tls_idx,
181 : uintptr_t sys_tls,
182 3 : uint32_t user_tls2) {
183 : int rv;
184 :
185 3 : NaClLog(4, " natp = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) natp);
186 3 : NaClLog(4, " nap = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) nap);
187 3 : NaClLog(4, "usr_stack_ptr = 0x%016"NACL_PRIxPTR"\n", usr_stack_ptr);
188 :
189 3 : NaClThreadContextCtor(&natp->user, nap, usr_entry, usr_stack_ptr, tls_idx);
190 :
191 3 : natp->signal_stack = NULL;
192 :
193 3 : if (!NaClMutexCtor(&natp->mu)) {
194 0 : return 0;
195 : }
196 3 : if (!NaClCondVarCtor(&natp->cv)) {
197 0 : goto cleanup_mutex;
198 : }
199 :
200 3 : natp->sysret = 0;
201 3 : natp->nap = nap;
202 :
203 3 : if (!NaClSignalStackAllocate(&natp->signal_stack)) {
204 0 : goto cleanup_cv;
205 : }
206 :
207 : #if NACL_WINDOWS
208 : natp->suspend_state = NACL_APP_THREAD_TRUSTED;
209 : #endif
210 :
211 3 : natp->state = NACL_APP_THREAD_ALIVE;
212 :
213 3 : natp->thread_num = -1; /* illegal index */
214 3 : natp->sys_tls = sys_tls;
215 3 : natp->tls2 = user_tls2;
216 3 : natp->usr_tlsp = NULL;
217 :
218 3 : natp->dynamic_delete_generation = 0;
219 :
220 3 : rv = NaClThreadCtor(&natp->thread,
221 : NaClThreadLauncher,
222 : (void *) natp,
223 : NACL_KERN_STACK_SIZE);
224 3 : if (rv != 0) {
225 3 : return rv; /* Success */
226 : }
227 :
228 0 : cleanup_cv:
229 0 : NaClCondVarDtor(&natp->cv);
230 0 : cleanup_mutex:
231 0 : NaClMutexDtor(&natp->mu);
232 0 : if (NULL != natp->signal_stack) {
233 0 : NaClSignalStackFree(&natp->signal_stack);
234 0 : natp->signal_stack = NULL;
235 : }
236 0 : return 0;
237 : }
238 :
239 :
240 3 : void NaClAppThreadDtor(struct NaClAppThread *natp) {
241 : /*
242 : * the thread must not be still running, else this crashes the system
243 : */
244 :
245 3 : NaClThreadDtor(&natp->thread);
246 3 : NaClSignalStackFree(natp->signal_stack);
247 3 : natp->signal_stack = NULL;
248 3 : NaClTlsFree(natp);
249 3 : NaClCondVarDtor(&natp->cv);
250 3 : NaClMutexDtor(&natp->mu);
251 3 : }
252 :
253 :
254 : int NaClAppThreadAllocSegCtor(struct NaClAppThread *natp,
255 : struct NaClApp *nap,
256 : uintptr_t usr_entry,
257 : uintptr_t usr_stack_ptr,
258 : uintptr_t sys_tls,
259 3 : uint32_t user_tls2) {
260 : uint32_t tls_idx;
261 :
262 : /*
263 : * Set this early, in case NaClTlsAllocate wants to examine it.
264 : */
265 3 : natp->nap = nap;
266 :
267 : /*
268 : * Even though we don't know what segment base/range should gs/r9/nacl_tls_idx
269 : * select, we still need one, since it identifies the thread when we context
270 : * switch back. This use of a dummy tls is only needed for the main thread,
271 : * which is expected to invoke the tls_init syscall from its crt code (before
272 : * main or much of libc can run). Other threads are spawned with the thread
273 : * pointer address as a parameter.
274 : */
275 3 : tls_idx = NaClTlsAllocate(natp, (void *) sys_tls);
276 :
277 3 : NaClLog(4,
278 : "NaClAppThreadAllocSegCtor: stack_ptr 0x%08"NACL_PRIxPTR", "
279 : "tls_idx 0x%02"NACL_PRIx32"\n",
280 : usr_stack_ptr, tls_idx);
281 :
282 3 : if (NACL_TLS_INDEX_INVALID == tls_idx) {
283 0 : NaClLog(LOG_ERROR, "No tls for thread, num_thread %d\n", nap->num_threads);
284 0 : return 0;
285 : }
286 :
287 3 : return NaClAppThreadCtor(natp,
288 : nap,
289 : usr_entry,
290 : usr_stack_ptr,
291 : tls_idx,
292 : sys_tls,
293 : user_tls2);
294 : }
|