Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: src/trusted/service_runtime/linux/thread_suspension.c

Issue 10392005: Thread suspension: Implement for Linux (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Use private futexes Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include <errno.h>
8 #include <linux/futex.h>
9 #include <signal.h>
10 #include <sys/syscall.h>
11
12 #include "native_client/src/shared/platform/nacl_check.h"
13 #include "native_client/src/shared/platform/nacl_exit.h"
14 #include "native_client/src/shared/platform/nacl_sync_checked.h"
15 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
16 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
17 #include "native_client/src/trusted/service_runtime/nacl_tls.h"
18 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
19
20
21 /*
22 * If |*addr| still contains |value|, this waits to be woken up by a
23 * FutexWake(addr,...) call from another thread; otherwise, it returns
24 * immediately.
25 *
26 * Note that if this is interrupted by a signal, the system call will
27 * get restarted, but it will recheck whether |*addr| still contains
28 * |value|.
29 *
30 * We use the *_PRIVATE variant to use process-local futexes which are
bradn 2012/05/21 17:42:57 Mention that these are well know but undocumented
31 * slightly faster than shared futexes.
32 */
33 static void FutexWait(Atomic32 *addr, Atomic32 value) {
34 if (syscall(SYS_futex, addr, FUTEX_WAIT_PRIVATE, value, 0, 0, 0) != 0) {
35 /*
36 * We get EWOULDBLOCK if *addr != value (EAGAIN is a synonym).
37 * We get EINTR if interrupted by a signal.
38 */
39 if (errno != EINTR && errno != EWOULDBLOCK) {
40 NaClLog(LOG_FATAL, "FutexWait: futex() failed with error %d\n", errno);
41 }
42 }
43 }
44
45 /*
46 * This wakes up threads that are waiting on |addr| using FutexWait().
47 * |waiters| is the maximum number of threads that will be woken up.
48 */
49 static void FutexWake(Atomic32 *addr, int waiters) {
50 if (syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, waiters, 0, 0, 0) < 0) {
51 NaClLog(LOG_FATAL, "FutexWake: futex() failed with error %d\n", errno);
52 }
53 }
54
55 void NaClAppThreadSetSuspendState(struct NaClAppThread *natp,
56 enum NaClSuspendState old_state,
57 enum NaClSuspendState new_state) {
58 while (1) {
59 Atomic32 state = natp->suspend_state;
60 if ((state & NACL_APP_THREAD_SUSPENDING) != 0) {
61 /* We have been asked to suspend, so wait. */
62 FutexWait(&natp->suspend_state, state);
63 continue; /* Retry */
64 }
65
66 CHECK(state == (Atomic32) old_state);
67 if (CompareAndSwap(&natp->suspend_state, old_state, new_state)
68 != (Atomic32) old_state) {
69 continue; /* Retry */
70 }
71 break;
72 }
73 }
74
75 void NaClSuspendSignalHandler(void) {
76 uint32_t tls_idx = NaClTlsGetIdx();
77 struct NaClAppThread *natp = nacl_thread[tls_idx];
78
79 /*
80 * Indicate that we have suspended by setting
81 * NACL_APP_THREAD_SUSPENDED. We should not need an atomic
82 * operation for this since the calling thread will not be trying to
83 * change suspend_state.
84 */
85 if (natp->suspend_state != (NACL_APP_THREAD_UNTRUSTED |
86 NACL_APP_THREAD_SUSPENDING)) {
87 NaClSignalErrorMessage("NaClSuspendSignalHandler: "
88 "Unexpected suspend_state\n");
89 NaClAbort();
90 }
91 natp->suspend_state |= NACL_APP_THREAD_SUSPENDED;
92 FutexWake(&natp->suspend_state, 1);
93
94 /* Wait until we are asked to resume. */
95 while (1) {
96 Atomic32 state = natp->suspend_state;
97 if ((state & NACL_APP_THREAD_SUSPENDED) != 0) {
98 FutexWait(&natp->suspend_state, state);
99 continue; /* Retry */
100 }
101 break;
102 }
103 }
104
105 /* Wait for the thread to indicate that it has suspended. */
106 static void WaitForUntrustedThreadToSuspend(struct NaClAppThread *natp) {
107 const Atomic32 kBaseState = (NACL_APP_THREAD_UNTRUSTED |
108 NACL_APP_THREAD_SUSPENDING);
109 while (1) {
110 Atomic32 state = natp->suspend_state;
111 if (state == kBaseState) {
112 FutexWait(&natp->suspend_state, state);
113 continue; /* Retry */
114 }
115 if (state != (kBaseState | NACL_APP_THREAD_SUSPENDED)) {
116 NaClLog(LOG_FATAL, "Unexpected state: %d\n", state);
117 }
118 break;
119 }
120 }
121
122 void NaClUntrustedThreadSuspend(struct NaClAppThread *natp) {
123 Atomic32 old_state;
124 Atomic32 suspending_state;
125
126 /*
127 * Note that if we are being called from a NaCl syscall (which is
128 * likely), natp could be the thread we are running in. That is
129 * fine, because this thread will be in the NACL_APP_THREAD_TRUSTED
130 * state, and so we will not try to interrupt it.
131 */
132
133 /*
134 * We do not want the thread to enter a NaCl syscall and start
135 * taking locks when pthread_kill() takes effect, so we ask the
136 * thread to suspend even if it is currently running untrusted code.
137 */
138 while (1) {
139 old_state = natp->suspend_state;
140 DCHECK((old_state & NACL_APP_THREAD_SUSPENDING) == 0);
141 suspending_state = old_state | NACL_APP_THREAD_SUSPENDING;
142 if (CompareAndSwap(&natp->suspend_state, old_state, suspending_state)
143 != old_state) {
144 continue; /* Retry */
145 }
146 break;
147 }
148 /*
149 * Once the thread has NACL_APP_THREAD_SUSPENDING set, it may not
150 * change state itself, so there should be no race condition in this
151 * check.
152 */
153 DCHECK(natp->suspend_state == suspending_state);
154
155 if (old_state == NACL_APP_THREAD_UNTRUSTED) {
156 if (pthread_kill(natp->thread.tid, NACL_THREAD_SUSPEND_SIGNAL) != 0) {
157 NaClLog(LOG_FATAL, "NaClUntrustedThreadsSuspend: "
158 "pthread_kill() call failed\n");
159 }
160 WaitForUntrustedThreadToSuspend(natp);
161 }
162 }
163
164 void NaClUntrustedThreadResume(struct NaClAppThread *natp) {
165 Atomic32 old_state;
166 Atomic32 new_state;
167 while (1) {
168 old_state = natp->suspend_state;
169 new_state = old_state & ~(NACL_APP_THREAD_SUSPENDING |
170 NACL_APP_THREAD_SUSPENDED);
171 DCHECK((old_state & NACL_APP_THREAD_SUSPENDING) != 0);
172 if (CompareAndSwap(&natp->suspend_state, old_state, new_state)
173 != old_state) {
174 continue; /* Retry */
175 }
176 break;
177 }
178
179 /*
180 * TODO(mseaborn): A refinement would be to wake up the thread only
181 * if it actually suspended during the context switch.
182 */
183 FutexWake(&natp->suspend_state, 1);
184 }
185
186 /*
187 * NaClUntrustedThreadsSuspend() ensures that any untrusted code is
188 * temporarily suspended.
189 *
190 * If a thread is currently executing a NaCl syscall, we tell the
191 * thread not to return to untrusted code yet. If a thread is
192 * currently executing untrusted code, we suspend it.
193 *
194 * This returns with the lock threads_mu held, because we need to pin
195 * the list of threads. NaClUntrustedThreadsResume() must be called
196 * to undo this.
197 */
198 void NaClUntrustedThreadsSuspendAll(struct NaClApp *nap) {
199 size_t index;
200
201 NaClXMutexLock(&nap->threads_mu);
202
203 for (index = 0; index < nap->threads.num_entries; index++) {
204 struct NaClAppThread *natp = NaClGetThreadMu(nap, (int) index);
205 if (natp != NULL) {
206 NaClUntrustedThreadSuspend(natp);
207 }
208 }
209 }
210
211 void NaClUntrustedThreadsResumeAll(struct NaClApp *nap) {
212 size_t index;
213 for (index = 0; index < nap->threads.num_entries; index++) {
214 struct NaClAppThread *natp = NaClGetThreadMu(nap, (int) index);
215 if (natp != NULL) {
216 NaClUntrustedThreadResume(natp);
217 }
218 }
219
220 NaClXMutexUnlock(&nap->threads_mu);
221 }
OLDNEW
« no previous file with comments | « src/trusted/service_runtime/generic/thread_suspension.c ('k') | src/trusted/service_runtime/nacl_app_thread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698