Changeset 215265 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Apr 12, 2017, 5:08:29 AM (8 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 21 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp
r208209 r215265 97 97 Bitmap bitmap; 98 98 const int numThreads = 5; 99 ThreadIdentifier threadIDs[numThreads];99 RefPtr<Thread> threads[numThreads]; 100 100 Data data[numThreads]; 101 101 … … 108 108 data[i].numThreads = numThreads; 109 109 std::function<void()> threadFunc = std::bind(setBitThreadFunc, &data[i]); 110 thread IDs[i] = createThread("setBitThreadFunc", threadFunc);110 threads[i] = Thread::create("setBitThreadFunc", threadFunc); 111 111 } 112 112 113 113 printf("Waiting for %d threads to join\n", numThreads); 114 114 for (int i = 0; i < numThreads; i++) 115 waitForThreadCompletion(threadIDs[i]);115 threads[i]->waitForCompletion(); 116 116 117 117 printf("PASS: CompareAndSwap test completed without a hang\n"); -
trunk/Source/JavaScriptCore/ChangeLog
r215250 r215265 1 2017-04-12 Yusuke Suzuki <[email protected]> 2 3 [WTF] Introduce Thread class and use RefPtr<Thread> and align Windows Threading implementation semantics to Pthread one 4 https://bugs.webkit.org/show_bug.cgi?id=170502 5 6 Reviewed by Mark Lam. 7 8 * API/tests/CompareAndSwapTest.cpp: 9 (testCompareAndSwap): 10 * JavaScriptCore.xcodeproj/project.pbxproj: 11 * b3/air/testair.cpp: 12 * b3/testb3.cpp: 13 (JSC::B3::run): 14 * bytecode/SuperSampler.cpp: 15 (JSC::initializeSuperSampler): 16 * dfg/DFGWorklist.cpp: 17 * disassembler/Disassembler.cpp: 18 * heap/Heap.cpp: 19 (JSC::Heap::lastChanceToFinalize): 20 (JSC::Heap::notifyIsSafeToCollect): 21 * heap/Heap.h: 22 * heap/MachineStackMarker.cpp: 23 (JSC::MachineThreads::~MachineThreads): 24 (JSC::MachineThreads::addCurrentThread): 25 (JSC::MachineThreads::removeThread): 26 (JSC::MachineThreads::removeThreadIfFound): 27 (JSC::MachineThreads::MachineThread::MachineThread): 28 (JSC::MachineThreads::MachineThread::getRegisters): 29 (JSC::MachineThreads::MachineThread::Registers::stackPointer): 30 (JSC::MachineThreads::MachineThread::Registers::framePointer): 31 (JSC::MachineThreads::MachineThread::Registers::instructionPointer): 32 (JSC::MachineThreads::MachineThread::Registers::llintPC): 33 (JSC::MachineThreads::MachineThread::captureStack): 34 (JSC::MachineThreads::tryCopyOtherThreadStack): 35 (JSC::MachineThreads::tryCopyOtherThreadStacks): 36 (pthreadSignalHandlerSuspendResume): Deleted. 37 (JSC::threadData): Deleted. 38 (JSC::MachineThreads::Thread::Thread): Deleted. 39 (JSC::MachineThreads::Thread::createForCurrentThread): Deleted. 40 (JSC::MachineThreads::Thread::operator==): Deleted. 41 (JSC::MachineThreads::machineThreadForCurrentThread): Deleted. 42 (JSC::MachineThreads::ThreadData::ThreadData): Deleted. 43 (JSC::MachineThreads::ThreadData::~ThreadData): Deleted. 44 (JSC::MachineThreads::ThreadData::suspend): Deleted. 45 (JSC::MachineThreads::ThreadData::resume): Deleted. 46 (JSC::MachineThreads::ThreadData::getRegisters): Deleted. 47 (JSC::MachineThreads::ThreadData::Registers::stackPointer): Deleted. 48 (JSC::MachineThreads::ThreadData::Registers::framePointer): Deleted. 49 (JSC::MachineThreads::ThreadData::Registers::instructionPointer): Deleted. 50 (JSC::MachineThreads::ThreadData::Registers::llintPC): Deleted. 51 (JSC::MachineThreads::ThreadData::freeRegisters): Deleted. 52 (JSC::MachineThreads::ThreadData::captureStack): Deleted. 53 * heap/MachineStackMarker.h: 54 (JSC::MachineThreads::MachineThread::suspend): 55 (JSC::MachineThreads::MachineThread::resume): 56 (JSC::MachineThreads::MachineThread::threadID): 57 (JSC::MachineThreads::MachineThread::stackBase): 58 (JSC::MachineThreads::MachineThread::stackEnd): 59 (JSC::MachineThreads::threadsListHead): 60 (JSC::MachineThreads::Thread::operator!=): Deleted. 61 (JSC::MachineThreads::Thread::suspend): Deleted. 62 (JSC::MachineThreads::Thread::resume): Deleted. 63 (JSC::MachineThreads::Thread::getRegisters): Deleted. 64 (JSC::MachineThreads::Thread::freeRegisters): Deleted. 65 (JSC::MachineThreads::Thread::captureStack): Deleted. 66 (JSC::MachineThreads::Thread::platformThread): Deleted. 67 (JSC::MachineThreads::Thread::stackBase): Deleted. 68 (JSC::MachineThreads::Thread::stackEnd): Deleted. 69 * jit/ICStats.cpp: 70 (JSC::ICStats::ICStats): 71 (JSC::ICStats::~ICStats): 72 * jit/ICStats.h: 73 * jsc.cpp: 74 (functionDollarAgentStart): 75 (startTimeoutThreadIfNeeded): 76 * runtime/JSLock.cpp: 77 (JSC::JSLock::lock): 78 * runtime/JSLock.h: 79 (JSC::JSLock::ownerThread): 80 (JSC::JSLock::currentThreadIsHoldingLock): 81 * runtime/SamplingProfiler.cpp: 82 (JSC::FrameWalker::isValidFramePointer): 83 (JSC::SamplingProfiler::SamplingProfiler): 84 (JSC::SamplingProfiler::createThreadIfNecessary): 85 (JSC::SamplingProfiler::takeSample): 86 * runtime/SamplingProfiler.h: 87 * runtime/VM.h: 88 (JSC::VM::ownerThread): 89 * runtime/VMTraps.cpp: 90 (JSC::findActiveVMAndStackBounds): 91 (JSC::VMTraps::SignalSender::send): 92 (JSC::VMTraps::fireTrap): 93 1 94 2017-04-11 Dean Jackson <[email protected]> 2 95 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r215103 r215265 2472 2472 FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */; }; 2473 2473 FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2474 FEE43FCE1E6641710077D6D1 /* PlatformThread.h in Headers */ = {isa = PBXBuildFile; fileRef = FEE43FCD1E6641400077D6D1 /* PlatformThread.h */; settings = {ATTRIBUTES = (Private, ); }; };2475 2474 FEF040511AAE662D00BD28B0 /* CompareAndSwapTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */; }; 2476 2475 FEFD6FC61D5E7992008F2F0B /* JSStringInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FEFD6FC51D5E7970008F2F0B /* JSStringInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 5102 5101 FEDA50D41B97F442009A3B4F /* PingPongStackOverflowTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PingPongStackOverflowTest.cpp; path = API/tests/PingPongStackOverflowTest.cpp; sourceTree = "<group>"; }; 5103 5102 FEDA50D51B97F4D9009A3B4F /* PingPongStackOverflowTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PingPongStackOverflowTest.h; path = API/tests/PingPongStackOverflowTest.h; sourceTree = "<group>"; }; 5104 FEE43FCD1E6641400077D6D1 /* PlatformThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformThread.h; sourceTree = "<group>"; };5105 5103 FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompareAndSwapTest.cpp; path = API/tests/CompareAndSwapTest.cpp; sourceTree = "<group>"; }; 5106 5104 FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompareAndSwapTest.h; path = API/tests/CompareAndSwapTest.h; sourceTree = "<group>"; }; … … 6867 6865 0FE228EA1436AB2300196C48 /* Options.cpp */, 6868 6866 0FE228EB1436AB2300196C48 /* Options.h */, 6869 FEE43FCD1E6641400077D6D1 /* PlatformThread.h */,6870 6867 868916A9155F285400CB2B9A /* PrivateName.h */, 6871 6868 147341DF1DC2CE9600AA29BA /* ProgramExecutable.cpp */, … … 9349 9346 705B41AC1A6E501E00716757 /* Symbol.h in Headers */, 9350 9347 705B41AE1A6E501E00716757 /* SymbolConstructor.h in Headers */, 9351 FEE43FCE1E6641710077D6D1 /* PlatformThread.h in Headers */,9352 9348 996B73271BDA08EF00331B84 /* SymbolConstructor.lut.h in Headers */, 9353 9349 705B41B01A6E501E00716757 /* SymbolObject.h in Headers */, -
trunk/Source/JavaScriptCore/b3/air/testair.cpp
r214571 r215265 1914 1914 Lock lock; 1915 1915 1916 Vector< ThreadIdentifier> threads;1916 Vector<RefPtr<Thread>> threads; 1917 1917 for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) { 1918 1918 threads.append( 1919 createThread(1919 Thread::create( 1920 1920 "testb3 thread", 1921 1921 [&] () { … … 1934 1934 } 1935 1935 1936 for ( ThreadIdentifierthread : threads)1937 waitForThreadCompletion(thread);1936 for (RefPtr<Thread> thread : threads) 1937 thread->waitForCompletion(); 1938 1938 crashLock.lock(); 1939 1939 } -
trunk/Source/JavaScriptCore/b3/testb3.cpp
r214908 r215265 16851 16851 Lock lock; 16852 16852 16853 Vector< ThreadIdentifier> threads;16853 Vector<RefPtr<Thread>> threads; 16854 16854 for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) { 16855 16855 threads.append( 16856 createThread(16856 Thread::create( 16857 16857 "testb3 thread", 16858 16858 [&] () { … … 16871 16871 } 16872 16872 16873 for ( ThreadIdentifierthread : threads)16874 waitForThreadCompletion(thread);16873 for (RefPtr<Thread> thread : threads) 16874 thread->waitForCompletion(); 16875 16875 crashLock.lock(); 16876 16876 } -
trunk/Source/JavaScriptCore/bytecode/SuperSampler.cpp
r205463 r215265 47 47 return; 48 48 49 createThread(49 Thread::create( 50 50 "JSC Super Sampler", 51 51 [] () { -
trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp
r212778 r215265 145 145 146 146 if (m_relativePriority) 147 changeThreadPriority(currentThread(),m_relativePriority);147 Thread::current().changePriority(m_relativePriority); 148 148 149 149 m_compilationScope = std::make_unique<CompilationScope>(); -
trunk/Source/JavaScriptCore/disassembler/Disassembler.cpp
r196729 r215265 74 74 AsynchronousDisassembler() 75 75 { 76 createThread("Asynchronous Disassembler", [&] () { run(); });76 Thread::create("Asynchronous Disassembler", [&] () { run(); }); 77 77 } 78 78 -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r214857 r215265 350 350 m_collectContinuouslyCondition.notifyOne(); 351 351 } 352 waitForThreadCompletion(m_collectContinuouslyThread);352 m_collectContinuouslyThread->waitForCompletion(); 353 353 } 354 354 … … 2682 2682 2683 2683 if (Options::collectContinuously()) { 2684 m_collectContinuouslyThread = createThread(2684 m_collectContinuouslyThread = WTF::Thread::create( 2685 2685 "JSC DEBUG Continuous GC", 2686 2686 [this] () { -
trunk/Source/JavaScriptCore/heap/Heap.h
r213883 r215265 50 50 #include <wtf/HashSet.h> 51 51 #include <wtf/ParallelHelperPool.h> 52 #include <wtf/Threading.h> 52 53 53 54 namespace JSC { … … 667 668 Condition m_collectContinuouslyCondition; 668 669 bool m_shouldStopCollectingContinuously { false }; 669 ThreadIdentifier m_collectContinuouslyThread { 0};670 RefPtr<WTF::Thread> m_collectContinuouslyThread { nullptr }; 670 671 671 672 MonotonicTime m_lastGCStartTime; -
trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp
r214319 r215265 37 37 #include <wtf/StdLibExtras.h> 38 38 39 #if OS(DARWIN)40 41 #include <mach/mach_init.h>42 #include <mach/mach_port.h>43 #include <mach/task.h>44 #include <mach/thread_act.h>45 #include <mach/vm_map.h>46 47 #elif OS(WINDOWS)48 49 #include <windows.h>50 #include <malloc.h>51 52 #elif OS(UNIX)53 54 #include <sys/mman.h>55 #include <unistd.h>56 57 #if OS(SOLARIS)58 #include <thread.h>59 #else60 #include <pthread.h>61 #endif62 63 #if HAVE(PTHREAD_NP_H)64 #include <pthread_np.h>65 #endif66 67 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)68 #include <signal.h>69 70 // We use SIGUSR2 to suspend and resume machine threads in JavaScriptCore.71 static const int SigThreadSuspendResume = SIGUSR2;72 static StaticLock globalSignalLock;73 thread_local static std::atomic<JSC::MachineThreads::ThreadData*> threadLocalCurrentThread { nullptr };74 75 static void pthreadSignalHandlerSuspendResume(int, siginfo_t*, void* ucontext)76 {77 // Touching thread local atomic types from signal handlers is allowed.78 JSC::MachineThreads::ThreadData* threadData = threadLocalCurrentThread.load();79 80 if (threadData->suspended.load(std::memory_order_acquire)) {81 // This is signal handler invocation that is intended to be used to resume sigsuspend.82 // So this handler invocation itself should not process.83 //84 // When signal comes, first, the system calls signal handler. And later, sigsuspend will be resumed. Signal handler invocation always precedes.85 // So, the problem never happens that suspended.store(true, ...) will be executed before the handler is called.86 // http://pubs.opengroup.org/onlinepubs/009695399/functions/sigsuspend.html87 return;88 }89 90 ucontext_t* userContext = static_cast<ucontext_t*>(ucontext);91 #if CPU(PPC)92 threadData->suspendedMachineContext = *userContext->uc_mcontext.uc_regs;93 #else94 threadData->suspendedMachineContext = userContext->uc_mcontext;95 #endif96 97 // Allow suspend caller to see that this thread is suspended.98 // sem_post is async-signal-safe function. It means that we can call this from a signal handler.99 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03100 //101 // And sem_post emits memory barrier that ensures that suspendedMachineContext is correctly saved.102 // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11103 sem_post(&threadData->semaphoreForSuspendResume);104 105 // Reaching here, SigThreadSuspendResume is blocked in this handler (this is configured by sigaction's sa_mask).106 // So before calling sigsuspend, SigThreadSuspendResume to this thread is deferred. This ensures that the handler is not executed recursively.107 sigset_t blockedSignalSet;108 sigfillset(&blockedSignalSet);109 sigdelset(&blockedSignalSet, SigThreadSuspendResume);110 sigsuspend(&blockedSignalSet);111 112 // Allow resume caller to see that this thread is resumed.113 sem_post(&threadData->semaphoreForSuspendResume);114 }115 #endif // USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)116 117 #endif118 119 39 using namespace WTF; 120 40 121 41 namespace JSC { 122 123 using Thread = MachineThreads::Thread;124 42 125 43 class ActiveMachineThreadsManager; … … 195 113 196 114 LockHolder registeredThreadsLock(m_registeredThreadsMutex); 197 for ( Thread* t = m_registeredThreads; t;) {198 Thread* next = t->next;115 for (MachineThread* t = m_registeredThreads; t;) { 116 MachineThread* next = t->next; 199 117 delete t; 200 118 t = next; 201 119 } 202 }203 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 216 Thread* MachineThreads::Thread::createForCurrentThread()217 {218 return new Thread(threadData());219 }220 221 bool MachineThreads::Thread::operator==(const PlatformThread& other) const222 {223 #if OS(DARWIN) || OS(WINDOWS)224 return data->platformThread == other;225 #elif USE(PTHREADS)226 return !!pthread_equal(data->platformThread, other);227 #else228 #error Need a way to compare threads on this platform229 #endif230 120 } 231 121 … … 240 130 } 241 131 242 Thread* thread = Thread::createForCurrentThread();132 MachineThread* thread = new MachineThread(); 243 133 threadSpecificSet(m_threadSpecificForMachineThreads, this); 244 134 … … 249 139 } 250 140 251 Thread* MachineThreads::machineThreadForCurrentThread() 141 auto MachineThreads::machineThreadForCurrentThread() -> MachineThread* 252 142 { 253 143 LockHolder lock(m_registeredThreadsMutex); 254 PlatformThread platformThread = currentPlatformThread();255 for ( Thread* thread = m_registeredThreads; thread; thread = thread->next) {256 if ( *thread == platformThread)144 ThreadIdentifier id = currentThread(); 145 for (MachineThread* thread = m_registeredThreads; thread; thread = thread->next) { 146 if (thread->threadID() == id) 257 147 return thread; 258 148 } … … 284 174 #endif 285 175 286 machineThreads->removeThreadIfFound(currentPlatformThread()); 287 } 288 } 289 290 template<typename PlatformThread> 291 void MachineThreads::removeThreadIfFound(PlatformThread platformThread) 176 machineThreads->removeThreadIfFound(currentThread()); 177 } 178 } 179 180 void MachineThreads::removeThreadIfFound(ThreadIdentifier id) 292 181 { 293 182 LockHolder lock(m_registeredThreadsMutex); 294 Thread* t = m_registeredThreads;295 if ( *t == platformThread) {183 MachineThread* t = m_registeredThreads; 184 if (t->threadID() == id) { 296 185 m_registeredThreads = m_registeredThreads->next; 297 186 delete t; 298 187 } else { 299 Thread* last = m_registeredThreads;188 MachineThread* last = m_registeredThreads; 300 189 for (t = m_registeredThreads->next; t; t = t->next) { 301 if ( *t == platformThread) {190 if (t->threadID() == id) { 302 191 last->next = t->next; 303 192 break; … … 321 210 } 322 211 323 MachineThreads::ThreadData::ThreadData() 212 MachineThreads::MachineThread::MachineThread() 213 : next(nullptr) 214 , m_thread(WTF::Thread::current()) 324 215 { 325 216 auto stackBounds = wtfThreadData().stack(); 326 platformThread = currentPlatformThread(); 327 stackBase = stackBounds.origin(); 328 stackEnd = stackBounds.end(); 329 330 #if OS(WINDOWS) 331 ASSERT(platformThread == GetCurrentThreadId()); 332 bool isSuccessful = 333 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), 334 &platformThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); 335 RELEASE_ASSERT(isSuccessful); 336 #elif USE(PTHREADS) && !OS(DARWIN) 337 threadLocalCurrentThread.store(this); 338 339 // Signal handlers are process global configuration. 340 static std::once_flag initializeSignalHandler; 341 std::call_once(initializeSignalHandler, [] { 342 // Intentionally block SigThreadSuspendResume in the handler. 343 // SigThreadSuspendResume will be allowed in the handler by sigsuspend. 344 struct sigaction action; 345 sigemptyset(&action.sa_mask); 346 sigaddset(&action.sa_mask, SigThreadSuspendResume); 347 348 action.sa_sigaction = pthreadSignalHandlerSuspendResume; 349 action.sa_flags = SA_RESTART | SA_SIGINFO; 350 sigaction(SigThreadSuspendResume, &action, 0); 351 }); 352 353 sigset_t mask; 354 sigemptyset(&mask); 355 sigaddset(&mask, SigThreadSuspendResume); 356 pthread_sigmask(SIG_UNBLOCK, &mask, 0); 357 358 sem_init(&semaphoreForSuspendResume, /* Only available in this process. */ 0, /* Initial value for the semaphore. */ 0); 359 #endif 360 } 361 362 MachineThreads::ThreadData::~ThreadData() 363 { 364 #if OS(WINDOWS) 365 CloseHandle(platformThreadHandle); 366 #elif USE(PTHREADS) && !OS(DARWIN) 367 sem_destroy(&semaphoreForSuspendResume); 368 #endif 369 } 370 371 bool MachineThreads::ThreadData::suspend() 372 { 373 #if OS(DARWIN) 374 kern_return_t result = thread_suspend(platformThread); 375 return result == KERN_SUCCESS; 376 #elif OS(WINDOWS) 377 bool threadIsSuspended = (SuspendThread(platformThreadHandle) != (DWORD)-1); 378 ASSERT(threadIsSuspended); 379 return threadIsSuspended; 380 #elif USE(PTHREADS) 381 ASSERT_WITH_MESSAGE(currentPlatformThread() != platformThread, "Currently we don't support suspend the current thread itself."); 382 { 383 // During suspend, suspend or resume should not be executed from the other threads. 384 // We use global lock instead of per thread lock. 385 // Consider the following case, there are threads A and B. 386 // And A attempt to suspend B and B attempt to suspend A. 387 // A and B send signals. And later, signals are delivered to A and B. 388 // In that case, both will be suspended. 389 LockHolder lock(globalSignalLock); 390 if (!suspendCount) { 391 // Ideally, we would like to use pthread_sigqueue. It allows us to pass the argument to the signal handler. 392 // But it can be used in a few platforms, like Linux. 393 // Instead, we use Thread* stored in the thread local storage to pass it to the signal handler. 394 if (pthread_kill(platformThread, SigThreadSuspendResume) == ESRCH) 395 return false; 396 sem_wait(&semaphoreForSuspendResume); 397 // Release barrier ensures that this operation is always executed after all the above processing is done. 398 suspended.store(true, std::memory_order_release); 399 } 400 ++suspendCount; 401 } 402 return true; 403 #else 404 #error Need a way to suspend threads on this platform 405 #endif 406 } 407 408 void MachineThreads::ThreadData::resume() 409 { 410 #if OS(DARWIN) 411 thread_resume(platformThread); 412 #elif OS(WINDOWS) 413 ResumeThread(platformThreadHandle); 414 #elif USE(PTHREADS) 415 { 416 // During resume, suspend or resume should not be executed from the other threads. 417 LockHolder lock(globalSignalLock); 418 if (suspendCount == 1) { 419 // When allowing SigThreadSuspendResume interrupt in the signal handler by sigsuspend and SigThreadSuspendResume is actually issued, 420 // the signal handler itself will be called once again. 421 // There are several ways to distinguish the handler invocation for suspend and resume. 422 // 1. Use different signal numbers. And check the signal number in the handler. 423 // 2. Use some arguments to distinguish suspend and resume in the handler. If pthread_sigqueue can be used, we can take this. 424 // 3. Use thread local storage with atomic variables in the signal handler. 425 // In this implementaiton, we take (3). suspended flag is used to distinguish it. 426 if (pthread_kill(platformThread, SigThreadSuspendResume) == ESRCH) 427 return; 428 sem_wait(&semaphoreForSuspendResume); 429 // Release barrier ensures that this operation is always executed after all the above processing is done. 430 suspended.store(false, std::memory_order_release); 431 } 432 --suspendCount; 433 } 434 #else 435 #error Need a way to resume threads on this platform 436 #endif 437 } 438 439 size_t MachineThreads::ThreadData::getRegisters(ThreadData::Registers& registers) 440 { 441 ThreadData::Registers::PlatformRegisters& regs = registers.regs; 442 #if OS(DARWIN) 443 #if CPU(X86) 444 unsigned user_count = sizeof(regs)/sizeof(int); 445 thread_state_flavor_t flavor = i386_THREAD_STATE; 446 #elif CPU(X86_64) 447 unsigned user_count = x86_THREAD_STATE64_COUNT; 448 thread_state_flavor_t flavor = x86_THREAD_STATE64; 449 #elif CPU(PPC) 450 unsigned user_count = PPC_THREAD_STATE_COUNT; 451 thread_state_flavor_t flavor = PPC_THREAD_STATE; 452 #elif CPU(PPC64) 453 unsigned user_count = PPC_THREAD_STATE64_COUNT; 454 thread_state_flavor_t flavor = PPC_THREAD_STATE64; 455 #elif CPU(ARM) 456 unsigned user_count = ARM_THREAD_STATE_COUNT; 457 thread_state_flavor_t flavor = ARM_THREAD_STATE; 458 #elif CPU(ARM64) 459 unsigned user_count = ARM_THREAD_STATE64_COUNT; 460 thread_state_flavor_t flavor = ARM_THREAD_STATE64; 461 #else 462 #error Unknown Architecture 463 #endif 464 465 kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count); 466 if (result != KERN_SUCCESS) { 467 WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 468 "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); 469 CRASH(); 470 } 471 return user_count * sizeof(uintptr_t); 472 // end OS(DARWIN) 473 474 #elif OS(WINDOWS) 475 regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; 476 GetThreadContext(platformThreadHandle, ®s); 477 return sizeof(CONTEXT); 478 #elif ((OS(FREEBSD) || defined(__GLIBC__)) && ENABLE(JIT)) 479 regs = suspendedMachineContext; 480 return sizeof(Registers::PlatformRegisters); 481 #elif USE(PTHREADS) 482 pthread_attr_init(®s.attribute); 483 #if HAVE(PTHREAD_NP_H) || OS(NETBSD) 484 #if !OS(OPENBSD) 485 // e.g. on FreeBSD 5.4, [email protected] 486 pthread_attr_get_np(platformThread, ®s.attribute); 487 #endif 488 #else 489 // FIXME: this function is non-portable; other POSIX systems may have different np alternatives 490 pthread_getattr_np(platformThread, ®s.attribute); 491 #endif 492 return 0; 493 #else 494 #error Need a way to get thread registers on this platform 495 #endif 496 } 497 498 void* MachineThreads::ThreadData::Registers::stackPointer() const 217 m_stackBase = stackBounds.origin(); 218 m_stackEnd = stackBounds.end(); 219 } 220 221 size_t MachineThreads::MachineThread::getRegisters(MachineThread::Registers& registers) 222 { 223 WTF::PlatformRegisters& regs = registers.regs; 224 return m_thread->getRegisters(regs); 225 } 226 227 void* MachineThreads::MachineThread::Registers::stackPointer() const 499 228 { 500 229 #if OS(DARWIN) || OS(WINDOWS) || ((OS(FREEBSD) || defined(__GLIBC__)) && ENABLE(JIT)) 501 230 return MachineContext::stackPointer(regs); 502 231 #elif USE(PTHREADS) 503 void* stackBase = 0; 504 size_t stackSize = 0; 505 #if OS(OPENBSD) 506 stack_t ss; 507 int rc = pthread_stackseg_np(pthread_self(), &ss); 508 stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size); 509 stackSize = ss.ss_size; 510 #else 511 int rc = pthread_attr_getstack(®s.attribute, &stackBase, &stackSize); 512 #endif 513 (void)rc; // FIXME: Deal with error code somehow? Seems fatal. 514 ASSERT(stackBase); 515 return static_cast<char*>(stackBase) + stackSize; 232 return regs.stackPointer; 516 233 #else 517 234 #error Need a way to get the stack pointer for another thread on this platform … … 520 237 521 238 #if ENABLE(SAMPLING_PROFILER) 522 void* MachineThreads:: ThreadData::Registers::framePointer() const239 void* MachineThreads::MachineThread::Registers::framePointer() const 523 240 { 524 241 #if OS(DARWIN) || OS(WINDOWS) || (OS(FREEBSD) || defined(__GLIBC__)) … … 529 246 } 530 247 531 void* MachineThreads:: ThreadData::Registers::instructionPointer() const248 void* MachineThreads::MachineThread::Registers::instructionPointer() const 532 249 { 533 250 #if OS(DARWIN) || OS(WINDOWS) || (OS(FREEBSD) || defined(__GLIBC__)) … … 538 255 } 539 256 540 void* MachineThreads:: ThreadData::Registers::llintPC() const257 void* MachineThreads::MachineThread::Registers::llintPC() const 541 258 { 542 259 // LLInt uses regT4 as PC. … … 548 265 } 549 266 #endif // ENABLE(SAMPLING_PROFILER) 550 551 void MachineThreads::ThreadData::freeRegisters(ThreadData::Registers& registers)552 {553 ThreadData::Registers::PlatformRegisters& regs = registers.regs;554 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) && !((OS(FREEBSD) || defined(__GLIBC__)) && ENABLE(JIT))555 pthread_attr_destroy(®s.attribute);556 #else557 UNUSED_PARAM(regs);558 #endif559 }560 267 561 268 static inline int osRedZoneAdjustment() … … 574 281 } 575 282 576 std::pair<void*, size_t> MachineThreads:: ThreadData::captureStack(void* stackTop)577 { 578 char* begin = reinterpret_cast_ptr<char*>( stackBase);283 std::pair<void*, size_t> MachineThreads::MachineThread::captureStack(void* stackTop) 284 { 285 char* begin = reinterpret_cast_ptr<char*>(m_stackBase); 579 286 char* end = bitwise_cast<char*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop))); 580 287 ASSERT(begin >= end); … … 583 290 ASSERT(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(endWithRedZone)) == reinterpret_cast<uintptr_t>(endWithRedZone)); 584 291 585 if (endWithRedZone < stackEnd)586 endWithRedZone = reinterpret_cast_ptr<char*>( stackEnd);292 if (endWithRedZone < m_stackEnd) 293 endWithRedZone = reinterpret_cast_ptr<char*>(m_stackEnd); 587 294 588 295 std::swap(begin, endWithRedZone); … … 617 324 // operation. As the heap is generally much larger than the stack the performance hit is minimal. 618 325 // See: https://bugs.webkit.org/show_bug.cgi?id=146297 619 void MachineThreads::tryCopyOtherThreadStack( Thread* thread, void* buffer, size_t capacity, size_t* size)620 { 621 Thread::Registers registers;326 void MachineThreads::tryCopyOtherThreadStack(MachineThread* thread, void* buffer, size_t capacity, size_t* size) 327 { 328 MachineThread::Registers registers; 622 329 size_t registersSize = thread->getRegisters(registers); 623 330 std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer()); … … 632 339 copyMemory(static_cast<char*>(buffer) + *size, stack.first, stack.second); 633 340 *size += stack.second; 634 635 thread->freeRegisters(registers);636 341 } 637 342 … … 645 350 *size = 0; 646 351 647 PlatformThread platformThread = currentPlatformThread();352 ThreadIdentifier id = currentThread(); 648 353 int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet. 649 354 int index = 1; 650 Thread* threadsToBeDeleted = nullptr;651 652 Thread* previousThread = nullptr;653 for ( Thread* thread = m_registeredThreads; thread; index++) {654 if ( *thread != platformThread) {655 bool success= thread->suspend();355 MachineThread* threadsToBeDeleted = nullptr; 356 357 MachineThread* previousThread = nullptr; 358 for (MachineThread* thread = m_registeredThreads; thread; index++) { 359 if (thread->threadID() != id) { 360 auto result = thread->suspend(); 656 361 #if OS(DARWIN) 657 if (! success) {362 if (!result) { 658 363 if (!numberOfThreads) { 659 for ( Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next)364 for (MachineThread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next) 660 365 numberOfThreads++; 661 366 } 662 663 // Re-do the suspension to get the actual failure result for logging. 664 kern_return_t error = thread_suspend(thread->platformThread()); 665 ASSERT(error != KERN_SUCCESS); 367 368 ASSERT(result.error() != KERN_SUCCESS); 666 369 667 370 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 668 "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",669 error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread()));371 "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] id %u.", 372 result.error(), index, numberOfThreads, thread, thread->threadID()); 670 373 671 374 // Put the invalid thread on the threadsToBeDeleted list. … … 674 377 // we need for deleting the invalid thread. Hence, we need to 675 378 // defer the deletion till after we have resumed all threads. 676 Thread* nextThread = thread->next;379 MachineThread* nextThread = thread->next; 677 380 thread->next = threadsToBeDeleted; 678 381 threadsToBeDeleted = thread; … … 688 391 UNUSED_PARAM(numberOfThreads); 689 392 UNUSED_PARAM(previousThread); 690 ASSERT_UNUSED( success, success);393 ASSERT_UNUSED(result, result); 691 394 #endif 692 395 } … … 695 398 } 696 399 697 for ( Thread* thread = m_registeredThreads; thread; thread = thread->next) {698 if ( *thread != platformThread)400 for (MachineThread* thread = m_registeredThreads; thread; thread = thread->next) { 401 if (thread->threadID() != id) 699 402 tryCopyOtherThreadStack(thread, buffer, capacity, size); 700 403 } 701 404 702 for ( Thread* thread = m_registeredThreads; thread; thread = thread->next) {703 if ( *thread != platformThread)405 for (MachineThread* thread = m_registeredThreads; thread; thread = thread->next) { 406 if (thread->threadID() != id) 704 407 thread->resume(); 705 408 } 706 409 707 for ( Thread* thread = threadsToBeDeleted; thread; ) {708 Thread* nextThread = thread->next;410 for (MachineThread* thread = threadsToBeDeleted; thread; ) { 411 MachineThread* nextThread = thread->next; 709 412 delete thread; 710 413 thread = nextThread; -
trunk/Source/JavaScriptCore/heap/MachineStackMarker.h
r214319 r215265 23 23 24 24 #include "MachineContext.h" 25 #include "PlatformThread.h"26 25 #include "RegisterState.h" 27 26 #include <wtf/Lock.h> … … 29 28 #include <wtf/ScopedLambda.h> 30 29 #include <wtf/ThreadSpecific.h> 31 32 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)33 #include <semaphore.h>34 #include <signal.h>35 // Using signal.h didn't make mcontext_t and ucontext_t available on FreeBSD.36 // This bug has been fixed in FreeBSD 11.0-CURRENT, so this workaround can be37 // removed after FreeBSD 10.x goes EOL.38 // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=20707939 #if OS(FREEBSD)40 #include <ucontext.h>41 #endif42 #endif43 30 44 31 namespace JSC { … … 65 52 JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads. 66 53 67 class ThreadData{54 class MachineThread { 68 55 WTF_MAKE_FAST_ALLOCATED; 69 56 public: 70 ThreadData(); 71 ~ThreadData(); 72 73 static ThreadData* createForCurrentThread(); 57 MachineThread(); 74 58 75 59 struct Registers { … … 80 64 void* llintPC() const; 81 65 #endif // ENABLE(SAMPLING_PROFILER) 82 83 #if OS(DARWIN) || OS(WINDOWS) 84 using PlatformRegisters = MachineContext::PlatformRegisters; 85 #elif (OS(FREEBSD) || defined(__GLIBC__)) && ENABLE(JIT) 86 using PlatformRegisters = mcontext_t; 87 #elif USE(PTHREADS) 88 struct PlatformRegisters { 89 pthread_attr_t attribute; 90 }; 91 #else 92 #error Need a thread register struct for this platform 93 #endif 94 95 PlatformRegisters regs; 66 WTF::PlatformRegisters regs; 96 67 }; 97 68 98 bool suspend(); 99 void resume(); 100 size_t getRegisters(Registers&); 101 void freeRegisters(Registers&); 69 Expected<void, Thread::PlatformSuspendError> suspend() { return m_thread->suspend(); } 70 void resume() { m_thread->resume(); } 71 size_t getRegisters(Registers& regs); 102 72 std::pair<void*, size_t> captureStack(void* stackTop); 103 73 104 PlatformThread platformThread; 105 void* stackBase; 106 void* stackEnd; 107 #if OS(WINDOWS) 108 HANDLE platformThreadHandle; 109 #elif USE(PTHREADS) && !OS(DARWIN) 110 sem_t semaphoreForSuspendResume; 111 mcontext_t suspendedMachineContext; 112 int suspendCount { 0 }; 113 std::atomic<bool> suspended { false }; 114 #endif 115 }; 74 WTF::ThreadIdentifier threadID() const { return m_thread->id(); } 75 void* stackBase() const { return m_stackBase; } 76 void* stackEnd() const { return m_stackEnd; } 116 77 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; 78 MachineThread* next; 79 Ref<WTF::Thread> m_thread; 80 void* m_stackBase; 81 void* m_stackEnd; 141 82 }; 142 83 143 84 Lock& getLock() { return m_registeredThreadsMutex; } 144 Thread* threadsListHead(const AbstractLocker&) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }145 Thread* machineThreadForCurrentThread();85 MachineThread* threadsListHead(const AbstractLocker&) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; } 86 MachineThread* machineThreadForCurrentThread(); 146 87 147 88 private: 148 89 void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, CurrentThreadState&); 149 90 150 void tryCopyOtherThreadStack( Thread*, void*, size_t capacity, size_t*);91 void tryCopyOtherThreadStack(MachineThread*, void*, size_t capacity, size_t*); 151 92 bool tryCopyOtherThreadStacks(const AbstractLocker&, void*, size_t capacity, size_t*); 152 93 153 94 static void THREAD_SPECIFIC_CALL removeThread(void*); 154 95 155 template<typename PlatformThread> 156 void removeThreadIfFound(PlatformThread); 96 void removeThreadIfFound(ThreadIdentifier); 157 97 158 98 Lock m_registeredThreadsMutex; 159 Thread* m_registeredThreads;99 MachineThread* m_registeredThreads; 160 100 WTF::ThreadSpecificKey m_threadSpecificForMachineThreads; 161 101 }; -
trunk/Source/JavaScriptCore/jit/ICStats.cpp
r208415 r215265 59 59 ICStats::ICStats() 60 60 { 61 m_thread = createThread(61 m_thread = Thread::create( 62 62 "JSC ICStats", 63 63 [this] () { … … 85 85 } 86 86 87 waitForThreadCompletion(m_thread);87 m_thread->waitForCompletion(); 88 88 } 89 89 -
trunk/Source/JavaScriptCore/jit/ICStats.h
r213467 r215265 180 180 181 181 Spectrum<ICEvent, uint64_t> m_spectrum; 182 ThreadIdentifierm_thread;182 RefPtr<Thread> m_thread; 183 183 Lock m_lock; 184 184 Condition m_condition; -
trunk/Source/JavaScriptCore/jsc.cpp
r215103 r215265 2545 2545 bool didStart = false; 2546 2546 2547 ThreadIdentifier thread = createThread(2547 RefPtr<Thread> thread = Thread::create( 2548 2548 "JSC Agent", 2549 2549 [sourceCode, &didStartLock, &didStartCondition, &didStart] () { … … 2572 2572 }); 2573 2573 }); 2574 detachThread(thread);2574 thread->detach(); 2575 2575 2576 2576 { … … 3312 3312 " but expected a number. Not using a timeout.\n"); 3313 3313 } else 3314 createThread(timeoutThreadMain, 0, "jsc Timeout Thread");3314 Thread::create(timeoutThreadMain, 0, "jsc Timeout Thread"); 3315 3315 } 3316 3316 } -
trunk/Source/JavaScriptCore/runtime/JSLock.cpp
r214489 r215265 110 110 } 111 111 112 m_ownerThread = currentThread();112 m_ownerThread = &Thread::current(); 113 113 WTF::storeStoreFence(); 114 114 m_hasOwnerThread = true; -
trunk/Source/JavaScriptCore/runtime/JSLock.h
r214489 r215265 93 93 VM* vm() { return m_vm; } 94 94 95 std::optional< ThreadIdentifier> ownerThread() const95 std::optional<RefPtr<Thread>> ownerThread() const 96 96 { 97 97 if (m_hasOwnerThread) … … 99 99 return std::nullopt; 100 100 } 101 bool currentThreadIsHoldingLock() { return m_hasOwnerThread && m_ownerThread == currentThread(); }101 bool currentThreadIsHoldingLock() { return m_hasOwnerThread && m_ownerThread->id() == currentThread(); } 102 102 103 103 void willDestroyVM(VM*); … … 136 136 // See https://bugs.webkit.org/show_bug.cgi?id=169042#c6 137 137 bool m_hasOwnerThread { false }; 138 ThreadIdentifierm_ownerThread;138 RefPtr<Thread> m_ownerThread; 139 139 intptr_t m_lockCount; 140 140 unsigned m_lockDropDepth; -
trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp
r214905 r215265 168 168 { 169 169 uint8_t* fpCast = bitwise_cast<uint8_t*>(exec); 170 for (MachineThreads:: Thread* thread = m_vm.heap.machineThreads().threadsListHead(m_machineThreadsLocker); thread; thread = thread->next) {170 for (MachineThreads::MachineThread* thread = m_vm.heap.machineThreads().threadsListHead(m_machineThreadsLocker); thread; thread = thread->next) { 171 171 uint8_t* stackBase = static_cast<uint8_t*>(thread->stackBase()); 172 172 uint8_t* stackLimit = static_cast<uint8_t*>(thread->stackEnd()); … … 280 280 , m_stopwatch(WTFMove(stopwatch)) 281 281 , m_timingInterval(std::chrono::microseconds(Options::sampleInterval())) 282 , m_threadIdentifier(0)283 282 , m_jscExecutionThread(nullptr) 284 283 , m_isPaused(false) … … 301 300 ASSERT(m_lock.isLocked()); 302 301 303 if (m_thread Identifier)302 if (m_thread) 304 303 return; 305 304 306 305 RefPtr<SamplingProfiler> profiler = this; 307 m_thread Identifier = createThread("jsc.sampling-profiler.thread", [profiler] {306 m_thread = Thread::create("jsc.sampling-profiler.thread", [profiler] { 308 307 profiler->timerLoop(); 309 308 }); … … 345 344 LockHolder executableAllocatorLocker(ExecutableAllocator::singleton().getLock()); 346 345 347 booldidSuspend = m_jscExecutionThread->suspend();346 auto didSuspend = m_jscExecutionThread->suspend(); 348 347 if (didSuspend) { 349 348 // While the JSC thread is suspended, we can't do things like malloc because the JSC thread … … 355 354 void* llintPC; 356 355 { 357 MachineThreads:: Thread::Registers registers;356 MachineThreads::MachineThread::Registers registers; 358 357 m_jscExecutionThread->getRegisters(registers); 359 358 machineFrame = registers.framePointer(); … … 361 360 machinePC = registers.instructionPointer(); 362 361 llintPC = registers.llintPC(); 363 m_jscExecutionThread->freeRegisters(registers);364 362 } 365 363 // FIXME: Lets have a way of detecting when we're parsing code. -
trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h
r214905 r215265 196 196 double m_lastTime; 197 197 Lock m_lock; 198 ThreadIdentifier m_threadIdentifier;199 MachineThreads:: Thread* m_jscExecutionThread;198 RefPtr<Thread> m_thread; 199 MachineThreads::MachineThread* m_jscExecutionThread; 200 200 bool m_isPaused; 201 201 bool m_isShutDown; -
trunk/Source/JavaScriptCore/runtime/VM.h
r214905 r215265 660 660 void logEvent(CodeBlock*, const char* summary, const Func& func); 661 661 662 std::optional< ThreadIdentifier> ownerThread() const { return m_apiLock->ownerThread(); }662 std::optional<RefPtr<Thread>> ownerThread() const { return m_apiLock->ownerThread(); } 663 663 664 664 VMTraps& traps() { return m_traps; } -
trunk/Source/JavaScriptCore/runtime/VMTraps.cpp
r214571 r215265 111 111 } 112 112 113 for (MachineThreads:: Thread* thread = machineThreads.threadsListHead(machineThreadsLocker); thread; thread = thread->next) {113 for (MachineThreads::MachineThread* thread = machineThreads.threadsListHead(machineThreadsLocker); thread; thread = thread->next) { 114 114 RELEASE_ASSERT(thread->stackBase()); 115 115 RELEASE_ASSERT(thread->stackEnd()); … … 456 456 auto optionalOwnerThread = vm.ownerThread(); 457 457 if (optionalOwnerThread) { 458 signalThread(optionalOwnerThread.value(),SIGUSR1);458 optionalOwnerThread.value()->signal(SIGUSR1); 459 459 break; 460 460 } … … 494 494 RefPtr<SignalSender> sender = adoptRef(new SignalSender(vm(), eventType)); 495 495 addSignalSender(sender.get()); 496 createThread("jsc.vmtraps.signalling.thread", [sender] {496 Thread::create("jsc.vmtraps.signalling.thread", [sender] { 497 497 sender->send(); 498 498 });
Note:
See TracChangeset
for help on using the changeset viewer.