<rdar://problem/6467376> Race condition in WTF::currentThread can lead to a thread...
[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 identifierByPthreadHandle(const pthread_t& pthreadHandle)
90 {
91     MutexLocker locker(threadMapMutex());
92
93     ThreadMap::iterator i = threadMap().begin();
94     for (; i != threadMap().end(); ++i) {
95         if (pthread_equal(i->second, pthreadHandle))
96             return i->first;
97     }
98
99     return 0;
100 }
101
102 static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle)
103 {
104     ASSERT(!identifierByPthreadHandle(pthreadHandle));
105
106     MutexLocker locker(threadMapMutex());
107
108     static ThreadIdentifier identifierCount = 1;
109
110     threadMap().add(identifierCount, pthreadHandle);
111     
112     return identifierCount++;
113 }
114
115 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
116 {
117     MutexLocker locker(threadMapMutex());
118     
119     return threadMap().get(id);
120 }
121
122 static void clearPthreadHandleForIdentifier(ThreadIdentifier id)
123 {
124     MutexLocker locker(threadMapMutex());
125
126     ASSERT(threadMap().contains(id));
127     
128     threadMap().remove(id);
129 }
130
131 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
132 {
133     pthread_t threadHandle;
134     if (pthread_create(&threadHandle, NULL, entryPoint, data)) {
135         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
136         return 0;
137     }
138
139     return establishIdentifierForPthreadHandle(threadHandle);
140 }
141
142 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
143 {
144     ASSERT(threadID);
145     
146     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
147  
148     int joinResult = pthread_join(pthreadHandle, result);
149     if (joinResult == EDEADLK)
150         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
151         
152     clearPthreadHandleForIdentifier(threadID);
153     return joinResult;
154 }
155
156 void detachThread(ThreadIdentifier threadID)
157 {
158     ASSERT(threadID);
159     
160     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
161     
162     pthread_detach(pthreadHandle);
163     
164     clearPthreadHandleForIdentifier(threadID);
165 }
166
167 ThreadIdentifier currentThread()
168 {
169     pthread_t currentThread = pthread_self();
170     if (ThreadIdentifier id = identifierByPthreadHandle(currentThread))
171         return id;
172     return establishIdentifierForPthreadHandle(currentThread);
173 }
174
175 bool isMainThread()
176 {
177 #if PLATFORM(DARWIN)
178     return pthread_main_np();
179 #else
180     return currentThread() == mainThreadIdentifier;
181 #endif
182 }
183
184 Mutex::Mutex()
185 {
186     pthread_mutex_init(&m_mutex, NULL);
187 }
188
189 Mutex::~Mutex()
190 {
191     pthread_mutex_destroy(&m_mutex);
192 }
193
194 void Mutex::lock()
195 {
196     if (pthread_mutex_lock(&m_mutex) != 0)
197         ASSERT(false);
198 }
199     
200 bool Mutex::tryLock()
201 {
202     int result = pthread_mutex_trylock(&m_mutex);
203     
204     if (result == 0)
205         return true;
206     else if (result == EBUSY)
207         return false;
208
209     ASSERT(false);
210     return false;
211 }
212
213 void Mutex::unlock()
214 {
215     if (pthread_mutex_unlock(&m_mutex) != 0)
216         ASSERT(false);
217 }
218
219 ThreadCondition::ThreadCondition()
220
221     pthread_cond_init(&m_condition, NULL);
222 }
223
224 ThreadCondition::~ThreadCondition()
225 {
226     pthread_cond_destroy(&m_condition);
227 }
228     
229 void ThreadCondition::wait(Mutex& mutex)
230 {
231     if (pthread_cond_wait(&m_condition, &mutex.impl()) != 0)
232         ASSERT(false);
233 }
234
235 bool ThreadCondition::timedWait(Mutex& mutex, double secondsToWait)
236 {
237     if (secondsToWait < 0.0) {
238         wait(mutex);
239         return true;
240     }
241
242     int intervalSeconds = static_cast<int>(secondsToWait);
243     int intervalMicroseconds = static_cast<int>((secondsToWait - intervalSeconds) * 1000000.0);
244
245     // Current time comes in sec/microsec
246     timeval currentTime;
247     gettimeofday(&currentTime, NULL);
248
249     // Target time comes in sec/nanosec
250     timespec targetTime;
251     targetTime.tv_sec = currentTime.tv_sec + intervalSeconds;
252     targetTime.tv_nsec = (currentTime.tv_usec + intervalMicroseconds) * 1000;
253     if (targetTime.tv_nsec > 1000000000) {
254         targetTime.tv_nsec -= 1000000000;
255         targetTime.tv_sec++;
256     }
257
258     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
259 }
260
261 void ThreadCondition::signal()
262 {
263     if (pthread_cond_signal(&m_condition) != 0)
264         ASSERT(false);
265 }
266
267 void ThreadCondition::broadcast()
268 {
269     if (pthread_cond_broadcast(&m_condition) != 0)
270         ASSERT(false);
271 }
272     
273 } // namespace WTF
274
275 #endif // USE(PTHREADS)