d5ad46c4bb6fe7caccdb1e11005b381597f73597
[WebKit-https.git] / Source / JavaScriptCore / wtf / ThreadingPthreads.cpp
1 /*
2  * Copyright (C) 2007, 2009 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
30 #include "config.h"
31 #include "Threading.h"
32
33 #if USE(PTHREADS)
34
35 #include "CurrentTime.h"
36 #include "HashMap.h"
37 #include "MainThread.h"
38 #include "RandomNumberSeed.h"
39 #include "StdLibExtras.h"
40 #include "ThreadIdentifierDataPthreads.h"
41 #include "ThreadSpecific.h"
42 #include "UnusedParam.h"
43 #include <errno.h>
44
45 #if !COMPILER(MSVC)
46 #include <limits.h>
47 #include <sched.h>
48 #include <sys/time.h>
49 #endif
50
51 #if OS(ANDROID)
52 #include "JNIUtility.h"
53 #include "ThreadFunctionInvocation.h"
54 #include <wtf/OwnPtr.h>
55 #include <wtf/PassOwnPtr.h>
56 #endif
57
58 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
59 #include <objc/objc-auto.h>
60 #endif
61
62 namespace WTF {
63
64 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
65
66 static Mutex* atomicallyInitializedStaticMutex;
67
68 void clearPthreadHandleForIdentifier(ThreadIdentifier);
69
70 static Mutex& threadMapMutex()
71 {
72     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
73     return mutex;
74 }
75
76 void initializeThreading()
77 {
78     if (atomicallyInitializedStaticMutex)
79         return;
80
81     atomicallyInitializedStaticMutex = new Mutex;
82     threadMapMutex();
83     initializeRandomNumberGenerator();
84     ThreadIdentifierData::initializeOnce();
85 }
86
87 void lockAtomicallyInitializedStaticMutex()
88 {
89     ASSERT(atomicallyInitializedStaticMutex);
90     atomicallyInitializedStaticMutex->lock();
91 }
92
93 void unlockAtomicallyInitializedStaticMutex()
94 {
95     atomicallyInitializedStaticMutex->unlock();
96 }
97
98 static ThreadMap& threadMap()
99 {
100     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
101     return map;
102 }
103
104 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
105 {
106     MutexLocker locker(threadMapMutex());
107
108     ThreadMap::iterator i = threadMap().begin();
109     for (; i != threadMap().end(); ++i) {
110         if (pthread_equal(i->second, pthreadHandle))
111             return i->first;
112     }
113
114     return 0;
115 }
116
117 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
118 {
119     ASSERT(!identifierByPthreadHandle(pthreadHandle));
120
121     MutexLocker locker(threadMapMutex());
122
123     static ThreadIdentifier identifierCount = 1;
124
125     threadMap().add(identifierCount, pthreadHandle);
126
127     return identifierCount++;
128 }
129
130 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
131 {
132     MutexLocker locker(threadMapMutex());
133
134     return threadMap().get(id);
135 }
136
137 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
138 {
139     MutexLocker locker(threadMapMutex());
140
141     ASSERT(threadMap().contains(id));
142
143     threadMap().remove(id);
144 }
145
146 #if OS(ANDROID)
147 static void* runThreadWithRegistration(void* arg)
148 {
149     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(arg));
150     JavaVM* vm = JSC::Bindings::getJavaVM();
151     JNIEnv* env;
152     void* ret = 0;
153     if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
154         ret = invocation->function(invocation->data);
155         vm->DetachCurrentThread();
156     }
157     return ret;
158 }
159
160 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
161 {
162     pthread_t threadHandle;
163
164     // On the Android platform, threads must be registered with the VM before they run.
165     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
166
167     if (pthread_create(&threadHandle, 0, runThreadWithRegistration, invocation.get())) {
168         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
169         return 0;
170     }
171
172     // The thread will take ownership of invocation.
173     invocation.leakPtr();
174
175     return establishIdentifierForPthreadHandle(threadHandle);
176 }
177 #else
178 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
179 {
180     pthread_t threadHandle;
181     if (pthread_create(&threadHandle, 0, entryPoint, data)) {
182         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
183         return 0;
184     }
185
186     return establishIdentifierForPthreadHandle(threadHandle);
187 }
188 #endif
189
190 void initializeCurrentThreadInternal(const char* threadName)
191 {
192 #if HAVE(PTHREAD_SETNAME_NP)
193     pthread_setname_np(threadName);
194 #else
195     UNUSED_PARAM(threadName);
196 #endif
197
198 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
199     // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
200     // garbage collector in case API implementations use garbage-collected memory.
201     objc_registerThreadWithCollector();
202 #endif
203
204     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
205     ASSERT(id);
206     ThreadIdentifierData::initialize(id);
207 }
208
209 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
210 {
211     ASSERT(threadID);
212
213     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
214     if (!pthreadHandle)
215         return 0;
216
217     int joinResult = pthread_join(pthreadHandle, result);
218     if (joinResult == EDEADLK)
219         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
220
221     return joinResult;
222 }
223
224 void detachThread(ThreadIdentifier threadID)
225 {
226     ASSERT(threadID);
227
228     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
229     if (!pthreadHandle)
230         return;
231
232     pthread_detach(pthreadHandle);
233 }
234
235 void yield()
236 {
237     sched_yield();
238 }
239
240 ThreadIdentifier currentThread()
241 {
242     ThreadIdentifier id = ThreadIdentifierData::identifier();
243     if (id)
244         return id;
245
246     // Not a WTF-created thread, ThreadIdentifier is not established yet.
247     id = establishIdentifierForPthreadHandle(pthread_self());
248     ThreadIdentifierData::initialize(id);
249     return id;
250 }
251
252 Mutex::Mutex()
253 {
254     pthread_mutexattr_t attr;
255     pthread_mutexattr_init(&attr);
256     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
257
258     pthread_mutex_init(&m_mutex, &attr);
259
260     pthread_mutexattr_destroy(&attr);
261 }
262
263 Mutex::~Mutex()
264 {
265     pthread_mutex_destroy(&m_mutex);
266 }
267
268 void Mutex::lock()
269 {
270     int result = pthread_mutex_lock(&m_mutex);
271     ASSERT_UNUSED(result, !result);
272 }
273
274 bool Mutex::tryLock()
275 {
276     int result = pthread_mutex_trylock(&m_mutex);
277
278     if (result == 0)
279         return true;
280     if (result == EBUSY)
281         return false;
282
283     ASSERT_NOT_REACHED();
284     return false;
285 }
286
287 void Mutex::unlock()
288 {
289     int result = pthread_mutex_unlock(&m_mutex);
290     ASSERT_UNUSED(result, !result);
291 }
292
293 #if HAVE(PTHREAD_RWLOCK)
294 ReadWriteLock::ReadWriteLock()
295 {
296     pthread_rwlock_init(&m_readWriteLock, NULL);
297 }
298
299 ReadWriteLock::~ReadWriteLock()
300 {
301     pthread_rwlock_destroy(&m_readWriteLock);
302 }
303
304 void ReadWriteLock::readLock()
305 {
306     int result = pthread_rwlock_rdlock(&m_readWriteLock);
307     ASSERT_UNUSED(result, !result);
308 }
309
310 bool ReadWriteLock::tryReadLock()
311 {
312     int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
313
314     if (result == 0)
315         return true;
316     if (result == EBUSY || result == EAGAIN)
317         return false;
318
319     ASSERT_NOT_REACHED();
320     return false;
321 }
322
323 void ReadWriteLock::writeLock()
324 {
325     int result = pthread_rwlock_wrlock(&m_readWriteLock);
326     ASSERT_UNUSED(result, !result);
327 }
328
329 bool ReadWriteLock::tryWriteLock()
330 {
331     int result = pthread_rwlock_trywrlock(&m_readWriteLock);
332
333     if (result == 0)
334         return true;
335     if (result == EBUSY || result == EAGAIN)
336         return false;
337
338     ASSERT_NOT_REACHED();
339     return false;
340 }
341
342 void ReadWriteLock::unlock()
343 {
344     int result = pthread_rwlock_unlock(&m_readWriteLock);
345     ASSERT_UNUSED(result, !result);
346 }
347 #endif  // HAVE(PTHREAD_RWLOCK)
348
349 ThreadCondition::ThreadCondition()
350
351     pthread_cond_init(&m_condition, NULL);
352 }
353
354 ThreadCondition::~ThreadCondition()
355 {
356     pthread_cond_destroy(&m_condition);
357 }
358     
359 void ThreadCondition::wait(Mutex& mutex)
360 {
361     int result = pthread_cond_wait(&m_condition, &mutex.impl());
362     ASSERT_UNUSED(result, !result);
363 }
364
365 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
366 {
367     if (absoluteTime < currentTime())
368         return false;
369
370     if (absoluteTime > INT_MAX) {
371         wait(mutex);
372         return true;
373     }
374
375     int timeSeconds = static_cast<int>(absoluteTime);
376     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
377
378     timespec targetTime;
379     targetTime.tv_sec = timeSeconds;
380     targetTime.tv_nsec = timeNanoseconds;
381
382     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
383 }
384
385 void ThreadCondition::signal()
386 {
387     int result = pthread_cond_signal(&m_condition);
388     ASSERT_UNUSED(result, !result);
389 }
390
391 void ThreadCondition::broadcast()
392 {
393     int result = pthread_cond_broadcast(&m_condition);
394     ASSERT_UNUSED(result, !result);
395 }
396
397 } // namespace WTF
398
399 #endif // USE(PTHREADS)