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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
32 #include "wtf/Threading.h"
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/ThreadSpecific.h"
42 #include "wtf/ThreadingPrimitives.h"
43 #include "wtf/WTFThreadData.h"
45 #include "wtf/dtoa/cached-powers.h"
55 #include <objc/objc-auto.h>
59 #include <sys/syscall.h>
62 #if OS(LINUX) || OS(ANDROID)
68 static Mutex
* atomicallyInitializedStaticMutex
;
70 void initializeThreading()
72 // This should only be called once.
73 ASSERT(!atomicallyInitializedStaticMutex
);
75 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
76 // so ensure it has been initialized from here.
78 StringImpl::empty16Bit();
79 atomicallyInitializedStaticMutex
= new Mutex
;
81 s_dtoaP5Mutex
= new Mutex
;
83 // Force initialization of static DoubleToStringConverter converter variable
84 // inside EcmaScriptConverter function while we are in single thread mode.
85 double_conversion::DoubleToStringConverter::EcmaScriptConverter();
88 void lockAtomicallyInitializedStaticMutex()
90 ASSERT(atomicallyInitializedStaticMutex
);
91 atomicallyInitializedStaticMutex
->lock();
94 void unlockAtomicallyInitializedStaticMutex()
96 atomicallyInitializedStaticMutex
->unlock();
99 ThreadIdentifier
currentThread()
102 return pthread_mach_thread_np(pthread_self());
104 return syscall(__NR_gettid
);
108 return reinterpret_cast<uintptr_t>(pthread_self());
112 MutexBase::MutexBase(bool recursive
)
114 pthread_mutexattr_t attr
;
115 pthread_mutexattr_init(&attr
);
116 pthread_mutexattr_settype(&attr
, recursive
? PTHREAD_MUTEX_RECURSIVE
: PTHREAD_MUTEX_NORMAL
);
118 int result
= pthread_mutex_init(&m_mutex
.m_internalMutex
, &attr
);
119 ASSERT_UNUSED(result
, !result
);
121 m_mutex
.m_recursionCount
= 0;
124 pthread_mutexattr_destroy(&attr
);
127 MutexBase::~MutexBase()
129 int result
= pthread_mutex_destroy(&m_mutex
.m_internalMutex
);
130 ASSERT_UNUSED(result
, !result
);
133 void MutexBase::lock()
135 int result
= pthread_mutex_lock(&m_mutex
.m_internalMutex
);
136 ASSERT_UNUSED(result
, !result
);
138 ++m_mutex
.m_recursionCount
;
142 void MutexBase::unlock()
145 ASSERT(m_mutex
.m_recursionCount
);
146 --m_mutex
.m_recursionCount
;
148 int result
= pthread_mutex_unlock(&m_mutex
.m_internalMutex
);
149 ASSERT_UNUSED(result
, !result
);
152 // There is a separate tryLock implementation for the Mutex and the
153 // RecursiveMutex since on Windows we need to manually check if tryLock should
154 // succeed or not for the non-recursive mutex. On Linux the two implementations
155 // are equal except we can assert the recursion count is always zero for the
156 // non-recursive mutex.
157 bool Mutex::tryLock()
159 int result
= pthread_mutex_trylock(&m_mutex
.m_internalMutex
);
162 // The Mutex class is not recursive, so the recursionCount should be
163 // zero after getting the lock.
164 ASSERT(!m_mutex
.m_recursionCount
);
165 ++m_mutex
.m_recursionCount
;
172 ASSERT_NOT_REACHED();
176 bool RecursiveMutex::tryLock()
178 int result
= pthread_mutex_trylock(&m_mutex
.m_internalMutex
);
181 ++m_mutex
.m_recursionCount
;
188 ASSERT_NOT_REACHED();
192 ThreadCondition::ThreadCondition()
194 pthread_cond_init(&m_condition
, NULL
);
197 ThreadCondition::~ThreadCondition()
199 pthread_cond_destroy(&m_condition
);
202 void ThreadCondition::wait(MutexBase
& mutex
)
204 PlatformMutex
& platformMutex
= mutex
.impl();
205 int result
= pthread_cond_wait(&m_condition
, &platformMutex
.m_internalMutex
);
206 ASSERT_UNUSED(result
, !result
);
208 ++platformMutex
.m_recursionCount
;
212 bool ThreadCondition::timedWait(MutexBase
& mutex
, double absoluteTime
)
214 if (absoluteTime
< currentTime())
217 if (absoluteTime
> INT_MAX
) {
222 int timeSeconds
= static_cast<int>(absoluteTime
);
223 int timeNanoseconds
= static_cast<int>((absoluteTime
- timeSeconds
) * 1E9
);
226 targetTime
.tv_sec
= timeSeconds
;
227 targetTime
.tv_nsec
= timeNanoseconds
;
229 PlatformMutex
& platformMutex
= mutex
.impl();
230 int result
= pthread_cond_timedwait(&m_condition
, &platformMutex
.m_internalMutex
, &targetTime
);
232 ++platformMutex
.m_recursionCount
;
237 void ThreadCondition::signal()
239 int result
= pthread_cond_signal(&m_condition
);
240 ASSERT_UNUSED(result
, !result
);
243 void ThreadCondition::broadcast()
245 int result
= pthread_cond_broadcast(&m_condition
);
246 ASSERT_UNUSED(result
, !result
);
250 static bool s_threadCreated
= false;
252 bool isAtomicallyInitializedStaticMutexLockHeld()
254 return atomicallyInitializedStaticMutex
&& atomicallyInitializedStaticMutex
->locked();
257 bool isBeforeThreadCreated()
259 return !s_threadCreated
;
262 void willCreateThread()
264 s_threadCreated
= true;
270 #endif // USE(PTHREADS)