initial import
[vuplus_webkit] / 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 "DateMath.h"
37 #include "dtoa.h"
38 #include "dtoa/cached-powers.h"
39 #include "HashMap.h"
40 #include "RandomNumberSeed.h"
41 #include "StdLibExtras.h"
42 #include "ThreadIdentifierDataPthreads.h"
43 #include "ThreadSpecific.h"
44 #include "UnusedParam.h"
45 #include <wtf/WTFThreadData.h>
46 #include <errno.h>
47
48 #if !COMPILER(MSVC)
49 #include <limits.h>
50 #include <sched.h>
51 #include <sys/time.h>
52 #endif
53
54 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
55 #include <objc/objc-auto.h>
56 #endif
57
58 namespace WTF {
59
60 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
61
62 static Mutex* atomicallyInitializedStaticMutex;
63
64 void clearPthreadHandleForIdentifier(ThreadIdentifier);
65
66 static Mutex& threadMapMutex()
67 {
68     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
69     return mutex;
70 }
71
72 void initializeThreading()
73 {
74     if (atomicallyInitializedStaticMutex)
75         return;
76
77     WTF::double_conversion::initialize();
78     // StringImpl::empty() does not construct its static string in a threadsafe fashion,
79     // so ensure it has been initialized from here.
80     StringImpl::empty();
81     atomicallyInitializedStaticMutex = new Mutex;
82     threadMapMutex();
83     initializeRandomNumberGenerator();
84     ThreadIdentifierData::initializeOnce();
85     wtfThreadData();
86 #if ENABLE(WTF_MULTIPLE_THREADS)
87     s_dtoaP5Mutex = new Mutex;
88     initializeDates();
89 #endif
90 }
91
92 void lockAtomicallyInitializedStaticMutex()
93 {
94     ASSERT(atomicallyInitializedStaticMutex);
95     atomicallyInitializedStaticMutex->lock();
96 }
97
98 void unlockAtomicallyInitializedStaticMutex()
99 {
100     atomicallyInitializedStaticMutex->unlock();
101 }
102
103 static ThreadMap& threadMap()
104 {
105     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
106     return map;
107 }
108
109 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
110 {
111     MutexLocker locker(threadMapMutex());
112
113     ThreadMap::iterator i = threadMap().begin();
114     for (; i != threadMap().end(); ++i) {
115         if (pthread_equal(i->second, pthreadHandle))
116             return i->first;
117     }
118
119     return 0;
120 }
121
122 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
123 {
124     ASSERT(!identifierByPthreadHandle(pthreadHandle));
125
126     MutexLocker locker(threadMapMutex());
127
128     static ThreadIdentifier identifierCount = 1;
129
130     threadMap().add(identifierCount, pthreadHandle);
131
132     return identifierCount++;
133 }
134
135 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
136 {
137     MutexLocker locker(threadMapMutex());
138
139     return threadMap().get(id);
140 }
141
142 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
143 {
144     MutexLocker locker(threadMapMutex());
145
146     ASSERT(threadMap().contains(id));
147
148     threadMap().remove(id);
149 }
150
151 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
152 {
153     pthread_t threadHandle;
154     if (pthread_create(&threadHandle, 0, entryPoint, data)) {
155         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
156         return 0;
157     }
158
159     return establishIdentifierForPthreadHandle(threadHandle);
160 }
161
162 void initializeCurrentThreadInternal(const char* threadName)
163 {
164 #if HAVE(PTHREAD_SETNAME_NP)
165     pthread_setname_np(threadName);
166 #else
167     UNUSED_PARAM(threadName);
168 #endif
169
170 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
171     // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
172     // garbage collector in case API implementations use garbage-collected memory.
173     objc_registerThreadWithCollector();
174 #endif
175
176     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
177     ASSERT(id);
178     ThreadIdentifierData::initialize(id);
179 }
180
181 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
182 {
183     ASSERT(threadID);
184
185     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
186     if (!pthreadHandle)
187         return 0;
188
189     int joinResult = pthread_join(pthreadHandle, result);
190     if (joinResult == EDEADLK)
191         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
192
193     return joinResult;
194 }
195
196 void detachThread(ThreadIdentifier threadID)
197 {
198     ASSERT(threadID);
199
200     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
201     if (!pthreadHandle)
202         return;
203
204     pthread_detach(pthreadHandle);
205 }
206
207 void yield()
208 {
209     sched_yield();
210 }
211
212 ThreadIdentifier currentThread()
213 {
214     ThreadIdentifier id = ThreadIdentifierData::identifier();
215     if (id)
216         return id;
217
218     // Not a WTF-created thread, ThreadIdentifier is not established yet.
219     id = establishIdentifierForPthreadHandle(pthread_self());
220     ThreadIdentifierData::initialize(id);
221     return id;
222 }
223
224 Mutex::Mutex()
225 {
226     pthread_mutexattr_t attr;
227     pthread_mutexattr_init(&attr);
228     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
229
230     pthread_mutex_init(&m_mutex, &attr);
231
232     pthread_mutexattr_destroy(&attr);
233 }
234
235 Mutex::~Mutex()
236 {
237     pthread_mutex_destroy(&m_mutex);
238 }
239
240 void Mutex::lock()
241 {
242     int result = pthread_mutex_lock(&m_mutex);
243     ASSERT_UNUSED(result, !result);
244 }
245
246 bool Mutex::tryLock()
247 {
248     int result = pthread_mutex_trylock(&m_mutex);
249
250     if (result == 0)
251         return true;
252     if (result == EBUSY)
253         return false;
254
255     ASSERT_NOT_REACHED();
256     return false;
257 }
258
259 void Mutex::unlock()
260 {
261     int result = pthread_mutex_unlock(&m_mutex);
262     ASSERT_UNUSED(result, !result);
263 }
264
265 #if HAVE(PTHREAD_RWLOCK)
266 ReadWriteLock::ReadWriteLock()
267 {
268     pthread_rwlock_init(&m_readWriteLock, NULL);
269 }
270
271 ReadWriteLock::~ReadWriteLock()
272 {
273     pthread_rwlock_destroy(&m_readWriteLock);
274 }
275
276 void ReadWriteLock::readLock()
277 {
278     int result = pthread_rwlock_rdlock(&m_readWriteLock);
279     ASSERT_UNUSED(result, !result);
280 }
281
282 bool ReadWriteLock::tryReadLock()
283 {
284     int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
285
286     if (result == 0)
287         return true;
288     if (result == EBUSY || result == EAGAIN)
289         return false;
290
291     ASSERT_NOT_REACHED();
292     return false;
293 }
294
295 void ReadWriteLock::writeLock()
296 {
297     int result = pthread_rwlock_wrlock(&m_readWriteLock);
298     ASSERT_UNUSED(result, !result);
299 }
300
301 bool ReadWriteLock::tryWriteLock()
302 {
303     int result = pthread_rwlock_trywrlock(&m_readWriteLock);
304
305     if (result == 0)
306         return true;
307     if (result == EBUSY || result == EAGAIN)
308         return false;
309
310     ASSERT_NOT_REACHED();
311     return false;
312 }
313
314 void ReadWriteLock::unlock()
315 {
316     int result = pthread_rwlock_unlock(&m_readWriteLock);
317     ASSERT_UNUSED(result, !result);
318 }
319 #endif  // HAVE(PTHREAD_RWLOCK)
320
321 ThreadCondition::ThreadCondition()
322
323     pthread_cond_init(&m_condition, NULL);
324 }
325
326 ThreadCondition::~ThreadCondition()
327 {
328     pthread_cond_destroy(&m_condition);
329 }
330     
331 void ThreadCondition::wait(Mutex& mutex)
332 {
333     int result = pthread_cond_wait(&m_condition, &mutex.impl());
334     ASSERT_UNUSED(result, !result);
335 }
336
337 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
338 {
339     if (absoluteTime < currentTime())
340         return false;
341
342     if (absoluteTime > INT_MAX) {
343         wait(mutex);
344         return true;
345     }
346
347     int timeSeconds = static_cast<int>(absoluteTime);
348     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
349
350     timespec targetTime;
351     targetTime.tv_sec = timeSeconds;
352     targetTime.tv_nsec = timeNanoseconds;
353
354     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
355 }
356
357 void ThreadCondition::signal()
358 {
359     int result = pthread_cond_signal(&m_condition);
360     ASSERT_UNUSED(result, !result);
361 }
362
363 void ThreadCondition::broadcast()
364 {
365     int result = pthread_cond_broadcast(&m_condition);
366     ASSERT_UNUSED(result, !result);
367 }
368
369 } // namespace WTF
370
371 #endif // USE(PTHREADS)