b1310dd79b91f29b6a9e264a5a246291bfac8d3b
[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     threadMap().add(threadID, threadHandle);
154 }
155
156 static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
157 {
158     MutexLocker locker(threadMapMutex());
159     return threadMap().get(id);
160 }
161
162 static void clearThreadHandleForIdentifier(ThreadIdentifier id)
163 {
164     MutexLocker locker(threadMapMutex());
165     ASSERT(threadMap().contains(id));
166     threadMap().remove(id);
167 }
168
169 struct ThreadFunctionInvocation {
170     ThreadFunctionInvocation(ThreadFunction function, void* data) : function(function), data(data) {}
171
172     ThreadFunction function;
173     void* data;
174 };
175
176 static unsigned __stdcall wtfThreadEntryPoint(void* param)
177 {
178     ThreadFunctionInvocation invocation = *static_cast<ThreadFunctionInvocation*>(param);
179     delete static_cast<ThreadFunctionInvocation*>(param);
180
181     void* result = invocation.function(invocation.data);
182
183 #if PLATFORM(WIN) && USE(PTHREADS)
184     // pthreads-win32 knows how to work with threads created with Win32 or CRT functions, so it's OK to mix APIs.
185     pthread_exit(result);
186 #endif
187
188     return reinterpret_cast<unsigned>(result);
189 }
190
191 ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* threadName)
192 {
193     unsigned threadIdentifier = 0;
194     ThreadIdentifier threadID = 0;
195     ThreadFunctionInvocation* invocation = new ThreadFunctionInvocation(entryPoint, data);
196     HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation, 0, &threadIdentifier));
197     if (!threadHandle) {
198         LOG_ERROR("Failed to create thread at entry point %p with data %p: %ld", entryPoint, data, errno);
199         return 0;
200     }
201
202     if (threadName)
203         setThreadName(threadIdentifier, threadName);
204
205     threadID = static_cast<ThreadIdentifier>(threadIdentifier);
206     storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
207
208     return threadID;
209 }
210
211 // This function is deprecated but needs to be kept around for backward
212 // compatibility. Use the 3-argument version of createThread above.
213 ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
214 {
215     return createThread(entryPoint, data, 0);
216 }
217
218 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
219 {
220     ASSERT(threadID);
221     
222     HANDLE threadHandle = threadHandleForIdentifier(threadID);
223     if (!threadHandle)
224         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
225  
226     DWORD joinResult = ::WaitForSingleObject(threadHandle, INFINITE);
227     if (joinResult == WAIT_FAILED)
228         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
229
230     ::CloseHandle(threadHandle);
231     clearThreadHandleForIdentifier(threadID);
232
233     return joinResult;
234 }
235
236 void detachThread(ThreadIdentifier threadID)
237 {
238     ASSERT(threadID);
239     
240     HANDLE threadHandle = threadHandleForIdentifier(threadID);
241     if (threadHandle)
242         ::CloseHandle(threadHandle);
243     clearThreadHandleForIdentifier(threadID);
244 }
245
246 ThreadIdentifier currentThread()
247 {
248     return static_cast<ThreadIdentifier>(::GetCurrentThreadId());
249 }
250
251 bool isMainThread()
252 {
253     return currentThread() == mainThreadIdentifier;
254 }
255
256 Mutex::Mutex()
257 {
258     m_mutex.m_recursionCount = 0;
259     ::InitializeCriticalSection(&m_mutex.m_internalMutex);
260 }
261
262 Mutex::~Mutex()
263 {
264     ::DeleteCriticalSection(&m_mutex.m_internalMutex);
265 }
266
267 void Mutex::lock()
268 {
269     ::EnterCriticalSection(&m_mutex.m_internalMutex);
270     ++m_mutex.m_recursionCount;
271 }
272     
273 bool Mutex::tryLock()
274 {
275     // This method is modeled after the behavior of pthread_mutex_trylock,
276     // which will return an error if the lock is already owned by the
277     // current thread.  Since the primitive Win32 'TryEnterCriticalSection'
278     // treats this as a successful case, it changes the behavior of several
279     // tests in WebKit that check to see if the current thread already
280     // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
281     DWORD result = ::TryEnterCriticalSection(&m_mutex.m_internalMutex);
282     
283     if (result != 0) {       // We got the lock
284         // If this thread already had the lock, we must unlock and
285         // return false so that we mimic the behavior of POSIX's
286         // pthread_mutex_trylock:
287         if (m_mutex.m_recursionCount > 0) {
288             ::LeaveCriticalSection(&m_mutex.m_internalMutex);
289             return false;
290         }
291
292         ++m_mutex.m_recursionCount;
293         return true;
294     }
295
296     return false;
297 }
298
299 void Mutex::unlock()
300 {
301     --m_mutex.m_recursionCount;
302     ::LeaveCriticalSection(&m_mutex.m_internalMutex);
303 }
304
305 static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
306
307 ThreadCondition::ThreadCondition()
308 {
309     m_condition.m_timedOut = 0;
310     m_condition.m_blocked = 0;
311     m_condition.m_waitingForRemoval = 0;
312     m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0);
313     m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
314     m_condition.m_mutex = ::CreateMutex(0, 0, 0);
315
316     if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) {
317         if (m_condition.m_gate)
318             ::CloseHandle(m_condition.m_gate);
319         if (m_condition.m_queue)
320             ::CloseHandle(m_condition.m_queue);
321         if (m_condition.m_mutex)
322             ::CloseHandle(m_condition.m_mutex);
323     }
324 }
325
326 ThreadCondition::~ThreadCondition()
327 {
328     ::CloseHandle(m_condition.m_gate);
329     ::CloseHandle(m_condition.m_queue);
330     ::CloseHandle(m_condition.m_mutex);
331 }
332     
333 void ThreadCondition::wait(Mutex& mutex)
334 {
335     PlatformMutex& cs = mutex.impl();
336
337     // Enter the wait state.
338     DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
339     ASSERT(res == WAIT_OBJECT_0);
340     ++m_condition.m_blocked;
341     res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
342     ASSERT(res);
343
344     ::LeaveCriticalSection(&cs.m_internalMutex);
345
346     res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
347     ASSERT(res == WAIT_OBJECT_0);
348
349     res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
350     ASSERT(res == WAIT_OBJECT_0);
351     size_t wasWaiting = m_condition.m_waitingForRemoval;
352     size_t wasTimedOut = m_condition.m_timedOut;
353     if (wasWaiting != 0) {
354         if (--m_condition.m_waitingForRemoval == 0) {
355             if (m_condition.m_blocked != 0) {
356                 res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);  // open m_gate
357                 ASSERT(res);
358                 wasWaiting = 0;
359             }
360             else if (m_condition.m_timedOut != 0)
361                 m_condition.m_timedOut = 0;
362         }
363     } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) {
364         // timeout occured, normalize the m_condition.m_timedOut count
365         // this may occur if many calls to wait with a timeout are made and
366         // no call to notify_* is made
367         res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
368         ASSERT(res == WAIT_OBJECT_0);
369         m_condition.m_blocked -= m_condition.m_timedOut;
370         res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
371         ASSERT(res);
372         m_condition.m_timedOut = 0;
373     }
374     res = ::ReleaseMutex(m_condition.m_mutex);
375     ASSERT(res);
376
377     if (wasWaiting == 1) {
378         for (/**/ ; wasTimedOut; --wasTimedOut) {
379             // better now than spurious later
380             res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
381             ASSERT(res == WAIT_OBJECT_0);
382         }
383         res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
384         ASSERT(res);
385     }
386
387     ::EnterCriticalSection (&cs.m_internalMutex);
388 }
389
390 bool ThreadCondition::timedWait(Mutex& mutex, double interval)
391 {
392     // Empty for now
393     ASSERT(false);
394     return false;
395 }
396
397 void ThreadCondition::signal()
398 {
399     unsigned signals = 0;
400
401     DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
402     ASSERT(res == WAIT_OBJECT_0);
403
404     if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
405         if (m_condition.m_blocked == 0) {
406             res = ::ReleaseMutex(m_condition.m_mutex);
407             ASSERT(res);
408             return;
409         }
410
411         ++m_condition.m_waitingForRemoval;
412         --m_condition.m_blocked;
413
414         signals = 1;
415     } else {
416         res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
417         ASSERT(res == WAIT_OBJECT_0);
418         if (m_condition.m_blocked > m_condition.m_timedOut) {
419             if (m_condition.m_timedOut != 0) {
420                 m_condition.m_blocked -= m_condition.m_timedOut;
421                 m_condition.m_timedOut = 0;
422             }
423             signals = m_condition.m_waitingForRemoval = 1;
424             --m_condition.m_blocked;
425         } else {
426             res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
427             ASSERT(res);
428         }
429     }
430
431     res =::ReleaseMutex(m_condition.m_mutex);
432     ASSERT(res);
433
434     if (signals) {
435         res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
436         ASSERT(res);
437     }
438 }
439
440 void ThreadCondition::broadcast()
441 {
442     unsigned signals = 0;
443
444     DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
445     ASSERT(res == WAIT_OBJECT_0);
446
447     if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
448         if (m_condition.m_blocked == 0) {
449             res = ::ReleaseMutex(m_condition.m_mutex);
450             ASSERT(res);
451             return;
452         }
453
454         m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked);
455         m_condition.m_blocked = 0;
456     } else {
457         res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
458         ASSERT(res == WAIT_OBJECT_0);
459         if (m_condition.m_blocked > m_condition.m_timedOut) {
460             if (m_condition.m_timedOut != 0) {
461                 m_condition.m_blocked -= m_condition.m_timedOut;
462                 m_condition.m_timedOut = 0;
463             }
464             signals = m_condition.m_waitingForRemoval = m_condition.m_blocked;
465             m_condition.m_blocked = 0;
466         } else {
467             res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
468             ASSERT(res);
469         }
470     }
471
472     res = ::ReleaseMutex(m_condition.m_mutex);
473     ASSERT(res);
474
475     if (signals) {
476         res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
477         ASSERT(res);
478     }
479 }
480
481 } // namespace WTF