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