OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. | |
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) | |
4 * Copyright (C) 2011 Research In Motion Limited. All rights reserved. | |
5 * | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions | |
8 * are met: | |
9 * | |
10 * 1. Redistributions of source code must retain the above copyright | |
11 * notice, this list of conditions and the following disclaimer. | |
12 * 2. Redistributions in binary form must reproduce the above copyright | |
13 * notice, this list of conditions and the following disclaimer in the | |
14 * documentation and/or other materials provided with the distribution. | |
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
16 * its contributors may be used to endorse or promote products derived | |
17 * from this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "wtf/Threading.h" | |
32 | |
33 #if OS(POSIX) | |
34 | |
35 #include "wtf/CurrentTime.h" | |
36 #include "wtf/DateMath.h" | |
37 #include "wtf/HashMap.h" | |
38 #include "wtf/StdLibExtras.h" | |
39 #include "wtf/ThreadSpecific.h" | |
40 #include "wtf/ThreadingPrimitives.h" | |
41 #include "wtf/WTFThreadData.h" | |
42 #include "wtf/dtoa/double-conversion.h" | |
43 #include <errno.h> | |
44 #include <limits.h> | |
45 #include <sched.h> | |
46 #include <sys/time.h> | |
47 | |
48 #if OS(MACOSX) | |
49 #include <objc/objc-auto.h> | |
50 #endif | |
51 | |
52 #if OS(LINUX) | |
53 #include <sys/syscall.h> | |
54 #endif | |
55 | |
56 #if OS(LINUX) || OS(ANDROID) | |
57 #include <unistd.h> | |
58 #endif | |
59 | |
60 namespace WTF { | |
61 | |
62 namespace internal { | |
63 | |
64 ThreadIdentifier currentThreadSyscall() { | |
65 #if OS(MACOSX) | |
66 return pthread_mach_thread_np(pthread_self()); | |
67 #elif OS(LINUX) | |
68 return syscall(__NR_gettid); | |
69 #elif OS(ANDROID) | |
70 return gettid(); | |
71 #else | |
72 return reinterpret_cast<uintptr_t>(pthread_self()); | |
73 #endif | |
74 } | |
75 | |
76 } // namespace internal | |
77 | |
78 void initializeThreading() { | |
79 // This should only be called once. | |
80 WTFThreadData::initialize(); | |
81 | |
82 initializeDates(); | |
83 // Force initialization of static DoubleToStringConverter converter variable | |
84 // inside EcmaScriptConverter function while we are in single thread mode. | |
85 double_conversion::DoubleToStringConverter::EcmaScriptConverter(); | |
86 } | |
87 | |
88 namespace { | |
89 ThreadSpecificKey s_currentThreadKey; | |
90 bool s_currentThreadKeyInitialized = false; | |
91 } // namespace | |
92 | |
93 void initializeCurrentThread() { | |
94 DCHECK(!s_currentThreadKeyInitialized); | |
95 threadSpecificKeyCreate(&s_currentThreadKey, [](void*) {}); | |
96 s_currentThreadKeyInitialized = true; | |
97 } | |
98 | |
99 ThreadIdentifier currentThread() { | |
100 // This doesn't use WTF::ThreadSpecific (e.g. WTFThreadData) because | |
101 // ThreadSpecific now depends on currentThread. It is necessary to avoid this | |
102 // or a similar loop: | |
103 // | |
104 // currentThread | |
105 // -> wtfThreadData | |
106 // -> ThreadSpecific::operator* | |
107 // -> isMainThread | |
108 // -> currentThread | |
109 static_assert(sizeof(ThreadIdentifier) <= sizeof(void*), | |
110 "ThreadIdentifier must fit in a void*."); | |
111 DCHECK(s_currentThreadKeyInitialized); | |
112 void* value = threadSpecificGet(s_currentThreadKey); | |
113 if (UNLIKELY(!value)) { | |
114 value = reinterpret_cast<void*>( | |
115 static_cast<intptr_t>(internal::currentThreadSyscall())); | |
116 DCHECK(value); | |
117 threadSpecificSet(s_currentThreadKey, value); | |
118 } | |
119 return reinterpret_cast<intptr_t>(threadSpecificGet(s_currentThreadKey)); | |
120 } | |
121 | |
122 MutexBase::MutexBase(bool recursive) { | |
123 pthread_mutexattr_t attr; | |
124 pthread_mutexattr_init(&attr); | |
125 pthread_mutexattr_settype( | |
126 &attr, recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL); | |
127 | |
128 int result = pthread_mutex_init(&m_mutex.m_internalMutex, &attr); | |
129 DCHECK_EQ(result, 0); | |
130 #if DCHECK_IS_ON() | |
131 m_mutex.m_recursionCount = 0; | |
132 #endif | |
133 | |
134 pthread_mutexattr_destroy(&attr); | |
135 } | |
136 | |
137 MutexBase::~MutexBase() { | |
138 int result = pthread_mutex_destroy(&m_mutex.m_internalMutex); | |
139 DCHECK_EQ(result, 0); | |
140 } | |
141 | |
142 void MutexBase::lock() { | |
143 int result = pthread_mutex_lock(&m_mutex.m_internalMutex); | |
144 DCHECK_EQ(result, 0); | |
145 #if DCHECK_IS_ON() | |
146 ++m_mutex.m_recursionCount; | |
147 #endif | |
148 } | |
149 | |
150 void MutexBase::unlock() { | |
151 #if DCHECK_IS_ON() | |
152 DCHECK(m_mutex.m_recursionCount); | |
153 --m_mutex.m_recursionCount; | |
154 #endif | |
155 int result = pthread_mutex_unlock(&m_mutex.m_internalMutex); | |
156 DCHECK_EQ(result, 0); | |
157 } | |
158 | |
159 // There is a separate tryLock implementation for the Mutex and the | |
160 // RecursiveMutex since on Windows we need to manually check if tryLock should | |
161 // succeed or not for the non-recursive mutex. On Linux the two implementations | |
162 // are equal except we can assert the recursion count is always zero for the | |
163 // non-recursive mutex. | |
164 bool Mutex::tryLock() { | |
165 int result = pthread_mutex_trylock(&m_mutex.m_internalMutex); | |
166 if (result == 0) { | |
167 #if DCHECK_IS_ON() | |
168 // The Mutex class is not recursive, so the recursionCount should be | |
169 // zero after getting the lock. | |
170 DCHECK(!m_mutex.m_recursionCount); | |
171 ++m_mutex.m_recursionCount; | |
172 #endif | |
173 return true; | |
174 } | |
175 if (result == EBUSY) | |
176 return false; | |
177 | |
178 NOTREACHED(); | |
179 return false; | |
180 } | |
181 | |
182 bool RecursiveMutex::tryLock() { | |
183 int result = pthread_mutex_trylock(&m_mutex.m_internalMutex); | |
184 if (result == 0) { | |
185 #if DCHECK_IS_ON() | |
186 ++m_mutex.m_recursionCount; | |
187 #endif | |
188 return true; | |
189 } | |
190 if (result == EBUSY) | |
191 return false; | |
192 | |
193 NOTREACHED(); | |
194 return false; | |
195 } | |
196 | |
197 ThreadCondition::ThreadCondition() { | |
198 pthread_cond_init(&m_condition, nullptr); | |
199 } | |
200 | |
201 ThreadCondition::~ThreadCondition() { | |
202 pthread_cond_destroy(&m_condition); | |
203 } | |
204 | |
205 void ThreadCondition::wait(MutexBase& mutex) { | |
206 PlatformMutex& platformMutex = mutex.impl(); | |
207 int result = pthread_cond_wait(&m_condition, &platformMutex.m_internalMutex); | |
208 DCHECK_EQ(result, 0); | |
209 #if DCHECK_IS_ON() | |
210 ++platformMutex.m_recursionCount; | |
211 #endif | |
212 } | |
213 | |
214 bool ThreadCondition::timedWait(MutexBase& mutex, double absoluteTime) { | |
215 if (absoluteTime < currentTime()) | |
216 return false; | |
217 | |
218 if (absoluteTime > INT_MAX) { | |
219 wait(mutex); | |
220 return true; | |
221 } | |
222 | |
223 int timeSeconds = static_cast<int>(absoluteTime); | |
224 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9); | |
225 | |
226 timespec targetTime; | |
227 targetTime.tv_sec = timeSeconds; | |
228 targetTime.tv_nsec = timeNanoseconds; | |
229 | |
230 PlatformMutex& platformMutex = mutex.impl(); | |
231 int result = pthread_cond_timedwait( | |
232 &m_condition, &platformMutex.m_internalMutex, &targetTime); | |
233 #if DCHECK_IS_ON() | |
234 ++platformMutex.m_recursionCount; | |
235 #endif | |
236 return result == 0; | |
237 } | |
238 | |
239 void ThreadCondition::signal() { | |
240 int result = pthread_cond_signal(&m_condition); | |
241 DCHECK_EQ(result, 0); | |
242 } | |
243 | |
244 void ThreadCondition::broadcast() { | |
245 int result = pthread_cond_broadcast(&m_condition); | |
246 DCHECK_EQ(result, 0); | |
247 } | |
248 | |
249 #if DCHECK_IS_ON() | |
250 static bool s_threadCreated = false; | |
251 | |
252 bool isBeforeThreadCreated() { | |
253 return !s_threadCreated; | |
254 } | |
255 | |
256 void willCreateThread() { | |
257 s_threadCreated = true; | |
258 } | |
259 #endif | |
260 | |
261 } // namespace WTF | |
262 | |
263 #endif // OS(POSIX) | |
OLD | NEW |