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 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 "config.h"
32#include "Threading.h"
33
34#if USE(PTHREADS)
35
36#include "CurrentTime.h"
37#include "DateMath.h"
38#include "dtoa.h"
39#include "dtoa/cached-powers.h"
40#include "HashMap.h"
41#include "RandomNumberSeed.h"
42#include "StackStats.h"
43#include "StdLibExtras.h"
44#include "ThreadFunctionInvocation.h"
45#include "ThreadIdentifierDataPthreads.h"
46#include "ThreadSpecific.h"
47#include <wtf/DataLog.h>
48#include <wtf/RawPointer.h>
49#include <wtf/WTFThreadData.h>
50#include <errno.h>
51
52#if !COMPILER(MSVC)
53#include <limits.h>
54#include <sched.h>
55#include <sys/time.h>
56#endif
57
58#if OS(MAC_OS_X)
59#include <objc/objc-auto.h>
60#endif
61
62namespace WTF {
63
64class PthreadState {
65    WTF_MAKE_FAST_ALLOCATED;
66public:
67    enum JoinableState {
68        Joinable, // The default thread state. The thread can be joined on.
69
70        Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a
71                // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run)
72                // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's
73                // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
74
75        Detached // The thread has been detached and can no longer be joined on. At this point, the thread must take care of cleaning up after itself.
76    };
77
78    // Currently all threads created by WTF start out as joinable.
79    PthreadState(pthread_t handle)
80        : m_joinableState(Joinable)
81        , m_didExit(false)
82        , m_pthreadHandle(handle)
83    {
84    }
85
86    JoinableState joinableState() { return m_joinableState; }
87    pthread_t pthreadHandle() { return m_pthreadHandle; }
88    void didBecomeDetached() { m_joinableState = Detached; }
89    void didExit() { m_didExit = true; }
90    void didJoin() { m_joinableState = Joined; }
91    bool hasExited() { return m_didExit; }
92
93private:
94    JoinableState m_joinableState;
95    bool m_didExit;
96    pthread_t m_pthreadHandle;
97};
98
99typedef HashMap<ThreadIdentifier, std::unique_ptr<PthreadState>> ThreadMap;
100
101void unsafeThreadWasDetached(ThreadIdentifier);
102void threadDidExit(ThreadIdentifier);
103void threadWasJoined(ThreadIdentifier);
104
105static Mutex& threadMapMutex()
106{
107    DEPRECATED_DEFINE_STATIC_LOCAL(Mutex, mutex, ());
108    return mutex;
109}
110
111void initializeThreading()
112{
113    static bool isInitialized;
114
115    if (isInitialized)
116        return;
117
118    isInitialized = true;
119
120    WTF::double_conversion::initialize();
121    // StringImpl::empty() does not construct its static string in a threadsafe fashion,
122    // so ensure it has been initialized from here.
123    StringImpl::empty();
124    threadMapMutex();
125    initializeRandomNumberGenerator();
126    ThreadIdentifierData::initializeOnce();
127    StackStats::initialize();
128    wtfThreadData();
129    s_dtoaP5Mutex = new Mutex;
130    initializeDates();
131}
132
133static ThreadMap& threadMap()
134{
135    DEPRECATED_DEFINE_STATIC_LOCAL(ThreadMap, map, ());
136    return map;
137}
138
139static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
140{
141    MutexLocker locker(threadMapMutex());
142
143    ThreadMap::iterator i = threadMap().begin();
144    for (; i != threadMap().end(); ++i) {
145        if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
146            return i->key;
147    }
148
149    return 0;
150}
151
152static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
153{
154    ASSERT(!identifierByPthreadHandle(pthreadHandle));
155    MutexLocker locker(threadMapMutex());
156    static ThreadIdentifier identifierCount = 1;
157    threadMap().add(identifierCount, std::make_unique<PthreadState>(pthreadHandle));
158    return identifierCount++;
159}
160
161static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
162{
163    return threadMap().get(id)->pthreadHandle();
164}
165
166static void* wtfThreadEntryPoint(void* param)
167{
168    // Balanced by .leakPtr() in createThreadInternal.
169    auto invocation = std::unique_ptr<ThreadFunctionInvocation>(static_cast<ThreadFunctionInvocation*>(param));
170    invocation->function(invocation->data);
171    return nullptr;
172}
173
174ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
175{
176    auto invocation = std::make_unique<ThreadFunctionInvocation>(entryPoint, data);
177    pthread_t threadHandle;
178    pthread_attr_t attr;
179    pthread_attr_init(&attr);
180#if HAVE(QOS_CLASSES)
181    pthread_attr_set_qos_class_np(&attr, QOS_CLASS_USER_INITIATED, 0);
182#endif
183    int error = pthread_create(&threadHandle, &attr, wtfThreadEntryPoint, invocation.get());
184    pthread_attr_destroy(&attr);
185    if (error) {
186        LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
187        return 0;
188    }
189
190    // Balanced by std::unique_ptr constructor in wtfThreadEntryPoint.
191    ThreadFunctionInvocation* leakedInvocation = invocation.release();
192    UNUSED_PARAM(leakedInvocation);
193
194    return establishIdentifierForPthreadHandle(threadHandle);
195}
196
197void initializeCurrentThreadInternal(const char* threadName)
198{
199#if HAVE(PTHREAD_SETNAME_NP)
200    pthread_setname_np(threadName);
201#else
202    UNUSED_PARAM(threadName);
203#endif
204
205#if OS(MAC_OS_X)
206    // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
207    // garbage collector in case API implementations use garbage-collected memory.
208    objc_registerThreadWithCollector();
209#endif
210
211    ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
212    ASSERT(id);
213    ThreadIdentifierData::initialize(id);
214}
215
216void changeThreadPriority(ThreadIdentifier threadID, int delta)
217{
218    pthread_t pthreadHandle;
219    ASSERT(threadID);
220
221    {
222        MutexLocker locker(threadMapMutex());
223        pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
224        ASSERT(pthreadHandle);
225    }
226
227    int policy;
228    struct sched_param param;
229
230    if (pthread_getschedparam(pthreadHandle, &policy, &param))
231        return;
232
233    param.sched_priority += delta;
234
235    pthread_setschedparam(pthreadHandle, policy, &param);
236}
237
238int waitForThreadCompletion(ThreadIdentifier threadID)
239{
240    pthread_t pthreadHandle;
241    ASSERT(threadID);
242
243    {
244        // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
245        MutexLocker locker(threadMapMutex());
246        pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
247        ASSERT(pthreadHandle);
248    }
249
250    int joinResult = pthread_join(pthreadHandle, 0);
251
252    if (joinResult == EDEADLK)
253        LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
254    else if (joinResult)
255        LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
256
257    MutexLocker locker(threadMapMutex());
258    PthreadState* state = threadMap().get(threadID);
259    ASSERT(state);
260    ASSERT(state->joinableState() == PthreadState::Joinable);
261
262    // The thread has already exited, so clean up after it.
263    if (state->hasExited())
264        threadMap().remove(threadID);
265    // The thread hasn't exited yet, so don't clean anything up. Just signal that we've already joined on it so that it will clean up after itself.
266    else
267        state->didJoin();
268
269    return joinResult;
270}
271
272void detachThread(ThreadIdentifier threadID)
273{
274    ASSERT(threadID);
275
276    MutexLocker locker(threadMapMutex());
277    pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
278    ASSERT(pthreadHandle);
279
280    int detachResult = pthread_detach(pthreadHandle);
281    if (detachResult)
282        LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
283
284    PthreadState* state = threadMap().get(threadID);
285    ASSERT(state);
286    if (state->hasExited())
287        threadMap().remove(threadID);
288    else
289        threadMap().get(threadID)->didBecomeDetached();
290}
291
292void threadDidExit(ThreadIdentifier threadID)
293{
294    MutexLocker locker(threadMapMutex());
295    PthreadState* state = threadMap().get(threadID);
296    ASSERT(state);
297
298    state->didExit();
299
300    if (state->joinableState() != PthreadState::Joinable)
301        threadMap().remove(threadID);
302}
303
304ThreadIdentifier currentThread()
305{
306    ThreadIdentifier id = ThreadIdentifierData::identifier();
307    if (id)
308        return id;
309
310    // Not a WTF-created thread, ThreadIdentifier is not established yet.
311    id = establishIdentifierForPthreadHandle(pthread_self());
312    ThreadIdentifierData::initialize(id);
313    return id;
314}
315
316Mutex::Mutex()
317{
318    pthread_mutexattr_t attr;
319    pthread_mutexattr_init(&attr);
320    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
321
322    int result = pthread_mutex_init(&m_mutex, &attr);
323    ASSERT_UNUSED(result, !result);
324
325    pthread_mutexattr_destroy(&attr);
326}
327
328Mutex::~Mutex()
329{
330    int result = pthread_mutex_destroy(&m_mutex);
331    ASSERT_UNUSED(result, !result);
332}
333
334void Mutex::lock()
335{
336    int result = pthread_mutex_lock(&m_mutex);
337    ASSERT_UNUSED(result, !result);
338}
339
340bool Mutex::tryLock()
341{
342    int result = pthread_mutex_trylock(&m_mutex);
343
344    if (result == 0)
345        return true;
346    if (result == EBUSY)
347        return false;
348
349    ASSERT_NOT_REACHED();
350    return false;
351}
352
353void Mutex::unlock()
354{
355    int result = pthread_mutex_unlock(&m_mutex);
356    ASSERT_UNUSED(result, !result);
357}
358
359ThreadCondition::ThreadCondition()
360{
361    pthread_cond_init(&m_condition, NULL);
362}
363
364ThreadCondition::~ThreadCondition()
365{
366    pthread_cond_destroy(&m_condition);
367}
368
369void ThreadCondition::wait(Mutex& mutex)
370{
371    int result = pthread_cond_wait(&m_condition, &mutex.impl());
372    ASSERT_UNUSED(result, !result);
373}
374
375bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
376{
377    if (absoluteTime < currentTime())
378        return false;
379
380    if (absoluteTime > INT_MAX) {
381        wait(mutex);
382        return true;
383    }
384
385    int timeSeconds = static_cast<int>(absoluteTime);
386    int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
387
388    timespec targetTime;
389    targetTime.tv_sec = timeSeconds;
390    targetTime.tv_nsec = timeNanoseconds;
391
392    return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
393}
394
395void ThreadCondition::signal()
396{
397    int result = pthread_cond_signal(&m_condition);
398    ASSERT_UNUSED(result, !result);
399}
400
401void ThreadCondition::broadcast()
402{
403    int result = pthread_cond_broadcast(&m_condition);
404    ASSERT_UNUSED(result, !result);
405}
406
407} // namespace WTF
408
409#endif // USE(PTHREADS)
410