4ea9999030fb226baab2199bef45ede7dae7939f
[WebKit-https.git] / JavaScriptCore / wtf / ThreadingPthreads.cpp
1 /*
2  * Copyright (C) 2007 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 #include "config.h"
30 #include "Threading.h"
31
32 #include "StdLibExtras.h"
33
34 #if USE(PTHREADS)
35
36 #include "HashMap.h"
37 #include "MainThread.h"
38 #include "RandomNumberSeed.h"
39
40 #include <errno.h>
41 #include <sys/time.h>
42
43 namespace WTF {
44
45 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
46
47 static Mutex* atomicallyInitializedStaticMutex;
48
49 #if !PLATFORM(DARWIN)
50 static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread.
51 #endif
52
53 static Mutex& threadMapMutex()
54 {
55     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
56     return mutex;
57 }
58
59 void initializeThreading()
60 {
61     if (!atomicallyInitializedStaticMutex) {
62         atomicallyInitializedStaticMutex = new Mutex;
63         threadMapMutex();
64         initializeRandomNumberGenerator();
65 #if !PLATFORM(DARWIN)
66         mainThreadIdentifier = currentThread();
67 #endif
68         initializeMainThread();
69     }
70 }
71
72 void lockAtomicallyInitializedStaticMutex()
73 {
74     ASSERT(atomicallyInitializedStaticMutex);
75     atomicallyInitializedStaticMutex->lock();
76 }
77
78 void unlockAtomicallyInitializedStaticMutex()
79 {
80     atomicallyInitializedStaticMutex->unlock();
81 }
82
83 static ThreadMap& threadMap()
84 {
85     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
86     return map;
87 }
88
89 static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle)
90 {
91     MutexLocker locker(threadMapMutex());
92
93     static ThreadIdentifier identifierCount = 1;
94
95     threadMap().add(identifierCount, pthreadHandle);
96     
97     return identifierCount++;
98 }
99
100 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
101 {
102     MutexLocker locker(threadMapMutex());
103
104     ThreadMap::iterator i = threadMap().begin();
105     for (; i != threadMap().end(); ++i) {
106         if (pthread_equal(i->second, pthreadHandle))
107             return i->first;
108     }
109
110     return 0;
111 }
112
113 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
114 {
115     MutexLocker locker(threadMapMutex());
116     
117     return threadMap().get(id);
118 }
119
120 static void clearPthreadHandleForIdentifier(ThreadIdentifier id)
121 {
122     MutexLocker locker(threadMapMutex());
123
124     ASSERT(threadMap().contains(id));
125     
126     threadMap().remove(id);
127 }
128
129 ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char*)
130 {
131     pthread_t threadHandle;
132     if (pthread_create(&threadHandle, NULL, entryPoint, data)) {
133         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
134         return 0;
135     }
136
137     ThreadIdentifier threadID = establishIdentifierForPthreadHandle(threadHandle);
138     return threadID;
139 }
140
141 #if PLATFORM(MAC)
142 // This function is deprecated but needs to be kept around for backward
143 // compatibility. Use the 3-argument version of createThread above instead.
144 ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
145 {
146     return createThread(entryPoint, data, 0);
147 }
148 #endif
149
150 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
151 {
152     ASSERT(threadID);
153     
154     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
155  
156     int joinResult = pthread_join(pthreadHandle, result);
157     if (joinResult == EDEADLK)
158         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
159         
160     clearPthreadHandleForIdentifier(threadID);
161     return joinResult;
162 }
163
164 void detachThread(ThreadIdentifier threadID)
165 {
166     ASSERT(threadID);
167     
168     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
169     
170     pthread_detach(pthreadHandle);
171     
172     clearPthreadHandleForIdentifier(threadID);
173 }
174
175 ThreadIdentifier currentThread()
176 {
177     pthread_t currentThread = pthread_self();
178     if (ThreadIdentifier id = identifierByPthreadHandle(currentThread))
179         return id;
180     return establishIdentifierForPthreadHandle(currentThread);
181 }
182
183 bool isMainThread()
184 {
185 #if PLATFORM(DARWIN)
186     return pthread_main_np();
187 #else
188     return currentThread() == mainThreadIdentifier;
189 #endif
190 }
191
192 Mutex::Mutex()
193 {
194     pthread_mutex_init(&m_mutex, NULL);
195 }
196
197 Mutex::~Mutex()
198 {
199     pthread_mutex_destroy(&m_mutex);
200 }
201
202 void Mutex::lock()
203 {
204     if (pthread_mutex_lock(&m_mutex) != 0)
205         ASSERT(false);
206 }
207     
208 bool Mutex::tryLock()
209 {
210     int result = pthread_mutex_trylock(&m_mutex);
211     
212     if (result == 0)
213         return true;
214     else if (result == EBUSY)
215         return false;
216
217     ASSERT(false);
218     return false;
219 }
220
221 void Mutex::unlock()
222 {
223     if (pthread_mutex_unlock(&m_mutex) != 0)
224         ASSERT(false);
225 }
226                 
227 ThreadCondition::ThreadCondition()
228
229     pthread_cond_init(&m_condition, NULL);
230 }
231
232 ThreadCondition::~ThreadCondition()
233 {
234     pthread_cond_destroy(&m_condition);
235 }
236     
237 void ThreadCondition::wait(Mutex& mutex)
238 {
239     if (pthread_cond_wait(&m_condition, &mutex.impl()) != 0)
240         ASSERT(false);
241 }
242
243 bool ThreadCondition::timedWait(Mutex& mutex, double secondsToWait)
244 {
245     if (secondsToWait < 0.0) {
246         wait(mutex);
247         return true;
248     }
249
250     int intervalSeconds = static_cast<int>(secondsToWait);
251     int intervalMicroseconds = static_cast<int>((secondsToWait - intervalSeconds) * 1000000.0);
252
253     // Current time comes in sec/microsec
254     timeval currentTime;
255     gettimeofday(&currentTime, NULL);
256
257     // Target time comes in sec/nanosec
258     timespec targetTime;
259     targetTime.tv_sec = currentTime.tv_sec + intervalSeconds;
260     targetTime.tv_nsec = (currentTime.tv_usec + intervalMicroseconds) * 1000;
261     if (targetTime.tv_nsec > 1000000000) {
262         targetTime.tv_nsec -= 1000000000;
263         targetTime.tv_sec++;
264     }
265
266     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
267 }
268
269 void ThreadCondition::signal()
270 {
271     if (pthread_cond_signal(&m_condition) != 0)
272         ASSERT(false);
273 }
274
275 void ThreadCondition::broadcast()
276 {
277     if (pthread_cond_broadcast(&m_condition) != 0)
278         ASSERT(false);
279 }
280     
281 } // namespace WTF
282
283 #endif // USE(PTHREADS)