1 /*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include "config.h"
30 #include "Threading.h"
31
32 #include "StdLibExtras.h"
33
34 #if USE(PTHREADS)
35
36 #include "CurrentTime.h"
37 #include "HashMap.h"
38 #include "MainThread.h"
39 #include "RandomNumberSeed.h"
40
41 #include <errno.h>
42 #include <limits.h>
43 #include <sys/time.h>
44
45 #if PLATFORM(ANDROID)
46 #include "jni_utility.h"
47 #endif
48
49 namespace WTF {
50
51 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
52
53 static Mutex* atomicallyInitializedStaticMutex;
54
55 #if !PLATFORM(DARWIN)
56 static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread.
57 #endif
58
threadMapMutex()59 static Mutex& threadMapMutex()
60 {
61 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
62 return mutex;
63 }
64
initializeThreading()65 void initializeThreading()
66 {
67 if (!atomicallyInitializedStaticMutex) {
68 atomicallyInitializedStaticMutex = new Mutex;
69 threadMapMutex();
70 initializeRandomNumberGenerator();
71 #if !PLATFORM(DARWIN)
72 mainThreadIdentifier = currentThread();
73 #endif
74 initializeMainThread();
75 }
76 }
77
lockAtomicallyInitializedStaticMutex()78 void lockAtomicallyInitializedStaticMutex()
79 {
80 ASSERT(atomicallyInitializedStaticMutex);
81 atomicallyInitializedStaticMutex->lock();
82 }
83
unlockAtomicallyInitializedStaticMutex()84 void unlockAtomicallyInitializedStaticMutex()
85 {
86 atomicallyInitializedStaticMutex->unlock();
87 }
88
threadMap()89 static ThreadMap& threadMap()
90 {
91 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
92 return map;
93 }
94
identifierByPthreadHandle(const pthread_t & pthreadHandle)95 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
96 {
97 MutexLocker locker(threadMapMutex());
98
99 ThreadMap::iterator i = threadMap().begin();
100 for (; i != threadMap().end(); ++i) {
101 if (pthread_equal(i->second, pthreadHandle))
102 return i->first;
103 }
104
105 return 0;
106 }
107
establishIdentifierForPthreadHandle(pthread_t & pthreadHandle)108 static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle)
109 {
110 ASSERT(!identifierByPthreadHandle(pthreadHandle));
111
112 MutexLocker locker(threadMapMutex());
113
114 static ThreadIdentifier identifierCount = 1;
115
116 threadMap().add(identifierCount, pthreadHandle);
117
118 return identifierCount++;
119 }
120
pthreadHandleForIdentifier(ThreadIdentifier id)121 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
122 {
123 MutexLocker locker(threadMapMutex());
124
125 return threadMap().get(id);
126 }
127
clearPthreadHandleForIdentifier(ThreadIdentifier id)128 static void clearPthreadHandleForIdentifier(ThreadIdentifier id)
129 {
130 MutexLocker locker(threadMapMutex());
131
132 ASSERT(threadMap().contains(id));
133
134 threadMap().remove(id);
135 }
136
137 #if PLATFORM(ANDROID)
138 // On the Android platform, threads must be registered with the VM before they run.
139 struct ThreadData {
140 ThreadFunction entryPoint;
141 void* arg;
142 };
143
runThreadWithRegistration(void * arg)144 static void* runThreadWithRegistration(void* arg)
145 {
146 ThreadData* data = static_cast<ThreadData*>(arg);
147 JavaVM* vm = JSC::Bindings::getJavaVM();
148 JNIEnv* env;
149 void* ret = 0;
150 if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
151 ret = data->entryPoint(data->arg);
152 vm->DetachCurrentThread();
153 }
154 delete data;
155 return ret;
156 }
157
createThreadInternal(ThreadFunction entryPoint,void * data,const char *)158 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
159 {
160 pthread_t threadHandle;
161 ThreadData* threadData = new ThreadData;
162 threadData->entryPoint = entryPoint;
163 threadData->arg = data;
164
165 if (pthread_create(&threadHandle, 0, runThreadWithRegistration, static_cast<void*>(threadData))) {
166 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
167 delete threadData;
168 return 0;
169 }
170 return establishIdentifierForPthreadHandle(threadHandle);
171 }
172 #else
createThreadInternal(ThreadFunction entryPoint,void * data,const char *)173 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
174 {
175 pthread_t threadHandle;
176 if (pthread_create(&threadHandle, NULL, entryPoint, data)) {
177 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
178 return 0;
179 }
180
181 return establishIdentifierForPthreadHandle(threadHandle);
182 }
183 #endif
184
waitForThreadCompletion(ThreadIdentifier threadID,void ** result)185 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
186 {
187 ASSERT(threadID);
188
189 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
190
191 int joinResult = pthread_join(pthreadHandle, result);
192 if (joinResult == EDEADLK)
193 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
194
195 clearPthreadHandleForIdentifier(threadID);
196 return joinResult;
197 }
198
detachThread(ThreadIdentifier threadID)199 void detachThread(ThreadIdentifier threadID)
200 {
201 ASSERT(threadID);
202
203 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
204
205 pthread_detach(pthreadHandle);
206
207 clearPthreadHandleForIdentifier(threadID);
208 }
209
currentThread()210 ThreadIdentifier currentThread()
211 {
212 pthread_t currentThread = pthread_self();
213 if (ThreadIdentifier id = identifierByPthreadHandle(currentThread))
214 return id;
215 return establishIdentifierForPthreadHandle(currentThread);
216 }
217
isMainThread()218 bool isMainThread()
219 {
220 #if PLATFORM(DARWIN)
221 return pthread_main_np();
222 #else
223 return currentThread() == mainThreadIdentifier;
224 #endif
225 }
226
Mutex()227 Mutex::Mutex()
228 {
229 pthread_mutex_init(&m_mutex, NULL);
230 }
231
~Mutex()232 Mutex::~Mutex()
233 {
234 pthread_mutex_destroy(&m_mutex);
235 }
236
lock()237 void Mutex::lock()
238 {
239 if (pthread_mutex_lock(&m_mutex) != 0)
240 ASSERT(false);
241 }
242
tryLock()243 bool Mutex::tryLock()
244 {
245 int result = pthread_mutex_trylock(&m_mutex);
246
247 if (result == 0)
248 return true;
249 else if (result == EBUSY)
250 return false;
251
252 ASSERT(false);
253 return false;
254 }
255
unlock()256 void Mutex::unlock()
257 {
258 if (pthread_mutex_unlock(&m_mutex) != 0)
259 ASSERT(false);
260 }
261
ThreadCondition()262 ThreadCondition::ThreadCondition()
263 {
264 pthread_cond_init(&m_condition, NULL);
265 }
266
~ThreadCondition()267 ThreadCondition::~ThreadCondition()
268 {
269 pthread_cond_destroy(&m_condition);
270 }
271
wait(Mutex & mutex)272 void ThreadCondition::wait(Mutex& mutex)
273 {
274 if (pthread_cond_wait(&m_condition, &mutex.impl()) != 0)
275 ASSERT(false);
276 }
277
timedWait(Mutex & mutex,double absoluteTime)278 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
279 {
280 if (absoluteTime < currentTime())
281 return false;
282
283 if (absoluteTime > INT_MAX) {
284 wait(mutex);
285 return true;
286 }
287
288 int timeSeconds = static_cast<int>(absoluteTime);
289 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
290
291 timespec targetTime;
292 targetTime.tv_sec = timeSeconds;
293 targetTime.tv_nsec = timeNanoseconds;
294
295 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
296 }
297
signal()298 void ThreadCondition::signal()
299 {
300 if (pthread_cond_signal(&m_condition) != 0)
301 ASSERT(false);
302 }
303
broadcast()304 void ThreadCondition::broadcast()
305 {
306 if (pthread_cond_broadcast(&m_condition) != 0)
307 ASSERT(false);
308 }
309
310 } // namespace WTF
311
312 #endif // USE(PTHREADS)
313