<rdar://problem/6467376> Race condition in WTF::currentThread can lead to a thread...
[WebKit-https.git] / JavaScriptCore / wtf / ThreadingWin.cpp
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * =============================================================================
29  * Note:  The implementation of condition variables under the Windows
30  * plaform was based on that of the excellent BOOST C++ library.  It
31  * has been rewritten to fit in with the WebKit architecture and to
32  * use its coding conventions.
33  * =============================================================================
34  *
35  * The Boost license is virtually identical to the Apple variation at the
36  * top of this file, but is included here for completeness:
37  *
38  * Boost Software License - Version 1.0 - August 17th, 2003
39  *
40  * Permission is hereby granted, free of charge, to any person or organization
41  * obtaining a copy of the software and accompanying documentation covered by
42  * this license (the "Software") to use, reproduce, display, distribute,
43  * execute, and transmit the Software, and to prepare derivative works of the
44  * Software, and to permit third-parties to whom the Software is furnished to
45  * do so, all subject to the following:
46  *
47  * The copyright notices in the Software and this entire statement, including
48  * the above license grant, this restriction and the following disclaimer,
49  * must be included in all copies of the Software, in whole or in part, and
50  * all derivative works of the Software, unless such copies or derivative
51  * works are solely in the form of machine-executable object code generated by
52  * a source language processor.
53  *
54  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
57  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
58  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
59  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
60  * DEALINGS IN THE SOFTWARE.
61  */
62
63 #include "config.h"
64 #include "Threading.h"
65
66 #include "MainThread.h"
67 #include <process.h>
68 #include <windows.h>
69 #include <wtf/HashMap.h>
70 #include <wtf/MathExtras.h>
71 #include <wtf/RandomNumberSeed.h>
72
73 #if PLATFORM(WIN) && USE(PTHREADS)
74 // Currently, Apple's Windows port uses a mixture of native and pthreads functions in FastMalloc.
75 // To ensure that thread-specific data is properly destroyed, we need to end each thread with pthread_exit().
76 #include <pthread.h>
77 #endif
78
79 namespace WTF {
80
81 // MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadName all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
82 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
83
84 #pragma pack(push, 8)
85 typedef struct tagTHREADNAME_INFO {
86     DWORD dwType; // must be 0x1000
87     LPCSTR szName; // pointer to name (in user addr space)
88     DWORD dwThreadID; // thread ID (-1=caller thread)
89     DWORD dwFlags; // reserved for future use, must be zero
90 } THREADNAME_INFO;
91 #pragma pack(pop)
92
93 static void setThreadName(DWORD dwThreadID, LPCSTR szThreadName)
94 {
95     // Visual Studio has a 31-character limit on thread names. Longer names will
96     // be truncated silently, but we'd like callers to know about the limit.
97     ASSERT_ARG(szThreadName, strlen(szThreadName) <= 31);
98
99     THREADNAME_INFO info;
100     info.dwType = 0x1000;
101     info.szName = szThreadName;
102     info.dwThreadID = dwThreadID;
103     info.dwFlags = 0;
104
105     __try {
106         RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
107     } __except (EXCEPTION_CONTINUE_EXECUTION) {
108     }
109 }
110
111 static Mutex* atomicallyInitializedStaticMutex;
112
113 void lockAtomicallyInitializedStaticMutex()
114 {
115     ASSERT(atomicallyInitializedStaticMutex);
116     atomicallyInitializedStaticMutex->lock();
117 }
118
119 void unlockAtomicallyInitializedStaticMutex()
120 {
121     atomicallyInitializedStaticMutex->unlock();
122 }
123
124 static ThreadIdentifier mainThreadIdentifier;
125
126 static Mutex& threadMapMutex()
127 {
128     static Mutex mutex;
129     return mutex;
130 }
131
132 void initializeThreading()
133 {
134     if (!atomicallyInitializedStaticMutex) {
135         atomicallyInitializedStaticMutex = new Mutex;
136         threadMapMutex();
137         initializeRandomNumberGenerator();
138         initializeMainThread();
139         mainThreadIdentifier = currentThread();
140         setThreadName(mainThreadIdentifier, "Main Thread");
141     }
142 }
143
144 static HashMap<DWORD, HANDLE>& threadMap()
145 {
146     static HashMap<DWORD, HANDLE> map;
147     return map;
148 }
149
150 static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle)
151 {
152     MutexLocker locker(threadMapMutex());
153     ASSERT(!threadMap().contains(threadID));
154     threadMap().add(threadID, threadHandle);
155 }
156
157 static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
158 {
159     MutexLocker locker(threadMapMutex());
160     return threadMap().get(id);
161 }
162
163 static void clearThreadHandleForIdentifier(ThreadIdentifier id)
164 {
165     MutexLocker locker(threadMapMutex());
166     ASSERT(threadMap().contains(id));
167     threadMap().remove(id);
168 }
169
170 struct ThreadFunctionInvocation {
171     ThreadFunctionInvocation(ThreadFunction function, void* data) : function(function), data(data) {}
172
173     ThreadFunction function;
174     void* data;
175 };
176
177 static unsigned __stdcall wtfThreadEntryPoint(void* param)
178 {
179     ThreadFunctionInvocation invocation = *static_cast<ThreadFunctionInvocation*>(param);
180     delete static_cast<ThreadFunctionInvocation*>(param);
181
182     void* result = invocation.function(invocation.data);
183
184 #if PLATFORM(WIN) && USE(PTHREADS)
185     // pthreads-win32 knows how to work with threads created with Win32 or CRT functions, so it's OK to mix APIs.
186     pthread_exit(result);
187 #endif
188
189     return reinterpret_cast<unsigned>(result);
190 }
191
192 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
193 {
194     unsigned threadIdentifier = 0;
195     ThreadIdentifier threadID = 0;
196     ThreadFunctionInvocation* invocation = new ThreadFunctionInvocation(entryPoint, data);
197     HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation, 0, &threadIdentifier));
198     if (!threadHandle) {
199         LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno);
200         return 0;
201     }
202
203     if (threadName)
204         setThreadName(threadIdentifier, threadName);
205
206     threadID = static_cast<ThreadIdentifier>(threadIdentifier);
207     storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
208
209     return threadID;
210 }
211
212 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
213 {
214     ASSERT(threadID);
215     
216     HANDLE threadHandle = threadHandleForIdentifier(threadID);
217     if (!threadHandle)
218         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
219  
220     DWORD joinResult = ::WaitForSingleObject(threadHandle, INFINITE);
221     if (joinResult == WAIT_FAILED)
222         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
223
224     ::CloseHandle(threadHandle);
225     clearThreadHandleForIdentifier(threadID);
226
227     return joinResult;
228 }
229
230 void detachThread(ThreadIdentifier threadID)
231 {
232     ASSERT(threadID);
233     
234     HANDLE threadHandle = threadHandleForIdentifier(threadID);
235     if (threadHandle)
236         ::CloseHandle(threadHandle);
237     clearThreadHandleForIdentifier(threadID);
238 }
239
240 ThreadIdentifier currentThread()
241 {
242     return static_cast<ThreadIdentifier>(::GetCurrentThreadId());
243 }
244
245 bool isMainThread()
246 {
247     return currentThread() == mainThreadIdentifier;
248 }
249
250 Mutex::Mutex()
251 {
252     m_mutex.m_recursionCount = 0;
253     ::InitializeCriticalSection(&m_mutex.m_internalMutex);
254 }
255
256 Mutex::~Mutex()
257 {
258     ::DeleteCriticalSection(&m_mutex.m_internalMutex);
259 }
260
261 void Mutex::lock()
262 {
263     ::EnterCriticalSection(&m_mutex.m_internalMutex);
264     ++m_mutex.m_recursionCount;
265 }
266     
267 bool Mutex::tryLock()
268 {
269     // This method is modeled after the behavior of pthread_mutex_trylock,
270     // which will return an error if the lock is already owned by the
271     // current thread.  Since the primitive Win32 'TryEnterCriticalSection'
272     // treats this as a successful case, it changes the behavior of several
273     // tests in WebKit that check to see if the current thread already
274     // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
275     DWORD result = ::TryEnterCriticalSection(&m_mutex.m_internalMutex);
276     
277     if (result != 0) {       // We got the lock
278         // If this thread already had the lock, we must unlock and
279         // return false so that we mimic the behavior of POSIX's
280         // pthread_mutex_trylock:
281         if (m_mutex.m_recursionCount > 0) {
282             ::LeaveCriticalSection(&m_mutex.m_internalMutex);
283             return false;
284         }
285
286         ++m_mutex.m_recursionCount;
287         return true;
288     }
289
290     return false;
291 }
292
293 void Mutex::unlock()
294 {
295     --m_mutex.m_recursionCount;
296     ::LeaveCriticalSection(&m_mutex.m_internalMutex);
297 }
298
299 static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
300
301 ThreadCondition::ThreadCondition()
302 {
303     m_condition.m_timedOut = 0;
304     m_condition.m_blocked = 0;
305     m_condition.m_waitingForRemoval = 0;
306     m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0);
307     m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
308     m_condition.m_mutex = ::CreateMutex(0, 0, 0);
309
310     if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) {
311         if (m_condition.m_gate)
312             ::CloseHandle(m_condition.m_gate);
313         if (m_condition.m_queue)
314             ::CloseHandle(m_condition.m_queue);
315         if (m_condition.m_mutex)
316             ::CloseHandle(m_condition.m_mutex);
317     }
318 }
319
320 ThreadCondition::~ThreadCondition()
321 {
322     ::CloseHandle(m_condition.m_gate);
323     ::CloseHandle(m_condition.m_queue);
324     ::CloseHandle(m_condition.m_mutex);
325 }
326     
327 void ThreadCondition::wait(Mutex& mutex)
328 {
329     PlatformMutex& cs = mutex.impl();
330
331     // Enter the wait state.
332     DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
333     ASSERT(res == WAIT_OBJECT_0);
334     ++m_condition.m_blocked;
335     res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
336     ASSERT(res);
337
338     ::LeaveCriticalSection(&cs.m_internalMutex);
339
340     res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
341     ASSERT(res == WAIT_OBJECT_0);
342
343     res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
344     ASSERT(res == WAIT_OBJECT_0);
345     size_t wasWaiting = m_condition.m_waitingForRemoval;
346     size_t wasTimedOut = m_condition.m_timedOut;
347     if (wasWaiting != 0) {
348         if (--m_condition.m_waitingForRemoval == 0) {
349             if (m_condition.m_blocked != 0) {
350                 res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);  // open m_gate
351                 ASSERT(res);
352                 wasWaiting = 0;
353             }
354             else if (m_condition.m_timedOut != 0)
355                 m_condition.m_timedOut = 0;
356         }
357     } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) {
358         // timeout occured, normalize the m_condition.m_timedOut count
359         // this may occur if many calls to wait with a timeout are made and
360         // no call to notify_* is made
361         res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
362         ASSERT(res == WAIT_OBJECT_0);
363         m_condition.m_blocked -= m_condition.m_timedOut;
364         res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
365         ASSERT(res);
366         m_condition.m_timedOut = 0;
367     }
368     res = ::ReleaseMutex(m_condition.m_mutex);
369     ASSERT(res);
370
371     if (wasWaiting == 1) {
372         for (/**/ ; wasTimedOut; --wasTimedOut) {
373             // better now than spurious later
374             res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
375             ASSERT(res == WAIT_OBJECT_0);
376         }
377         res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
378         ASSERT(res);
379     }
380
381     ::EnterCriticalSection (&cs.m_internalMutex);
382 }
383
384 bool ThreadCondition::timedWait(Mutex& mutex, double interval)
385 {
386     // Empty for now
387     ASSERT(false);
388     return false;
389 }
390
391 void ThreadCondition::signal()
392 {
393     unsigned signals = 0;
394
395     DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
396     ASSERT(res == WAIT_OBJECT_0);
397
398     if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
399         if (m_condition.m_blocked == 0) {
400             res = ::ReleaseMutex(m_condition.m_mutex);
401             ASSERT(res);
402             return;
403         }
404
405         ++m_condition.m_waitingForRemoval;
406         --m_condition.m_blocked;
407
408         signals = 1;
409     } else {
410         res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
411         ASSERT(res == WAIT_OBJECT_0);
412         if (m_condition.m_blocked > m_condition.m_timedOut) {
413             if (m_condition.m_timedOut != 0) {
414                 m_condition.m_blocked -= m_condition.m_timedOut;
415                 m_condition.m_timedOut = 0;
416             }
417             signals = m_condition.m_waitingForRemoval = 1;
418             --m_condition.m_blocked;
419         } else {
420             res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
421             ASSERT(res);
422         }
423     }
424
425     res =::ReleaseMutex(m_condition.m_mutex);
426     ASSERT(res);
427
428     if (signals) {
429         res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
430         ASSERT(res);
431     }
432 }
433
434 void ThreadCondition::broadcast()
435 {
436     unsigned signals = 0;
437
438     DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
439     ASSERT(res == WAIT_OBJECT_0);
440
441     if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
442         if (m_condition.m_blocked == 0) {
443             res = ::ReleaseMutex(m_condition.m_mutex);
444             ASSERT(res);
445             return;
446         }
447
448         m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked);
449         m_condition.m_blocked = 0;
450     } else {
451         res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
452         ASSERT(res == WAIT_OBJECT_0);
453         if (m_condition.m_blocked > m_condition.m_timedOut) {
454             if (m_condition.m_timedOut != 0) {
455                 m_condition.m_blocked -= m_condition.m_timedOut;
456                 m_condition.m_timedOut = 0;
457             }
458             signals = m_condition.m_waitingForRemoval = m_condition.m_blocked;
459             m_condition.m_blocked = 0;
460         } else {
461             res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
462             ASSERT(res);
463         }
464     }
465
466     res = ::ReleaseMutex(m_condition.m_mutex);
467     ASSERT(res);
468
469     if (signals) {
470         res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
471         ASSERT(res);
472     }
473 }
474
475 } // namespace WTF