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 Computer, 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 "wtf/Threading.h"
33
34#if USE(PTHREADS)
35
36#include "wtf/DateMath.h"
37#include "wtf/HashMap.h"
38#include "wtf/OwnPtr.h"
39#include "wtf/PassOwnPtr.h"
40#include "wtf/StdLibExtras.h"
41#include "wtf/ThreadFunctionInvocation.h"
42#include "wtf/ThreadSpecific.h"
43#include "wtf/ThreadingPrimitives.h"
44#include "wtf/WTFThreadData.h"
45#include "wtf/dtoa.h"
46#include "wtf/dtoa/cached-powers.h"
47#include <errno.h>
48
49#if !COMPILER(MSVC)
50#include <limits.h>
51#include <sched.h>
52#include <sys/time.h>
53#endif
54
55#if OS(MACOSX)
56#include <objc/objc-auto.h>
57#endif
58
59#if OS(LINUX)
60#include <sys/syscall.h>
61#endif
62
63#if OS(LINUX) || OS(ANDROID)
64#include <unistd.h>
65#endif
66
67namespace WTF {
68
69static Mutex* atomicallyInitializedStaticMutex;
70
71void initializeThreading()
72{
73    // This should only be called once.
74    ASSERT(!atomicallyInitializedStaticMutex);
75
76    // StringImpl::empty() does not construct its static string in a threadsafe fashion,
77    // so ensure it has been initialized from here.
78    StringImpl::empty();
79    StringImpl::empty16Bit();
80    atomicallyInitializedStaticMutex = new Mutex;
81    wtfThreadData();
82    s_dtoaP5Mutex = new Mutex;
83    initializeDates();
84    // Force initialization of static DoubleToStringConverter converter variable
85    // inside EcmaScriptConverter function while we are in single thread mode.
86    double_conversion::DoubleToStringConverter::EcmaScriptConverter();
87}
88
89void lockAtomicallyInitializedStaticMutex()
90{
91    ASSERT(atomicallyInitializedStaticMutex);
92    atomicallyInitializedStaticMutex->lock();
93}
94
95void unlockAtomicallyInitializedStaticMutex()
96{
97    atomicallyInitializedStaticMutex->unlock();
98}
99
100ThreadIdentifier currentThread()
101{
102#if OS(MACOSX)
103    return pthread_mach_thread_np(pthread_self());
104#elif OS(LINUX)
105    return syscall(__NR_gettid);
106#elif OS(ANDROID)
107    return gettid();
108#else
109    return reinterpret_cast<uintptr_t>(pthread_self());
110#endif
111}
112
113MutexBase::MutexBase(bool recursive)
114{
115    pthread_mutexattr_t attr;
116    pthread_mutexattr_init(&attr);
117    pthread_mutexattr_settype(&attr, recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL);
118
119    int result = pthread_mutex_init(&m_mutex.m_internalMutex, &attr);
120    ASSERT_UNUSED(result, !result);
121#if ENABLE(ASSERT)
122    m_mutex.m_recursionCount = 0;
123#endif
124
125    pthread_mutexattr_destroy(&attr);
126}
127
128MutexBase::~MutexBase()
129{
130    int result = pthread_mutex_destroy(&m_mutex.m_internalMutex);
131    ASSERT_UNUSED(result, !result);
132}
133
134void MutexBase::lock()
135{
136    int result = pthread_mutex_lock(&m_mutex.m_internalMutex);
137    ASSERT_UNUSED(result, !result);
138#if ENABLE(ASSERT)
139    ++m_mutex.m_recursionCount;
140#endif
141}
142
143void MutexBase::unlock()
144{
145#if ENABLE(ASSERT)
146    ASSERT(m_mutex.m_recursionCount);
147    --m_mutex.m_recursionCount;
148#endif
149    int result = pthread_mutex_unlock(&m_mutex.m_internalMutex);
150    ASSERT_UNUSED(result, !result);
151}
152
153// There is a separate tryLock implementation for the Mutex and the
154// RecursiveMutex since on Windows we need to manually check if tryLock should
155// succeed or not for the non-recursive mutex. On Linux the two implementations
156// are equal except we can assert the recursion count is always zero for the
157// non-recursive mutex.
158bool Mutex::tryLock()
159{
160    int result = pthread_mutex_trylock(&m_mutex.m_internalMutex);
161    if (result == 0) {
162#if ENABLE(ASSERT)
163        // The Mutex class is not recursive, so the recursionCount should be
164        // zero after getting the lock.
165        ASSERT(!m_mutex.m_recursionCount);
166        ++m_mutex.m_recursionCount;
167#endif
168        return true;
169    }
170    if (result == EBUSY)
171        return false;
172
173    ASSERT_NOT_REACHED();
174    return false;
175}
176
177bool RecursiveMutex::tryLock()
178{
179    int result = pthread_mutex_trylock(&m_mutex.m_internalMutex);
180    if (result == 0) {
181#if ENABLE(ASSERT)
182        ++m_mutex.m_recursionCount;
183#endif
184        return true;
185    }
186    if (result == EBUSY)
187        return false;
188
189    ASSERT_NOT_REACHED();
190    return false;
191}
192
193ThreadCondition::ThreadCondition()
194{
195    pthread_cond_init(&m_condition, NULL);
196}
197
198ThreadCondition::~ThreadCondition()
199{
200    pthread_cond_destroy(&m_condition);
201}
202
203void ThreadCondition::wait(MutexBase& mutex)
204{
205    PlatformMutex& platformMutex = mutex.impl();
206    int result = pthread_cond_wait(&m_condition, &platformMutex.m_internalMutex);
207    ASSERT_UNUSED(result, !result);
208#if ENABLE(ASSERT)
209    ++platformMutex.m_recursionCount;
210#endif
211}
212
213bool ThreadCondition::timedWait(MutexBase& mutex, double absoluteTime)
214{
215    if (absoluteTime < currentTime())
216        return false;
217
218    if (absoluteTime > INT_MAX) {
219        wait(mutex);
220        return true;
221    }
222
223    int timeSeconds = static_cast<int>(absoluteTime);
224    int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
225
226    timespec targetTime;
227    targetTime.tv_sec = timeSeconds;
228    targetTime.tv_nsec = timeNanoseconds;
229
230    PlatformMutex& platformMutex = mutex.impl();
231    int result = pthread_cond_timedwait(&m_condition, &platformMutex.m_internalMutex, &targetTime);
232#if ENABLE(ASSERT)
233    ++platformMutex.m_recursionCount;
234#endif
235    return result == 0;
236}
237
238void ThreadCondition::signal()
239{
240    int result = pthread_cond_signal(&m_condition);
241    ASSERT_UNUSED(result, !result);
242}
243
244void ThreadCondition::broadcast()
245{
246    int result = pthread_cond_broadcast(&m_condition);
247    ASSERT_UNUSED(result, !result);
248}
249
250} // namespace WTF
251
252#endif // USE(PTHREADS)
253