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
62namespace WTF {
63
64typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
65
66static Mutex* atomicallyInitializedStaticMutex;
67
68void clearPthreadHandleForIdentifier(ThreadIdentifier);
69
70static Mutex& threadMapMutex()
71{
72    DEFINE_STATIC_LOCAL(Mutex, mutex, ());
73    return mutex;
74}
75
76void initializeThreading()
77{
78    if (atomicallyInitializedStaticMutex)
79        return;
80
81    atomicallyInitializedStaticMutex = new Mutex;
82    threadMapMutex();
83    initializeRandomNumberGenerator();
84}
85
86void lockAtomicallyInitializedStaticMutex()
87{
88    ASSERT(atomicallyInitializedStaticMutex);
89    atomicallyInitializedStaticMutex->lock();
90}
91
92void unlockAtomicallyInitializedStaticMutex()
93{
94    atomicallyInitializedStaticMutex->unlock();
95}
96
97static ThreadMap& threadMap()
98{
99    DEFINE_STATIC_LOCAL(ThreadMap, map, ());
100    return map;
101}
102
103static 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
116static 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
129static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
130{
131    MutexLocker locker(threadMapMutex());
132
133    return threadMap().get(id);
134}
135
136void 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)
146static 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
159ThreadIdentifier 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    ThreadFunctionInvocation* unused = invocation.leakPtr();
173
174    return establishIdentifierForPthreadHandle(threadHandle);
175}
176#else
177ThreadIdentifier 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
189void 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
208int 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
223void 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
234void yield()
235{
236    sched_yield();
237}
238
239ThreadIdentifier 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
251Mutex::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
262Mutex::~Mutex()
263{
264    pthread_mutex_destroy(&m_mutex);
265}
266
267void Mutex::lock()
268{
269    int result = pthread_mutex_lock(&m_mutex);
270    ASSERT_UNUSED(result, !result);
271}
272
273bool 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
286void Mutex::unlock()
287{
288    int result = pthread_mutex_unlock(&m_mutex);
289    ASSERT_UNUSED(result, !result);
290}
291
292#if HAVE(PTHREAD_RWLOCK)
293ReadWriteLock::ReadWriteLock()
294{
295    pthread_rwlock_init(&m_readWriteLock, NULL);
296}
297
298ReadWriteLock::~ReadWriteLock()
299{
300    pthread_rwlock_destroy(&m_readWriteLock);
301}
302
303void ReadWriteLock::readLock()
304{
305    int result = pthread_rwlock_rdlock(&m_readWriteLock);
306    ASSERT_UNUSED(result, !result);
307}
308
309bool 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
322void ReadWriteLock::writeLock()
323{
324    int result = pthread_rwlock_wrlock(&m_readWriteLock);
325    ASSERT_UNUSED(result, !result);
326}
327
328bool 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
341void ReadWriteLock::unlock()
342{
343    int result = pthread_rwlock_unlock(&m_readWriteLock);
344    ASSERT_UNUSED(result, !result);
345}
346#endif  // HAVE(PTHREAD_RWLOCK)
347
348ThreadCondition::ThreadCondition()
349{
350    pthread_cond_init(&m_condition, NULL);
351}
352
353ThreadCondition::~ThreadCondition()
354{
355    pthread_cond_destroy(&m_condition);
356}
357
358void ThreadCondition::wait(Mutex& mutex)
359{
360    int result = pthread_cond_wait(&m_condition, &mutex.impl());
361    ASSERT_UNUSED(result, !result);
362}
363
364bool 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
384void ThreadCondition::signal()
385{
386    int result = pthread_cond_signal(&m_condition);
387    ASSERT_UNUSED(result, !result);
388}
389
390void 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)
399