<rdar://problem/6467376> Race condition in WTF::currentThread can lead to a thread...
[WebKit-https.git] / JavaScriptCore / wtf / ThreadingGtk.cpp
1 /*
2  * Copyright (C) 2007, 2008 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 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 "HashMap.h"
36 #include "MainThread.h"
37 #include "RandomNumberSeed.h"
38
39 #include <glib.h>
40
41 namespace WTF {
42
43 static Mutex* atomicallyInitializedStaticMutex;
44
45 static ThreadIdentifier mainThreadIdentifier;
46
47 static Mutex& threadMapMutex()
48 {
49     static Mutex mutex;
50     return mutex;
51 }
52
53 void initializeThreading()
54 {
55     if (!g_thread_supported())
56         g_thread_init(NULL);
57     ASSERT(g_thread_supported());
58
59     if (!atomicallyInitializedStaticMutex) {
60         atomicallyInitializedStaticMutex = new Mutex;
61         threadMapMutex();
62         initializeRandomNumberGenerator();
63         mainThreadIdentifier = currentThread();
64         initializeMainThread();
65     }
66 }
67
68 void lockAtomicallyInitializedStaticMutex()
69 {
70     ASSERT(atomicallyInitializedStaticMutex);
71     atomicallyInitializedStaticMutex->lock();
72 }
73
74 void unlockAtomicallyInitializedStaticMutex()
75 {
76     atomicallyInitializedStaticMutex->unlock();
77 }
78
79 static HashMap<ThreadIdentifier, GThread*>& threadMap()
80 {
81     static HashMap<ThreadIdentifier, GThread*> map;
82     return map;
83 }
84
85 static ThreadIdentifier identifierByGthreadHandle(GThread*& thread)
86 {
87     MutexLocker locker(threadMapMutex());
88
89     HashMap<ThreadIdentifier, GThread*>::iterator i = threadMap().begin();
90     for (; i != threadMap().end(); ++i) {
91         if (i->second == thread)
92             return i->first;
93     }
94
95     return 0;
96 }
97
98 static ThreadIdentifier establishIdentifierForThread(GThread*& thread)
99 {
100     ASSERT(!identifierByGthreadHandle(thread));
101
102     MutexLocker locker(threadMapMutex());
103
104     static ThreadIdentifier identifierCount = 1;
105
106     threadMap().add(identifierCount, thread);
107
108     return identifierCount++;
109 }
110
111 static GThread* threadForIdentifier(ThreadIdentifier id)
112 {
113     MutexLocker locker(threadMapMutex());
114
115     return threadMap().get(id);
116 }
117
118 static void clearThreadForIdentifier(ThreadIdentifier id)
119 {
120     MutexLocker locker(threadMapMutex());
121
122     ASSERT(threadMap().contains(id));
123
124     threadMap().remove(id);
125 }
126
127 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
128 {
129     GThread* thread;
130     if (!(thread = g_thread_create(entryPoint, data, TRUE, 0))) {
131         LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
132         return 0;
133     }
134
135     ThreadIdentifier threadID = establishIdentifierForThread(thread);
136     return threadID;
137 }
138
139 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
140 {
141     ASSERT(threadID);
142
143     GThread* thread = threadForIdentifier(threadID);
144
145     void* joinResult = g_thread_join(thread);
146     if (result)
147         *result = joinResult;
148
149     clearThreadForIdentifier(threadID);
150     return 0;
151 }
152
153 void detachThread(ThreadIdentifier)
154 {
155 }
156
157 ThreadIdentifier currentThread()
158 {
159     GThread* currentThread = g_thread_self();
160     if (ThreadIdentifier id = identifierByGthreadHandle(currentThread))
161         return id;
162     return establishIdentifierForThread(currentThread);
163 }
164
165 bool isMainThread()
166 {
167     return currentThread() == mainThreadIdentifier;
168 }
169
170 Mutex::Mutex()
171     : m_mutex(g_mutex_new())
172 {
173 }
174
175 Mutex::~Mutex()
176 {
177 }
178
179 void Mutex::lock()
180 {
181     g_mutex_lock(m_mutex.get());
182 }
183
184 bool Mutex::tryLock()
185 {
186     return g_mutex_trylock(m_mutex.get());
187 }
188
189 void Mutex::unlock()
190 {
191     g_mutex_unlock(m_mutex.get());
192 }
193
194 ThreadCondition::ThreadCondition()
195     : m_condition(g_cond_new())
196 {
197 }
198
199 ThreadCondition::~ThreadCondition()
200 {
201 }
202
203 void ThreadCondition::wait(Mutex& mutex)
204 {
205     g_cond_wait(m_condition.get(), mutex.impl().get());
206 }
207
208 bool ThreadCondition::timedWait(Mutex& mutex, double interval)
209 {
210     if (interval < 0.0) {
211         wait(mutex);
212         return true;
213     }
214     
215     int intervalSeconds = static_cast<int>(interval);
216     int intervalMicroseconds = static_cast<int>((interval - intervalSeconds) * 1000000.0);
217     
218     GTimeVal targetTime;
219     g_get_current_time(&targetTime);
220         
221     targetTime.tv_sec += intervalSeconds;
222     targetTime.tv_usec += intervalMicroseconds;
223     if (targetTime.tv_usec > 1000000) {
224         targetTime.tv_usec -= 1000000;
225         targetTime.tv_sec++;
226     }
227
228     return g_cond_timed_wait(m_condition.get(), mutex.impl().get(), &targetTime);
229 }
230
231 void ThreadCondition::signal()
232 {
233     g_cond_signal(m_condition.get());
234 }
235
236 void ThreadCondition::broadcast()
237 {
238     g_cond_broadcast(m_condition.get());
239 }
240
241
242 }
243
244 #endif // !USE(PTHREADS)