Changeset 218080 in webkit
- Timestamp:
- Jun 11, 2017, 5:47:18 PM (8 years ago)
- Location:
- trunk/Source
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r218070 r218080 1 2017-06-11 Yusuke Suzuki <[email protected]> 2 3 [WTF] Make ThreadMessage portable 4 https://bugs.webkit.org/show_bug.cgi?id=172073 5 6 Reviewed by Keith Miller. 7 8 * runtime/MachineContext.h: 9 (JSC::MachineContext::stackPointer): 10 * tools/CodeProfiling.cpp: 11 (JSC::profilingTimer): 12 1 13 2017-06-11 Yusuke Suzuki <[email protected]> 2 14 -
trunk/Source/JavaScriptCore/runtime/MachineContext.h
r215270 r218080 34 34 namespace MachineContext { 35 35 36 36 void* stackPointer(const PlatformRegisters&); 37 38 #if OS(WINDOWS) || HAVE(MACHINE_CONTEXT) 37 39 void*& stackPointer(PlatformRegisters&); 38 void* stackPointer(const PlatformRegisters&);39 40 #if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)41 40 void*& framePointer(PlatformRegisters&); 42 41 void* framePointer(const PlatformRegisters&); … … 65 64 #endif // OS(WINDOWS) || HAVE(MACHINE_CONTEXT) 66 65 66 #if OS(WINDOWS) || HAVE(MACHINE_CONTEXT) 67 67 inline void*& stackPointer(PlatformRegisters& regs) 68 68 { … … 112 112 #elif HAVE(MACHINE_CONTEXT) 113 113 return stackPointer(regs.machineContext); 114 #else 114 #endif 115 } 116 117 inline void* stackPointer(const PlatformRegisters& regs) 118 { 119 return stackPointer(const_cast<PlatformRegisters&>(regs)); 120 } 121 #else // not OS(WINDOWS) || HAVE(MACHINE_CONTEXT) 122 inline void* stackPointer(const PlatformRegisters& regs) 123 { 115 124 return regs.stackPointer; 116 #endif 117 } 118 119 inline void* stackPointer(const PlatformRegisters& regs) 120 { 121 return stackPointer(const_cast<PlatformRegisters&>(regs)); 122 } 123 125 } 126 #endif // OS(WINDOWS) || HAVE(MACHINE_CONTEXT) 124 127 125 128 #if HAVE(MACHINE_CONTEXT) -
trunk/Source/JavaScriptCore/tools/CodeProfiling.cpp
r215318 r218080 71 71 static void profilingTimer(int, siginfo_t*, void* uap) 72 72 { 73 mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext;73 PlatformRegisters& platformRegisters = WTF::registersFromUContext(static_cast<ucontext_t*>(uap)); 74 74 CodeProfiling::sample( 75 MachineContext::instructionPointer( context),76 reinterpret_cast<void**>(MachineContext::framePointer( context)));75 MachineContext::instructionPointer(platformRegisters), 76 reinterpret_cast<void**>(MachineContext::framePointer(platformRegisters))); 77 77 } 78 78 #endif -
trunk/Source/WTF/ChangeLog
r218069 r218080 1 2017-06-11 Yusuke Suzuki <[email protected]> 2 3 [WTF] Make ThreadMessage portable 4 https://bugs.webkit.org/show_bug.cgi?id=172073 5 6 Reviewed by Keith Miller. 7 8 Recently, we change ThreadMessage semantics: message handler 9 can be executed in the sender thread. 10 This allows ThreadMessage to be implemented in a portable way. 11 12 This patch implements ThreadMessage for all the platforms. 13 We use platform-independent Thread APIs, suspend(), resume(), 14 and getRegisters(). 15 16 * wtf/PlatformRegisters.h: 17 (WTF::registersFromUContext): 18 * wtf/ThreadMessage.cpp: 19 (WTF::sendMessageScoped): 20 (WTF::ThreadMessageData::ThreadMessageData): Deleted. 21 (): Deleted. 22 (WTF::initializeThreadMessages): Deleted. 23 (WTF::sendMessageUsingSignal): Deleted. 24 (WTF::sendMessageUsingMach): Deleted. 25 (WTF::deliverMessagesUsingMach): Deleted. 26 * wtf/ThreadMessage.h: 27 * wtf/Threading.cpp: 28 (WTF::initializeThreading): 29 * wtf/Threading.h: 30 (WTF::Thread::threadMessages): Deleted. 31 * wtf/ThreadingPthreads.cpp: 32 (WTF::Thread::signalHandlerSuspendResume): 33 (WTF::threadStateMetadata): 34 (WTF::Thread::getRegisters): 35 * wtf/threads/Signals.cpp: 36 (WTF::handleSignalsWithMach): 37 1 38 2017-06-11 Yusuke Suzuki <[email protected]> 2 39 -
trunk/Source/WTF/wtf/PlatformRegisters.h
r217669 r218080 75 75 inline PlatformRegisters& registersFromUContext(ucontext_t* ucontext) 76 76 { 77 #if CPU(PPC) 78 return *bitwise_cast<PlatformRegisters*>(ucontext->uc_mcontext.uc_regs); 79 #else 77 80 return *bitwise_cast<PlatformRegisters*>(&ucontext->uc_mcontext); 81 #endif 78 82 } 79 83 -
trunk/Source/WTF/wtf/ThreadMessage.cpp
r217669 r218080 27 27 #include "ThreadMessage.h" 28 28 29 #if USE(PTHREADS)30 31 #include <fcntl.h>32 #include <unistd.h>33 34 #include <wtf/DataLog.h>35 29 #include <wtf/Lock.h> 36 30 #include <wtf/Locker.h> 37 #include <wtf/threads/Signals.h>38 39 #if HAVE(MACH_EXCEPTIONS)40 #include <mach/thread_act.h>41 #endif42 31 43 32 namespace WTF { 44 33 45 using Node = LocklessBag<ThreadMessageData*>::Node; 46 47 class ThreadMessageData { 48 WTF_MAKE_FAST_ALLOCATED; 49 public: 50 ThreadMessageData(const ThreadMessage& m) 51 : ran(nullptr) 52 , message(m) 53 { 54 } 55 56 Atomic<Node*> ran; 57 const ThreadMessage& message; 58 }; 59 60 enum FileDescriptor { 61 Read, 62 Write, 63 NumberOfFileDescriptors, 64 }; 65 66 static int fileDescriptors[NumberOfFileDescriptors]; 67 static const char* const magicByte = "d"; 68 69 70 void initializeThreadMessages() 71 { 72 int result = pipe(fileDescriptors); 73 RELEASE_ASSERT(!result); 74 75 int flags = fcntl(fileDescriptors[Write], F_GETFL); 76 result = fcntl(fileDescriptors[Write], F_SETFL, flags | O_NONBLOCK | O_APPEND); 77 flags = fcntl(fileDescriptors[Write], F_GETFL); 78 RELEASE_ASSERT(result != -1); 79 RELEASE_ASSERT((flags & O_NONBLOCK) && (flags & O_APPEND)); 80 81 flags = fcntl(fileDescriptors[Read], F_GETFL); 82 result = fcntl(fileDescriptors[Read], F_SETFL, flags & ~O_NONBLOCK); 83 flags = fcntl(fileDescriptors[Read], F_GETFL); 84 RELEASE_ASSERT(result != -1); 85 RELEASE_ASSERT(!(flags & O_NONBLOCK)); 86 } 87 88 SUPPRESS_ASAN 89 static MessageStatus sendMessageUsingSignal(Thread& thread, const ThreadMessage& message) 90 { 91 constexpr Signal signal = Signal::Usr; 92 static std::once_flag once; 93 std::call_once(once, [] { 94 installSignalHandler(signal, [] (Signal, SigInfo&, PlatformRegisters& registers) { 95 Thread* thread = Thread::currentMayBeNull(); 96 97 if (!thread) { 98 dataLogLn("We somehow got a message on a thread that didn't have a WTF::Thread initialized, we probably deadlocked, halp."); 99 return SignalAction::NotHandled; 100 } 101 102 // Node should be deleted in the sender thread. Deleting Nodes in signal handler causes dead lock. 103 thread->threadMessages().consumeAllWithNode([&] (ThreadMessageData* data, Node* node) { 104 data->message(registers); 105 // By setting ran variable, (1) the sender acknowledges the completion and 106 // (2) gets the Node to be deleted. 107 data->ran.store(node); 108 }); 109 110 while (write(fileDescriptors[Write], magicByte, 1) == -1) 111 ASSERT(errno == EAGAIN); 112 113 return SignalAction::Handled; 114 }); 115 }); 116 117 118 // Since we are guarenteed not to return until we get a response from the other thread this is ok. 119 ThreadMessageData data(message); 120 121 thread.threadMessages().add(&data); 122 bool result = thread.signal(toSystemSignal(signal)); 123 if (!result) 124 return MessageStatus::ThreadExited; 125 RELEASE_ASSERT(result); 126 127 static StaticLock readLock; 128 while (true) { 129 LockHolder locker(readLock); 130 constexpr size_t bufferSize = 16; 131 char buffer[bufferSize]; 132 133 // It's always safe to clear the pipe because only one thread can ever block trying to read 134 // from the pipe. Thus, each byte we clear from the pipe actually just corresponds to some task 135 // that has already finished. We actively want to ensure that the pipe does not overfill because 136 // otherwise our writers might spin trying to write. 137 auto clearPipe = [&] { 138 int flags = fcntl(fileDescriptors[Read], F_GETFL); 139 ASSERT(!(flags & O_NONBLOCK)); 140 fcntl(fileDescriptors[Read], F_SETFL, flags | O_NONBLOCK); 141 142 while (read(fileDescriptors[Read], buffer, bufferSize) != -1) { } 143 ASSERT(errno == EAGAIN); 144 145 fcntl(fileDescriptors[Read], F_SETFL, flags); 146 }; 147 148 if (Node* node = data.ran.load()) { 149 clearPipe(); 150 delete node; 151 return MessageStatus::MessageRan; 152 } 153 154 int ret = read(fileDescriptors[Read], buffer, 1); 155 UNUSED_PARAM(ret); 156 ASSERT(buffer[0] == magicByte[0]); 157 clearPipe(); 158 } 159 RELEASE_ASSERT_NOT_REACHED(); 160 } 161 162 #if HAVE(MACH_EXCEPTIONS) 163 static MessageStatus sendMessageUsingMach(Thread& thread, const ThreadMessage& message) 34 MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message) 164 35 { 165 36 static StaticLock messageLock; … … 179 50 } 180 51 181 static bool useMach = false;182 void deliverMessagesUsingMach()183 {184 useMach = true;185 }186 187 #endif // HAVE(MACH_EXCEPTIONS)188 189 MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)190 {191 #if HAVE(MACH_EXCEPTIONS)192 if (useMach)193 return sendMessageUsingMach(thread, message);194 #endif195 return sendMessageUsingSignal(thread, message);196 }197 198 199 52 } // namespace WTF 200 201 #endif // USE(PTHREADS) -
trunk/Source/WTF/wtf/ThreadMessage.h
r217669 r218080 30 30 #include <wtf/Threading.h> 31 31 32 #if USE(PTHREADS)33 34 32 namespace WTF { 35 33 36 void initializeThreadMessages();37 38 class ThreadMessageData;39 34 using ThreadMessage = ScopedLambda<void(PlatformRegisters&)>; 40 35 … … 56 51 } 57 52 58 #if HAVE(MACH_EXCEPTIONS)59 void deliverMessagesUsingMach();60 #endif61 62 53 } // namespace WTF 63 54 64 55 using WTF::sendMessage; 65 66 #endif // USE(PTHREADS) -
trunk/Source/WTF/wtf/Threading.cpp
r218012 r218080 180 180 initializeDates(); 181 181 Thread::initializePlatformThreading(); 182 #if USE(PTHREADS)183 initializeThreadMessages();184 #endif185 182 }); 186 183 } -
trunk/Source/WTF/wtf/Threading.h
r218069 r218080 37 37 #include <wtf/Expected.h> 38 38 #include <wtf/Function.h> 39 #include <wtf/LocklessBag.h>40 39 #include <wtf/PlatformRegisters.h> 41 40 #include <wtf/RefPtr.h> … … 129 128 static void initializePlatformThreading(); 130 129 131 #if USE(PTHREADS)132 LocklessBag<ThreadMessageData*>& threadMessages() { return m_threadMessages; }133 134 130 #if OS(DARWIN) 135 131 mach_port_t machThread() { return m_platformThread; } 136 #endif137 132 #endif 138 133 … … 183 178 pthread_t m_handle; 184 179 185 LocklessBag<ThreadMessageData*> m_threadMessages;186 180 #if OS(DARWIN) 187 181 mach_port_t m_platformThread; -
trunk/Source/WTF/wtf/ThreadingPthreads.cpp
r217431 r218080 146 146 147 147 #if HAVE(MACHINE_CONTEXT) 148 #if CPU(PPC) 149 thread->m_platformRegisters = PlatformRegisters { *userContext->uc_mcontext.uc_regs }; 150 #else 151 thread->m_platformRegisters = PlatformRegisters { userContext->uc_mcontext }; 152 #endif 148 thread->m_platformRegisters = registersFromUContext(userContext); 153 149 #else 154 150 thread->m_platformRegisters = PlatformRegisters { getApproximateStackPointer() }; … … 403 399 } 404 400 405 size_t Thread::getRegisters(PlatformRegisters& registers)406 {407 std::unique_lock<std::mutex> locker(m_mutex);408 401 #if OS(DARWIN) 402 struct ThreadStateMetadata { 403 unsigned userCount; 404 thread_state_flavor_t flavor; 405 }; 406 407 static ThreadStateMetadata threadStateMetadata() 408 { 409 409 #if CPU(X86) 410 unsigned userCount = sizeof( registers) / sizeof(int);410 unsigned userCount = sizeof(PlatformRegisters) / sizeof(int); 411 411 thread_state_flavor_t flavor = i386_THREAD_STATE; 412 412 #elif CPU(X86_64) … … 428 428 #error Unknown Architecture 429 429 #endif 430 431 kern_return_t result = thread_get_state(m_platformThread, flavor, (thread_state_t)®isters, &userCount); 430 return ThreadStateMetadata { userCount, flavor }; 431 } 432 #endif // OS(DARWIN) 433 434 size_t Thread::getRegisters(PlatformRegisters& registers) 435 { 436 std::unique_lock<std::mutex> locker(m_mutex); 437 #if OS(DARWIN) 438 auto metadata = threadStateMetadata(); 439 kern_return_t result = thread_get_state(m_platformThread, metadata.flavor, (thread_state_t)®isters, &metadata.userCount); 432 440 if (result != KERN_SUCCESS) { 433 441 WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "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); 434 442 CRASH(); 435 443 } 436 return userCount * sizeof(uintptr_t);444 return metadata.userCount * sizeof(uintptr_t); 437 445 #else 438 446 ASSERT_WITH_MESSAGE(m_suspendCount, "We can get registers only if the thread is suspended."); -
trunk/Source/WTF/wtf/threads/Signals.cpp
r217669 r218080 209 209 void handleSignalsWithMach() 210 210 { 211 deliverMessagesUsingMach();212 211 useMach = true; 213 212 }
Note:
See TracChangeset
for help on using the changeset viewer.