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