]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
1 | /* |
2 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. | |
3 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> | |
4 | * Copyright (C) 2009 Acision BV. All rights reserved. | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | * | |
20 | */ | |
21 | ||
22 | #include "config.h" | |
23 | #include "MachineStackMarker.h" | |
24 | ||
25 | #include "ConservativeRoots.h" | |
26 | #include "Heap.h" | |
27 | #include "JSArray.h" | |
81345200 | 28 | #include "JSCInlines.h" |
93a37866 | 29 | #include "VM.h" |
14957cd0 A |
30 | #include <setjmp.h> |
31 | #include <stdlib.h> | |
32 | #include <wtf/StdLibExtras.h> | |
33 | ||
14957cd0 A |
34 | #if OS(DARWIN) |
35 | ||
36 | #include <mach/mach_init.h> | |
37 | #include <mach/mach_port.h> | |
38 | #include <mach/task.h> | |
39 | #include <mach/thread_act.h> | |
40 | #include <mach/vm_map.h> | |
41 | ||
42 | #elif OS(WINDOWS) | |
43 | ||
44 | #include <windows.h> | |
45 | #include <malloc.h> | |
46 | ||
14957cd0 A |
47 | #elif OS(UNIX) |
48 | ||
14957cd0 | 49 | #include <sys/mman.h> |
14957cd0 A |
50 | #include <unistd.h> |
51 | ||
52 | #if OS(SOLARIS) | |
53 | #include <thread.h> | |
54 | #else | |
55 | #include <pthread.h> | |
56 | #endif | |
57 | ||
58 | #if HAVE(PTHREAD_NP_H) | |
59 | #include <pthread_np.h> | |
60 | #endif | |
61 | ||
14957cd0 A |
62 | #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) |
63 | #include <signal.h> | |
14957cd0 A |
64 | #endif |
65 | ||
66 | #endif | |
67 | ||
68 | using namespace WTF; | |
69 | ||
70 | namespace JSC { | |
71 | ||
72 | static inline void swapIfBackwards(void*& begin, void*& end) | |
73 | { | |
74 | #if OS(WINCE) | |
75 | if (begin <= end) | |
76 | return; | |
77 | std::swap(begin, end); | |
78 | #else | |
79 | UNUSED_PARAM(begin); | |
80 | UNUSED_PARAM(end); | |
81 | #endif | |
82 | } | |
83 | ||
14957cd0 A |
84 | #if OS(DARWIN) |
85 | typedef mach_port_t PlatformThread; | |
86 | #elif OS(WINDOWS) | |
87 | typedef HANDLE PlatformThread; | |
88 | #elif USE(PTHREADS) | |
89 | typedef pthread_t PlatformThread; | |
90 | static const int SigThreadSuspendResume = SIGUSR2; | |
91 | ||
6fe7ccc8 | 92 | #if defined(SA_RESTART) |
93a37866 | 93 | static void pthreadSignalHandlerSuspendResume(int) |
14957cd0 A |
94 | { |
95 | sigset_t signalSet; | |
96 | sigemptyset(&signalSet); | |
97 | sigaddset(&signalSet, SigThreadSuspendResume); | |
98 | sigsuspend(&signalSet); | |
99 | } | |
100 | #endif | |
6fe7ccc8 | 101 | #endif |
14957cd0 A |
102 | |
103 | class MachineThreads::Thread { | |
93a37866 | 104 | WTF_MAKE_FAST_ALLOCATED; |
14957cd0 | 105 | public: |
6fe7ccc8 A |
106 | Thread(const PlatformThread& platThread, void* base) |
107 | : platformThread(platThread) | |
14957cd0 A |
108 | , stackBase(base) |
109 | { | |
6fe7ccc8 A |
110 | #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) && defined(SA_RESTART) |
111 | // if we have SA_RESTART, enable SIGUSR2 debugging mechanism | |
14957cd0 A |
112 | struct sigaction action; |
113 | action.sa_handler = pthreadSignalHandlerSuspendResume; | |
114 | sigemptyset(&action.sa_mask); | |
115 | action.sa_flags = SA_RESTART; | |
116 | sigaction(SigThreadSuspendResume, &action, 0); | |
117 | ||
118 | sigset_t mask; | |
119 | sigemptyset(&mask); | |
120 | sigaddset(&mask, SigThreadSuspendResume); | |
121 | pthread_sigmask(SIG_UNBLOCK, &mask, 0); | |
122 | #endif | |
123 | } | |
124 | ||
125 | Thread* next; | |
14957cd0 A |
126 | PlatformThread platformThread; |
127 | void* stackBase; | |
128 | }; | |
129 | ||
14957cd0 | 130 | MachineThreads::MachineThreads(Heap* heap) |
93a37866 | 131 | : m_registeredThreads(0) |
14957cd0 | 132 | , m_threadSpecific(0) |
93a37866 A |
133 | #if !ASSERT_DISABLED |
134 | , m_heap(heap) | |
135 | #endif | |
14957cd0 | 136 | { |
93a37866 | 137 | UNUSED_PARAM(heap); |
14957cd0 A |
138 | } |
139 | ||
140 | MachineThreads::~MachineThreads() | |
141 | { | |
93a37866 A |
142 | if (m_threadSpecific) |
143 | threadSpecificKeyDelete(m_threadSpecific); | |
14957cd0 A |
144 | |
145 | MutexLocker registeredThreadsLock(m_registeredThreadsMutex); | |
146 | for (Thread* t = m_registeredThreads; t;) { | |
147 | Thread* next = t->next; | |
148 | delete t; | |
149 | t = next; | |
150 | } | |
14957cd0 A |
151 | } |
152 | ||
14957cd0 A |
153 | static inline PlatformThread getCurrentPlatformThread() |
154 | { | |
155 | #if OS(DARWIN) | |
156 | return pthread_mach_thread_np(pthread_self()); | |
157 | #elif OS(WINDOWS) | |
6fe7ccc8 | 158 | return GetCurrentThread(); |
14957cd0 A |
159 | #elif USE(PTHREADS) |
160 | return pthread_self(); | |
161 | #endif | |
162 | } | |
163 | ||
6fe7ccc8 A |
164 | static inline bool equalThread(const PlatformThread& first, const PlatformThread& second) |
165 | { | |
166 | #if OS(DARWIN) || OS(WINDOWS) | |
167 | return first == second; | |
168 | #elif USE(PTHREADS) | |
169 | return !!pthread_equal(first, second); | |
170 | #else | |
171 | #error Need a way to compare threads on this platform | |
172 | #endif | |
173 | } | |
174 | ||
14957cd0 A |
175 | void MachineThreads::makeUsableFromMultipleThreads() |
176 | { | |
177 | if (m_threadSpecific) | |
178 | return; | |
179 | ||
93a37866 | 180 | threadSpecificKeyCreate(&m_threadSpecific, removeThread); |
14957cd0 A |
181 | } |
182 | ||
183 | void MachineThreads::addCurrentThread() | |
184 | { | |
81345200 | 185 | ASSERT(!m_heap->vm()->hasExclusiveThread() || m_heap->vm()->exclusiveThread() == std::this_thread::get_id()); |
14957cd0 | 186 | |
93a37866 | 187 | if (!m_threadSpecific || threadSpecificGet(m_threadSpecific)) |
14957cd0 A |
188 | return; |
189 | ||
93a37866 | 190 | threadSpecificSet(m_threadSpecific, this); |
6fe7ccc8 | 191 | Thread* thread = new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); |
14957cd0 A |
192 | |
193 | MutexLocker lock(m_registeredThreadsMutex); | |
194 | ||
195 | thread->next = m_registeredThreads; | |
196 | m_registeredThreads = thread; | |
197 | } | |
198 | ||
199 | void MachineThreads::removeThread(void* p) | |
200 | { | |
201 | if (p) | |
202 | static_cast<MachineThreads*>(p)->removeCurrentThread(); | |
203 | } | |
204 | ||
205 | void MachineThreads::removeCurrentThread() | |
206 | { | |
6fe7ccc8 | 207 | PlatformThread currentPlatformThread = getCurrentPlatformThread(); |
14957cd0 A |
208 | |
209 | MutexLocker lock(m_registeredThreadsMutex); | |
210 | ||
6fe7ccc8 | 211 | if (equalThread(currentPlatformThread, m_registeredThreads->platformThread)) { |
14957cd0 A |
212 | Thread* t = m_registeredThreads; |
213 | m_registeredThreads = m_registeredThreads->next; | |
214 | delete t; | |
215 | } else { | |
216 | Thread* last = m_registeredThreads; | |
217 | Thread* t; | |
218 | for (t = m_registeredThreads->next; t; t = t->next) { | |
6fe7ccc8 | 219 | if (equalThread(t->platformThread, currentPlatformThread)) { |
14957cd0 A |
220 | last->next = t->next; |
221 | break; | |
222 | } | |
223 | last = t; | |
224 | } | |
225 | ASSERT(t); // If t is NULL, we never found ourselves in the list. | |
226 | delete t; | |
227 | } | |
228 | } | |
229 | ||
40a37d08 | 230 | void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers) |
14957cd0 | 231 | { |
14957cd0 A |
232 | void* registersBegin = ®isters; |
233 | void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(®isters + 1))); | |
234 | swapIfBackwards(registersBegin, registersEnd); | |
81345200 | 235 | conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks); |
14957cd0 A |
236 | |
237 | void* stackBegin = stackCurrent; | |
6fe7ccc8 | 238 | void* stackEnd = wtfThreadData().stack().origin(); |
14957cd0 | 239 | swapIfBackwards(stackBegin, stackEnd); |
81345200 | 240 | conservativeRoots.add(stackBegin, stackEnd, jitStubRoutines, codeBlocks); |
14957cd0 A |
241 | } |
242 | ||
40a37d08 | 243 | static inline bool suspendThread(const PlatformThread& platformThread) |
14957cd0 A |
244 | { |
245 | #if OS(DARWIN) | |
40a37d08 A |
246 | kern_return_t result = thread_suspend(platformThread); |
247 | return result == KERN_SUCCESS; | |
14957cd0 | 248 | #elif OS(WINDOWS) |
40a37d08 A |
249 | bool threadIsSuspended = (SuspendThread(platformThread) != (DWORD)-1); |
250 | ASSERT(threadIsSuspended); | |
251 | return threadIsSuspended; | |
14957cd0 A |
252 | #elif USE(PTHREADS) |
253 | pthread_kill(platformThread, SigThreadSuspendResume); | |
40a37d08 | 254 | return true; |
14957cd0 A |
255 | #else |
256 | #error Need a way to suspend threads on this platform | |
257 | #endif | |
258 | } | |
259 | ||
260 | static inline void resumeThread(const PlatformThread& platformThread) | |
261 | { | |
262 | #if OS(DARWIN) | |
263 | thread_resume(platformThread); | |
264 | #elif OS(WINDOWS) | |
265 | ResumeThread(platformThread); | |
266 | #elif USE(PTHREADS) | |
267 | pthread_kill(platformThread, SigThreadSuspendResume); | |
268 | #else | |
269 | #error Need a way to resume threads on this platform | |
270 | #endif | |
271 | } | |
272 | ||
273 | typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit | |
274 | ||
275 | #if OS(DARWIN) | |
276 | ||
277 | #if CPU(X86) | |
278 | typedef i386_thread_state_t PlatformThreadRegisters; | |
279 | #elif CPU(X86_64) | |
280 | typedef x86_thread_state64_t PlatformThreadRegisters; | |
281 | #elif CPU(PPC) | |
282 | typedef ppc_thread_state_t PlatformThreadRegisters; | |
283 | #elif CPU(PPC64) | |
284 | typedef ppc_thread_state64_t PlatformThreadRegisters; | |
285 | #elif CPU(ARM) | |
286 | typedef arm_thread_state_t PlatformThreadRegisters; | |
93a37866 A |
287 | #elif CPU(ARM64) |
288 | typedef arm_thread_state64_t PlatformThreadRegisters; | |
14957cd0 A |
289 | #else |
290 | #error Unknown Architecture | |
291 | #endif | |
292 | ||
293 | #elif OS(WINDOWS) | |
294 | typedef CONTEXT PlatformThreadRegisters; | |
295 | #elif USE(PTHREADS) | |
296 | typedef pthread_attr_t PlatformThreadRegisters; | |
297 | #else | |
298 | #error Need a thread register struct for this platform | |
299 | #endif | |
300 | ||
301 | static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) | |
302 | { | |
303 | #if OS(DARWIN) | |
304 | ||
305 | #if CPU(X86) | |
306 | unsigned user_count = sizeof(regs)/sizeof(int); | |
307 | thread_state_flavor_t flavor = i386_THREAD_STATE; | |
308 | #elif CPU(X86_64) | |
309 | unsigned user_count = x86_THREAD_STATE64_COUNT; | |
310 | thread_state_flavor_t flavor = x86_THREAD_STATE64; | |
311 | #elif CPU(PPC) | |
312 | unsigned user_count = PPC_THREAD_STATE_COUNT; | |
313 | thread_state_flavor_t flavor = PPC_THREAD_STATE; | |
314 | #elif CPU(PPC64) | |
315 | unsigned user_count = PPC_THREAD_STATE64_COUNT; | |
316 | thread_state_flavor_t flavor = PPC_THREAD_STATE64; | |
317 | #elif CPU(ARM) | |
318 | unsigned user_count = ARM_THREAD_STATE_COUNT; | |
319 | thread_state_flavor_t flavor = ARM_THREAD_STATE; | |
93a37866 A |
320 | #elif CPU(ARM64) |
321 | unsigned user_count = ARM_THREAD_STATE64_COUNT; | |
322 | thread_state_flavor_t flavor = ARM_THREAD_STATE64; | |
14957cd0 A |
323 | #else |
324 | #error Unknown Architecture | |
325 | #endif | |
326 | ||
327 | kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count); | |
328 | if (result != KERN_SUCCESS) { | |
329 | WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, | |
330 | "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result); | |
331 | CRASH(); | |
332 | } | |
333 | return user_count * sizeof(usword_t); | |
334 | // end OS(DARWIN) | |
335 | ||
336 | #elif OS(WINDOWS) | |
6fe7ccc8 | 337 | regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; |
14957cd0 A |
338 | GetThreadContext(platformThread, ®s); |
339 | return sizeof(CONTEXT); | |
340 | #elif USE(PTHREADS) | |
341 | pthread_attr_init(®s); | |
342 | #if HAVE(PTHREAD_NP_H) || OS(NETBSD) | |
81345200 | 343 | #if !OS(OPENBSD) |
14957cd0 A |
344 | // e.g. on FreeBSD 5.4, neundorf@kde.org |
345 | pthread_attr_get_np(platformThread, ®s); | |
81345200 | 346 | #endif |
14957cd0 A |
347 | #else |
348 | // FIXME: this function is non-portable; other POSIX systems may have different np alternatives | |
349 | pthread_getattr_np(platformThread, ®s); | |
350 | #endif | |
351 | return 0; | |
352 | #else | |
353 | #error Need a way to get thread registers on this platform | |
354 | #endif | |
355 | } | |
356 | ||
357 | static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) | |
358 | { | |
359 | #if OS(DARWIN) | |
360 | ||
361 | #if __DARWIN_UNIX03 | |
362 | ||
363 | #if CPU(X86) | |
364 | return reinterpret_cast<void*>(regs.__esp); | |
365 | #elif CPU(X86_64) | |
366 | return reinterpret_cast<void*>(regs.__rsp); | |
367 | #elif CPU(PPC) || CPU(PPC64) | |
368 | return reinterpret_cast<void*>(regs.__r1); | |
369 | #elif CPU(ARM) | |
370 | return reinterpret_cast<void*>(regs.__sp); | |
93a37866 A |
371 | #elif CPU(ARM64) |
372 | return reinterpret_cast<void*>(regs.__sp); | |
14957cd0 A |
373 | #else |
374 | #error Unknown Architecture | |
375 | #endif | |
376 | ||
377 | #else // !__DARWIN_UNIX03 | |
378 | ||
379 | #if CPU(X86) | |
380 | return reinterpret_cast<void*>(regs.esp); | |
381 | #elif CPU(X86_64) | |
382 | return reinterpret_cast<void*>(regs.rsp); | |
383 | #elif CPU(PPC) || CPU(PPC64) | |
384 | return reinterpret_cast<void*>(regs.r1); | |
385 | #else | |
386 | #error Unknown Architecture | |
387 | #endif | |
388 | ||
389 | #endif // __DARWIN_UNIX03 | |
390 | ||
391 | // end OS(DARWIN) | |
6fe7ccc8 A |
392 | #elif OS(WINDOWS) |
393 | ||
394 | #if CPU(ARM) | |
395 | return reinterpret_cast<void*>((uintptr_t) regs.Sp); | |
396 | #elif CPU(MIPS) | |
397 | return reinterpret_cast<void*>((uintptr_t) regs.IntSp); | |
398 | #elif CPU(X86) | |
14957cd0 | 399 | return reinterpret_cast<void*>((uintptr_t) regs.Esp); |
6fe7ccc8 | 400 | #elif CPU(X86_64) |
14957cd0 | 401 | return reinterpret_cast<void*>((uintptr_t) regs.Rsp); |
6fe7ccc8 A |
402 | #else |
403 | #error Unknown Architecture | |
404 | #endif | |
405 | ||
14957cd0 A |
406 | #elif USE(PTHREADS) |
407 | void* stackBase = 0; | |
408 | size_t stackSize = 0; | |
81345200 A |
409 | #if OS(OPENBSD) |
410 | stack_t ss; | |
411 | int rc = pthread_stackseg_np(pthread_self(), &ss); | |
412 | stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size); | |
413 | stackSize = ss.ss_size; | |
414 | #else | |
14957cd0 | 415 | int rc = pthread_attr_getstack(®s, &stackBase, &stackSize); |
81345200 | 416 | #endif |
14957cd0 A |
417 | (void)rc; // FIXME: Deal with error code somehow? Seems fatal. |
418 | ASSERT(stackBase); | |
419 | return static_cast<char*>(stackBase) + stackSize; | |
420 | #else | |
421 | #error Need a way to get the stack pointer for another thread on this platform | |
422 | #endif | |
423 | } | |
424 | ||
425 | static void freePlatformThreadRegisters(PlatformThreadRegisters& regs) | |
426 | { | |
81345200 | 427 | #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) |
14957cd0 A |
428 | pthread_attr_destroy(®s); |
429 | #else | |
430 | UNUSED_PARAM(regs); | |
431 | #endif | |
432 | } | |
433 | ||
81345200 | 434 | void MachineThreads::gatherFromOtherThread(ConservativeRoots& conservativeRoots, Thread* thread, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks) |
14957cd0 | 435 | { |
14957cd0 A |
436 | PlatformThreadRegisters regs; |
437 | size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); | |
438 | ||
81345200 | 439 | conservativeRoots.add(static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize), jitStubRoutines, codeBlocks); |
14957cd0 A |
440 | |
441 | void* stackPointer = otherThreadStackPointer(regs); | |
442 | void* stackBase = thread->stackBase; | |
443 | swapIfBackwards(stackPointer, stackBase); | |
81345200 A |
444 | stackPointer = reinterpret_cast<void*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackPointer))); |
445 | conservativeRoots.add(stackPointer, stackBase, jitStubRoutines, codeBlocks); | |
14957cd0 | 446 | |
14957cd0 A |
447 | freePlatformThreadRegisters(regs); |
448 | } | |
449 | ||
40a37d08 | 450 | void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers) |
14957cd0 | 451 | { |
40a37d08 | 452 | gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackCurrent, registers); |
14957cd0 | 453 | |
14957cd0 | 454 | if (m_threadSpecific) { |
6fe7ccc8 | 455 | PlatformThread currentPlatformThread = getCurrentPlatformThread(); |
14957cd0 A |
456 | |
457 | MutexLocker lock(m_registeredThreadsMutex); | |
458 | ||
40a37d08 A |
459 | Thread* threadsToBeDeleted = nullptr; |
460 | ||
14957cd0 A |
461 | #ifndef NDEBUG |
462 | // Forbid malloc during the gather phase. The gather phase suspends | |
463 | // threads, so a malloc during gather would risk a deadlock with a | |
464 | // thread that had been suspended while holding the malloc lock. | |
465 | fastMallocForbid(); | |
466 | #endif | |
40a37d08 A |
467 | int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet. |
468 | int index = 1; | |
469 | Thread* previousThread = nullptr; | |
470 | for (Thread* thread = m_registeredThreads; thread; index++) { | |
471 | if (!equalThread(thread->platformThread, currentPlatformThread)) { | |
472 | bool success = suspendThread(thread->platformThread); | |
473 | #if OS(DARWIN) | |
474 | if (!success) { | |
475 | if (!numberOfThreads) { | |
476 | for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next) | |
477 | numberOfThreads++; | |
478 | } | |
479 | ||
480 | // Re-do the suspension to get the actual failure result for logging. | |
481 | kern_return_t error = thread_suspend(thread->platformThread); | |
482 | ASSERT(error != KERN_SUCCESS); | |
483 | ||
484 | WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, | |
485 | "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.", | |
486 | error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread)); | |
487 | ||
488 | // Put the invalid thread on the threadsToBeDeleted list. | |
489 | // We can't just delete it here because we have suspended other | |
490 | // threads, and they may still be holding the C heap lock which | |
491 | // we need for deleting the invalid thread. Hence, we need to | |
492 | // defer the deletion till after we have resumed all threads. | |
493 | Thread* nextThread = thread->next; | |
494 | thread->next = threadsToBeDeleted; | |
495 | threadsToBeDeleted = thread; | |
496 | ||
497 | if (previousThread) | |
498 | previousThread->next = nextThread; | |
499 | else | |
500 | m_registeredThreads = nextThread; | |
501 | thread = nextThread; | |
502 | continue; | |
503 | } | |
504 | #else | |
505 | UNUSED_PARAM(numberOfThreads); | |
506 | ASSERT_UNUSED(success, success); | |
507 | #endif | |
508 | } | |
509 | previousThread = thread; | |
510 | thread = thread->next; | |
93a37866 A |
511 | } |
512 | ||
14957cd0 A |
513 | // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, |
514 | // and since this is a shared heap, they are real locks. | |
515 | for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { | |
6fe7ccc8 | 516 | if (!equalThread(thread->platformThread, currentPlatformThread)) |
81345200 | 517 | gatherFromOtherThread(conservativeRoots, thread, jitStubRoutines, codeBlocks); |
14957cd0 | 518 | } |
93a37866 A |
519 | |
520 | for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { | |
521 | if (!equalThread(thread->platformThread, currentPlatformThread)) | |
522 | resumeThread(thread->platformThread); | |
523 | } | |
524 | ||
14957cd0 A |
525 | #ifndef NDEBUG |
526 | fastMallocAllow(); | |
527 | #endif | |
40a37d08 A |
528 | for (Thread* thread = threadsToBeDeleted; thread; ) { |
529 | Thread* nextThread = thread->next; | |
530 | delete thread; | |
531 | thread = nextThread; | |
532 | } | |
14957cd0 | 533 | } |
14957cd0 A |
534 | } |
535 | ||
536 | } // namespace JSC |