1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2015 Apple Inc. 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#ifndef MachineThreads_h
23#define MachineThreads_h
24
25#include <setjmp.h>
26#include <wtf/Lock.h>
27#include <wtf/Noncopyable.h>
28#include <wtf/ThreadSpecific.h>
29
30#if OS(DARWIN)
31#include <mach/thread_act.h>
32#endif
33
34#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
35#include <semaphore.h>
36#include <signal.h>
37// Using signal.h didn't make mcontext_t and ucontext_t available on FreeBSD.
38// This bug has been fixed in FreeBSD 11.0-CURRENT, so this workaround can be
39// removed after FreeBSD 10.x goes EOL.
40// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=207079
41#if OS(FREEBSD)
42#include <ucontext.h>
43#endif
44#endif
45
46#if OS(DARWIN)
47typedef mach_port_t PlatformThread;
48#elif OS(WINDOWS)
49typedef DWORD PlatformThread;
50#elif USE(PTHREADS)
51typedef pthread_t PlatformThread;
52#endif // OS(DARWIN)
53
54namespace JSC {
55
56class CodeBlockSet;
57class ConservativeRoots;
58class Heap;
59class JITStubRoutineSet;
60
61class MachineThreads {
62 WTF_MAKE_NONCOPYABLE(MachineThreads);
63public:
64 typedef jmp_buf RegisterState;
65
66 MachineThreads(Heap*);
67 ~MachineThreads();
68
69 void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters);
70
71 JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
72
73 class Thread {
74 WTF_MAKE_FAST_ALLOCATED;
75 Thread(const PlatformThread& platThread, void* base, void* end);
76
77 public:
78 ~Thread();
79
80 static Thread* createForCurrentThread();
81
82 struct Registers {
83 void* stackPointer() const;
84#if ENABLE(SAMPLING_PROFILER)
85 void* framePointer() const;
86 void* instructionPointer() const;
87 void* llintPC() const;
88#endif // ENABLE(SAMPLING_PROFILER)
89
90#if OS(DARWIN)
91#if CPU(X86)
92 typedef i386_thread_state_t PlatformRegisters;
93#elif CPU(X86_64)
94 typedef x86_thread_state64_t PlatformRegisters;
95#elif CPU(PPC)
96 typedef ppc_thread_state_t PlatformRegisters;
97#elif CPU(PPC64)
98 typedef ppc_thread_state64_t PlatformRegisters;
99#elif CPU(ARM)
100 typedef arm_thread_state_t PlatformRegisters;
101#elif CPU(ARM64)
102 typedef arm_thread_state64_t PlatformRegisters;
103#else
104#error Unknown Architecture
105#endif
106
107#elif OS(WINDOWS)
108 typedef CONTEXT PlatformRegisters;
109#elif USE(PTHREADS)
110 struct PlatformRegisters {
111 pthread_attr_t attribute;
112 mcontext_t machineContext;
113 };
114#else
115#error Need a thread register struct for this platform
116#endif
117
118 PlatformRegisters regs;
119 };
120
121 bool operator==(const PlatformThread& other) const;
122 bool operator!=(const PlatformThread& other) const { return !(*this == other); }
123
124 bool suspend();
125 void resume();
126 size_t getRegisters(Registers&);
127 void freeRegisters(Registers&);
128 std::pair<void*, size_t> captureStack(void* stackTop);
129
130 Thread* next;
131 PlatformThread platformThread;
132 void* stackBase;
133 void* stackEnd;
134#if OS(WINDOWS)
135 HANDLE platformThreadHandle;
136#elif USE(PTHREADS) && !OS(DARWIN)
137 sem_t semaphoreForSuspendResume;
138 mcontext_t suspendedMachineContext;
139 int suspendCount { 0 };
140 std::atomic<bool> suspended { false };
141#endif
142 };
143
144 Lock& getLock() { return m_registeredThreadsMutex; }
145 Thread* threadsListHead(const LockHolder&) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }
146 Thread* machineThreadForCurrentThread();
147
148private:
149 void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters);
150
151 void tryCopyOtherThreadStack(Thread*, void*, size_t capacity, size_t*);
152 bool tryCopyOtherThreadStacks(LockHolder&, void*, size_t capacity, size_t*);
153
154 static void removeThread(void*);
155
156 template<typename PlatformThread>
157 void removeThreadIfFound(PlatformThread);
158
159 Lock m_registeredThreadsMutex;
160 Thread* m_registeredThreads;
161 WTF::ThreadSpecificKey m_threadSpecificForMachineThreads;
162 WTF::ThreadSpecificKey m_threadSpecificForThread;
163#if !ASSERT_DISABLED
164 Heap* m_heap;
165#endif
166};
167
168} // namespace JSC
169
170#if COMPILER(GCC_OR_CLANG)
171#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
172#else
173#define REGISTER_BUFFER_ALIGNMENT
174#endif
175
176// ALLOCATE_AND_GET_REGISTER_STATE() is a macro so that it is always "inlined" even in debug builds.
177#if COMPILER(MSVC)
178#pragma warning(push)
179#pragma warning(disable: 4611)
180#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
181 MachineThreads::RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
182 setjmp(registers)
183#pragma warning(pop)
184#else
185#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
186 MachineThreads::RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
187 setjmp(registers)
188#endif
189
190#endif // MachineThreads_h
191