Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

Commit 237c568

Browse files
[JSC] MachineThreads does not consider situation that one thread has multiple VMs
https://bugs.webkit.org/show_bug.cgi?id=169819 Reviewed by Mark Lam. The Linux port of PlatformThread suspend/resume mechanism relies on having a thread specific singleton thread data, and was relying on MachineThreads::Thread to be this thread specific singleton. But because MachineThreads::Thread is not a thread specific singleton, we can get a deadlock in the GTK port's DatabaseProcess. This patch fixes this issue by moving per thread data from MachineThreads::Thread to MachineThreads::ThreadData, where there will only be one instance of MachineThreads::ThreadData per thread. Each MachineThreads::Thread will now point to the same MachineThreads::ThreadData for any given thread. * heap/MachineStackMarker.cpp: (pthreadSignalHandlerSuspendResume): (JSC::threadData): (JSC::MachineThreads::Thread::Thread): (JSC::MachineThreads::Thread::createForCurrentThread): (JSC::MachineThreads::Thread::operator==): (JSC::MachineThreads::ThreadData::ThreadData): (JSC::MachineThreads::ThreadData::~ThreadData): (JSC::MachineThreads::ThreadData::suspend): (JSC::MachineThreads::ThreadData::resume): (JSC::MachineThreads::ThreadData::getRegisters): (JSC::MachineThreads::ThreadData::Registers::stackPointer): (JSC::MachineThreads::ThreadData::Registers::framePointer): (JSC::MachineThreads::ThreadData::Registers::instructionPointer): (JSC::MachineThreads::ThreadData::Registers::llintPC): (JSC::MachineThreads::ThreadData::freeRegisters): (JSC::MachineThreads::ThreadData::captureStack): (JSC::MachineThreads::tryCopyOtherThreadStacks): (JSC::MachineThreads::Thread::~Thread): Deleted. (JSC::MachineThreads::Thread::suspend): Deleted. (JSC::MachineThreads::Thread::resume): Deleted. (JSC::MachineThreads::Thread::getRegisters): Deleted. (JSC::MachineThreads::Thread::Registers::stackPointer): Deleted. (JSC::MachineThreads::Thread::Registers::framePointer): Deleted. (JSC::MachineThreads::Thread::Registers::instructionPointer): Deleted. (JSC::MachineThreads::Thread::Registers::llintPC): Deleted. (JSC::MachineThreads::Thread::freeRegisters): Deleted. (JSC::MachineThreads::Thread::captureStack): Deleted. * heap/MachineStackMarker.h: (JSC::MachineThreads::Thread::operator!=): (JSC::MachineThreads::Thread::suspend): (JSC::MachineThreads::Thread::resume): (JSC::MachineThreads::Thread::getRegisters): (JSC::MachineThreads::Thread::freeRegisters): (JSC::MachineThreads::Thread::captureStack): (JSC::MachineThreads::Thread::platformThread): (JSC::MachineThreads::Thread::stackBase): (JSC::MachineThreads::Thread::stackEnd): * runtime/SamplingProfiler.cpp: (JSC::FrameWalker::isValidFramePointer): * runtime/VMTraps.cpp: (JSC::findActiveVMAndStackBounds): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@214319 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 4a2e532 commit 237c568

File tree

5 files changed

+140
-45
lines changed

5 files changed

+140
-45
lines changed

Source/JavaScriptCore/ChangeLog

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,63 @@
1+
2017-03-23 Yusuke Suzuki <[email protected]>
2+
3+
[JSC] MachineThreads does not consider situation that one thread has multiple VMs
4+
https://bugs.webkit.org/show_bug.cgi?id=169819
5+
6+
Reviewed by Mark Lam.
7+
8+
The Linux port of PlatformThread suspend/resume mechanism relies on having a thread
9+
specific singleton thread data, and was relying on MachineThreads::Thread to be this
10+
thread specific singleton. But because MachineThreads::Thread is not a thread specific
11+
singleton, we can get a deadlock in the GTK port's DatabaseProcess.
12+
13+
This patch fixes this issue by moving per thread data from MachineThreads::Thread to
14+
MachineThreads::ThreadData, where there will only be one instance of
15+
MachineThreads::ThreadData per thread. Each MachineThreads::Thread will now point to
16+
the same MachineThreads::ThreadData for any given thread.
17+
18+
* heap/MachineStackMarker.cpp:
19+
(pthreadSignalHandlerSuspendResume):
20+
(JSC::threadData):
21+
(JSC::MachineThreads::Thread::Thread):
22+
(JSC::MachineThreads::Thread::createForCurrentThread):
23+
(JSC::MachineThreads::Thread::operator==):
24+
(JSC::MachineThreads::ThreadData::ThreadData):
25+
(JSC::MachineThreads::ThreadData::~ThreadData):
26+
(JSC::MachineThreads::ThreadData::suspend):
27+
(JSC::MachineThreads::ThreadData::resume):
28+
(JSC::MachineThreads::ThreadData::getRegisters):
29+
(JSC::MachineThreads::ThreadData::Registers::stackPointer):
30+
(JSC::MachineThreads::ThreadData::Registers::framePointer):
31+
(JSC::MachineThreads::ThreadData::Registers::instructionPointer):
32+
(JSC::MachineThreads::ThreadData::Registers::llintPC):
33+
(JSC::MachineThreads::ThreadData::freeRegisters):
34+
(JSC::MachineThreads::ThreadData::captureStack):
35+
(JSC::MachineThreads::tryCopyOtherThreadStacks):
36+
(JSC::MachineThreads::Thread::~Thread): Deleted.
37+
(JSC::MachineThreads::Thread::suspend): Deleted.
38+
(JSC::MachineThreads::Thread::resume): Deleted.
39+
(JSC::MachineThreads::Thread::getRegisters): Deleted.
40+
(JSC::MachineThreads::Thread::Registers::stackPointer): Deleted.
41+
(JSC::MachineThreads::Thread::Registers::framePointer): Deleted.
42+
(JSC::MachineThreads::Thread::Registers::instructionPointer): Deleted.
43+
(JSC::MachineThreads::Thread::Registers::llintPC): Deleted.
44+
(JSC::MachineThreads::Thread::freeRegisters): Deleted.
45+
(JSC::MachineThreads::Thread::captureStack): Deleted.
46+
* heap/MachineStackMarker.h:
47+
(JSC::MachineThreads::Thread::operator!=):
48+
(JSC::MachineThreads::Thread::suspend):
49+
(JSC::MachineThreads::Thread::resume):
50+
(JSC::MachineThreads::Thread::getRegisters):
51+
(JSC::MachineThreads::Thread::freeRegisters):
52+
(JSC::MachineThreads::Thread::captureStack):
53+
(JSC::MachineThreads::Thread::platformThread):
54+
(JSC::MachineThreads::Thread::stackBase):
55+
(JSC::MachineThreads::Thread::stackEnd):
56+
* runtime/SamplingProfiler.cpp:
57+
(JSC::FrameWalker::isValidFramePointer):
58+
* runtime/VMTraps.cpp:
59+
(JSC::findActiveVMAndStackBounds):
60+
161
2017-03-23 Mark Lam <[email protected]>
262

363
Clients of JSArray::tryCreateForInitializationPrivate() should do their own null checks.

Source/JavaScriptCore/heap/MachineStackMarker.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <setjmp.h>
3434
#include <stdlib.h>
3535
#include <wtf/MainThread.h>
36+
#include <wtf/NeverDestroyed.h>
3637
#include <wtf/StdLibExtras.h>
3738

3839
#if OS(DARWIN)
@@ -69,14 +70,14 @@
6970
// We use SIGUSR2 to suspend and resume machine threads in JavaScriptCore.
7071
static const int SigThreadSuspendResume = SIGUSR2;
7172
static StaticLock globalSignalLock;
72-
thread_local static std::atomic<JSC::MachineThreads::Thread*> threadLocalCurrentThread;
73+
thread_local static std::atomic<JSC::MachineThreads::ThreadData*> threadLocalCurrentThread { nullptr };
7374

7475
static void pthreadSignalHandlerSuspendResume(int, siginfo_t*, void* ucontext)
7576
{
7677
// Touching thread local atomic types from signal handlers is allowed.
77-
JSC::MachineThreads::Thread* thread = threadLocalCurrentThread.load();
78+
JSC::MachineThreads::ThreadData* threadData = threadLocalCurrentThread.load();
7879

79-
if (thread->suspended.load(std::memory_order_acquire)) {
80+
if (threadData->suspended.load(std::memory_order_acquire)) {
8081
// This is signal handler invocation that is intended to be used to resume sigsuspend.
8182
// So this handler invocation itself should not process.
8283
//
@@ -88,9 +89,9 @@ static void pthreadSignalHandlerSuspendResume(int, siginfo_t*, void* ucontext)
8889

8990
ucontext_t* userContext = static_cast<ucontext_t*>(ucontext);
9091
#if CPU(PPC)
91-
thread->suspendedMachineContext = *userContext->uc_mcontext.uc_regs;
92+
threadData->suspendedMachineContext = *userContext->uc_mcontext.uc_regs;
9293
#else
93-
thread->suspendedMachineContext = userContext->uc_mcontext;
94+
threadData->suspendedMachineContext = userContext->uc_mcontext;
9495
#endif
9596

9697
// Allow suspend caller to see that this thread is suspended.
@@ -99,7 +100,7 @@ static void pthreadSignalHandlerSuspendResume(int, siginfo_t*, void* ucontext)
99100
//
100101
// And sem_post emits memory barrier that ensures that suspendedMachineContext is correctly saved.
101102
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11
102-
sem_post(&thread->semaphoreForSuspendResume);
103+
sem_post(&threadData->semaphoreForSuspendResume);
103104

104105
// Reaching here, SigThreadSuspendResume is blocked in this handler (this is configured by sigaction's sa_mask).
105106
// So before calling sigsuspend, SigThreadSuspendResume to this thread is deferred. This ensures that the handler is not executed recursively.
@@ -109,7 +110,7 @@ static void pthreadSignalHandlerSuspendResume(int, siginfo_t*, void* ucontext)
109110
sigsuspend(&blockedSignalSet);
110111

111112
// Allow resume caller to see that this thread is resumed.
112-
sem_post(&thread->semaphoreForSuspendResume);
113+
sem_post(&threadData->semaphoreForSuspendResume);
113114
}
114115
#endif // USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
115116

@@ -200,18 +201,29 @@ MachineThreads::~MachineThreads()
200201
}
201202
}
202203

204+
static MachineThreads::ThreadData* threadData()
205+
{
206+
static NeverDestroyed<ThreadSpecific<MachineThreads::ThreadData, CanBeGCThread::True>> threadData;
207+
return threadData.get();
208+
}
209+
210+
MachineThreads::Thread::Thread(ThreadData* threadData)
211+
: data(threadData)
212+
{
213+
ASSERT(threadData);
214+
}
215+
203216
Thread* MachineThreads::Thread::createForCurrentThread()
204217
{
205-
auto stackBounds = wtfThreadData().stack();
206-
return new Thread(currentPlatformThread(), stackBounds.origin(), stackBounds.end());
218+
return new Thread(threadData());
207219
}
208220

209221
bool MachineThreads::Thread::operator==(const PlatformThread& other) const
210222
{
211223
#if OS(DARWIN) || OS(WINDOWS)
212-
return platformThread == other;
224+
return data->platformThread == other;
213225
#elif USE(PTHREADS)
214-
return !!pthread_equal(platformThread, other);
226+
return !!pthread_equal(data->platformThread, other);
215227
#else
216228
#error Need a way to compare threads on this platform
217229
#endif
@@ -308,11 +320,13 @@ void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoot
308320
conservativeRoots.add(currentThreadState.stackTop, currentThreadState.stackOrigin, jitStubRoutines, codeBlocks);
309321
}
310322

311-
MachineThreads::Thread::Thread(const PlatformThread& platThread, void* base, void* end)
312-
: platformThread(platThread)
313-
, stackBase(base)
314-
, stackEnd(end)
323+
MachineThreads::ThreadData::ThreadData()
315324
{
325+
auto stackBounds = wtfThreadData().stack();
326+
platformThread = currentPlatformThread();
327+
stackBase = stackBounds.origin();
328+
stackEnd = stackBounds.end();
329+
316330
#if OS(WINDOWS)
317331
ASSERT(platformThread == GetCurrentThreadId());
318332
bool isSuccessful =
@@ -345,7 +359,7 @@ MachineThreads::Thread::Thread(const PlatformThread& platThread, void* base, voi
345359
#endif
346360
}
347361

348-
MachineThreads::Thread::~Thread()
362+
MachineThreads::ThreadData::~ThreadData()
349363
{
350364
#if OS(WINDOWS)
351365
CloseHandle(platformThreadHandle);
@@ -354,7 +368,7 @@ MachineThreads::Thread::~Thread()
354368
#endif
355369
}
356370

357-
bool MachineThreads::Thread::suspend()
371+
bool MachineThreads::ThreadData::suspend()
358372
{
359373
#if OS(DARWIN)
360374
kern_return_t result = thread_suspend(platformThread);
@@ -391,7 +405,7 @@ bool MachineThreads::Thread::suspend()
391405
#endif
392406
}
393407

394-
void MachineThreads::Thread::resume()
408+
void MachineThreads::ThreadData::resume()
395409
{
396410
#if OS(DARWIN)
397411
thread_resume(platformThread);
@@ -422,9 +436,9 @@ void MachineThreads::Thread::resume()
422436
#endif
423437
}
424438

425-
size_t MachineThreads::Thread::getRegisters(Thread::Registers& registers)
439+
size_t MachineThreads::ThreadData::getRegisters(ThreadData::Registers& registers)
426440
{
427-
Thread::Registers::PlatformRegisters& regs = registers.regs;
441+
ThreadData::Registers::PlatformRegisters& regs = registers.regs;
428442
#if OS(DARWIN)
429443
#if CPU(X86)
430444
unsigned user_count = sizeof(regs)/sizeof(int);
@@ -481,7 +495,7 @@ size_t MachineThreads::Thread::getRegisters(Thread::Registers& registers)
481495
#endif
482496
}
483497

484-
void* MachineThreads::Thread::Registers::stackPointer() const
498+
void* MachineThreads::ThreadData::Registers::stackPointer() const
485499
{
486500
#if OS(DARWIN) || OS(WINDOWS) || ((OS(FREEBSD) || defined(__GLIBC__)) && ENABLE(JIT))
487501
return MachineContext::stackPointer(regs);
@@ -505,7 +519,7 @@ void* MachineThreads::Thread::Registers::stackPointer() const
505519
}
506520

507521
#if ENABLE(SAMPLING_PROFILER)
508-
void* MachineThreads::Thread::Registers::framePointer() const
522+
void* MachineThreads::ThreadData::Registers::framePointer() const
509523
{
510524
#if OS(DARWIN) || OS(WINDOWS) || (OS(FREEBSD) || defined(__GLIBC__))
511525
return MachineContext::framePointer(regs);
@@ -514,7 +528,7 @@ void* MachineThreads::Thread::Registers::framePointer() const
514528
#endif
515529
}
516530

517-
void* MachineThreads::Thread::Registers::instructionPointer() const
531+
void* MachineThreads::ThreadData::Registers::instructionPointer() const
518532
{
519533
#if OS(DARWIN) || OS(WINDOWS) || (OS(FREEBSD) || defined(__GLIBC__))
520534
return MachineContext::instructionPointer(regs);
@@ -523,7 +537,7 @@ void* MachineThreads::Thread::Registers::instructionPointer() const
523537
#endif
524538
}
525539

526-
void* MachineThreads::Thread::Registers::llintPC() const
540+
void* MachineThreads::ThreadData::Registers::llintPC() const
527541
{
528542
// LLInt uses regT4 as PC.
529543
#if OS(DARWIN) || OS(WINDOWS) || (OS(FREEBSD) || defined(__GLIBC__))
@@ -534,9 +548,9 @@ void* MachineThreads::Thread::Registers::llintPC() const
534548
}
535549
#endif // ENABLE(SAMPLING_PROFILER)
536550

537-
void MachineThreads::Thread::freeRegisters(Thread::Registers& registers)
551+
void MachineThreads::ThreadData::freeRegisters(ThreadData::Registers& registers)
538552
{
539-
Thread::Registers::PlatformRegisters& regs = registers.regs;
553+
ThreadData::Registers::PlatformRegisters& regs = registers.regs;
540554
#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) && !((OS(FREEBSD) || defined(__GLIBC__)) && ENABLE(JIT))
541555
pthread_attr_destroy(&regs.attribute);
542556
#else
@@ -559,7 +573,7 @@ static inline int osRedZoneAdjustment()
559573
return redZoneAdjustment;
560574
}
561575

562-
std::pair<void*, size_t> MachineThreads::Thread::captureStack(void* stackTop)
576+
std::pair<void*, size_t> MachineThreads::ThreadData::captureStack(void* stackTop)
563577
{
564578
char* begin = reinterpret_cast_ptr<char*>(stackBase);
565579
char* end = bitwise_cast<char*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop)));
@@ -647,12 +661,12 @@ bool MachineThreads::tryCopyOtherThreadStacks(const AbstractLocker&, void* buffe
647661
}
648662

649663
// Re-do the suspension to get the actual failure result for logging.
650-
kern_return_t error = thread_suspend(thread->platformThread);
664+
kern_return_t error = thread_suspend(thread->platformThread());
651665
ASSERT(error != KERN_SUCCESS);
652666

653667
WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
654668
"JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
655-
error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
669+
error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread()));
656670

657671
// Put the invalid thread on the threadsToBeDeleted list.
658672
// We can't just delete it here because we have suspended other

Source/JavaScriptCore/heap/MachineStackMarker.h

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,13 @@ class MachineThreads {
6464

6565
JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
6666

67-
class Thread {
67+
class ThreadData {
6868
WTF_MAKE_FAST_ALLOCATED;
69-
Thread(const PlatformThread& platThread, void* base, void* end);
70-
7169
public:
72-
~Thread();
70+
ThreadData();
71+
~ThreadData();
7372

74-
static Thread* createForCurrentThread();
73+
static ThreadData* createForCurrentThread();
7574

7675
struct Registers {
7776
void* stackPointer() const;
@@ -92,20 +91,16 @@ class MachineThreads {
9291
#else
9392
#error Need a thread register struct for this platform
9493
#endif
95-
94+
9695
PlatformRegisters regs;
9796
};
98-
99-
bool operator==(const PlatformThread& other) const;
100-
bool operator!=(const PlatformThread& other) const { return !(*this == other); }
10197

10298
bool suspend();
10399
void resume();
104100
size_t getRegisters(Registers&);
105101
void freeRegisters(Registers&);
106102
std::pair<void*, size_t> captureStack(void* stackTop);
107103

108-
Thread* next;
109104
PlatformThread platformThread;
110105
void* stackBase;
111106
void* stackEnd;
@@ -119,6 +114,32 @@ class MachineThreads {
119114
#endif
120115
};
121116

117+
class Thread {
118+
WTF_MAKE_FAST_ALLOCATED;
119+
Thread(ThreadData*);
120+
121+
public:
122+
using Registers = ThreadData::Registers;
123+
124+
static Thread* createForCurrentThread();
125+
126+
bool operator==(const PlatformThread& other) const;
127+
bool operator!=(const PlatformThread& other) const { return !(*this == other); }
128+
129+
bool suspend() { return data->suspend(); }
130+
void resume() { data->resume(); }
131+
size_t getRegisters(Registers& regs) { return data->getRegisters(regs); }
132+
void freeRegisters(Registers& regs) { data->freeRegisters(regs); }
133+
std::pair<void*, size_t> captureStack(void* stackTop) { return data->captureStack(stackTop); }
134+
135+
const PlatformThread& platformThread() { return data->platformThread; }
136+
void* stackBase() const { return data->stackBase; }
137+
void* stackEnd() const { return data->stackEnd; }
138+
139+
Thread* next;
140+
ThreadData* data;
141+
};
142+
122143
Lock& getLock() { return m_registeredThreadsMutex; }
123144
Thread* threadsListHead(const AbstractLocker&) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }
124145
Thread* machineThreadForCurrentThread();

Source/JavaScriptCore/runtime/SamplingProfiler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ class FrameWalker {
169169
{
170170
uint8_t* fpCast = bitwise_cast<uint8_t*>(exec);
171171
for (MachineThreads::Thread* thread = m_vm.heap.machineThreads().threadsListHead(m_machineThreadsLocker); thread; thread = thread->next) {
172-
uint8_t* stackBase = static_cast<uint8_t*>(thread->stackBase);
173-
uint8_t* stackLimit = static_cast<uint8_t*>(thread->stackEnd);
172+
uint8_t* stackBase = static_cast<uint8_t*>(thread->stackBase());
173+
uint8_t* stackLimit = static_cast<uint8_t*>(thread->stackEnd());
174174
RELEASE_ASSERT(stackBase);
175175
RELEASE_ASSERT(stackLimit);
176176
if (fpCast <= stackBase && fpCast >= stackLimit)

Source/JavaScriptCore/runtime/VMTraps.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ static Expected<std::pair<VM*, StackBounds>, VMTraps::Error> findActiveVMAndStac
111111
}
112112

113113
for (MachineThreads::Thread* thread = machineThreads.threadsListHead(machineThreadsLocker); thread; thread = thread->next) {
114-
RELEASE_ASSERT(thread->stackBase);
115-
RELEASE_ASSERT(thread->stackEnd);
116-
if (stackPointer <= thread->stackBase && stackPointer >= thread->stackEnd) {
114+
RELEASE_ASSERT(thread->stackBase());
115+
RELEASE_ASSERT(thread->stackEnd());
116+
if (stackPointer <= thread->stackBase() && stackPointer >= thread->stackEnd()) {
117117
activeVM = &vm;
118-
stackBounds = StackBounds(thread->stackBase, thread->stackEnd);
118+
stackBounds = StackBounds(thread->stackBase(), thread->stackEnd());
119119
return VMInspector::FunctorStatus::Done;
120120
}
121121
}

0 commit comments

Comments
 (0)