9890e8ef023ee5aee5a7a97ef3abe4d4c962c0a3
[WebKit-https.git] / WebCore / platform / win / ThreadingWin.cpp
1 /*
2  * Copyright (C) 2007 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 #include "config.h"
30 #include "Logging.h"
31 #include "Page.h"
32 #include "Threading.h"
33 #include <errno.h>
34 #include <windows.h>
35 #include <wtf/HashMap.h>
36
37 namespace WebCore {
38
39 typedef Vector<void(*)()> FunctionQueue;
40
41 static HWND threadingWindowHandle = 0;
42 static UINT threadingFiredMessage = 0;
43 const LPCWSTR kThreadingWindowClassName = L"ThreadingWindowClass";
44 static bool processingCustomThreadingMessage = false;
45
46 static Mutex& threadMapMutex()
47 {
48     static Mutex mutex;
49     return mutex;
50 }
51
52 static HashMap<DWORD, HANDLE>& threadMap()
53 {
54     static HashMap<DWORD, HANDLE> map;
55     return map;
56 }
57
58 static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle)
59 {
60     MutexLocker locker(threadMapMutex());
61     threadMap().add(threadID, threadHandle);
62 }
63
64 static ThreadIdentifier identifierByThreadHandle(HANDLE threadHandle)
65 {
66     MutexLocker locker(threadMapMutex());
67
68     HashMap<DWORD, HANDLE>::iterator i = threadMap().begin();
69     for (; i != threadMap().end(); ++i) {
70         if (i->second == threadHandle)
71             return i->first;
72     }
73
74     return 0;
75 }
76
77 static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
78 {
79     MutexLocker locker(threadMapMutex());
80     return threadMap().get(id);
81 }
82
83 static void clearThreadHandleForIdentifier(ThreadIdentifier id)
84 {
85     MutexLocker locker(threadMapMutex());
86     ASSERT(threadMap().contains(id));
87     threadMap().remove(id);
88 }
89
90 ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
91 {
92     DWORD threadIdentifier = 0;
93     ThreadIdentifier threadID = 0;
94     HANDLE hEvent = ::CreateEvent(0, FALSE, FALSE, 0);
95     HANDLE threadHandle = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)entryPoint, data, 0, &threadIdentifier);
96     if (!threadHandle) {
97         LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
98         return 0;
99     }
100
101     threadID = static_cast<ThreadIdentifier>(threadIdentifier);
102     storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
103
104     LOG(Threading, "Created thread with thread id %u", threadID);
105     return threadID;
106 }
107
108 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
109 {
110     ASSERT(threadID);
111     
112     HANDLE threadHandle = threadHandleForIdentifier(threadID);
113     if (!threadHandle)
114         LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
115  
116     DWORD joinResult = ::WaitForSingleObject(threadHandle, INFINITE);
117     if (joinResult == WAIT_FAILED)
118         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
119
120     ::CloseHandle(threadHandle);
121     clearThreadHandleForIdentifier(threadID);
122
123     return joinResult;
124 }
125
126 void detachThread(ThreadIdentifier threadID)
127 {
128     ASSERT(threadID);
129     
130     HANDLE threadHandle = threadHandleForIdentifier(threadID);
131     if (threadHandle)
132         ::CloseHandle(threadHandle);
133     clearThreadHandleForIdentifier(threadID);
134 }
135
136 ThreadIdentifier currentThread()
137 {
138     return static_cast<ThreadIdentifier>(::GetCurrentThreadId());
139 }
140
141 static Mutex& functionQueueMutex()
142 {
143     static Mutex staticFunctionQueueMutex;
144     return staticFunctionQueueMutex;
145 }
146
147 static FunctionQueue& functionQueue()
148 {
149     static FunctionQueue staticFunctionQueue;
150     return staticFunctionQueue;
151 }
152
153 static void callFunctionsOnMainThread()
154 {
155     FunctionQueue queueCopy;
156     {
157         MutexLocker locker(functionQueueMutex());
158         queueCopy.swap(functionQueue());
159     }
160
161     LOG(Threading, "Calling %u functions on the main thread", queueCopy.size());
162     for (unsigned i = 0; i < queueCopy.size(); ++i)
163         queueCopy[i]();
164 }
165
166 LRESULT CALLBACK ThreadingWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
167 {
168     if (message == threadingFiredMessage) {
169         processingCustomThreadingMessage = true;
170         callFunctionsOnMainThread();
171         processingCustomThreadingMessage = false;
172     } else
173         return DefWindowProc(hWnd, message, wParam, lParam);
174     return 0;
175 }
176
177 void initializeThreading()
178 {
179     if (threadingWindowHandle)
180         return;
181     
182     WNDCLASSEX wcex;
183     memset(&wcex, 0, sizeof(WNDCLASSEX));
184     wcex.cbSize = sizeof(WNDCLASSEX);
185     wcex.lpfnWndProc    = ThreadingWindowWndProc;
186     wcex.hInstance      = Page::instanceHandle();
187     wcex.lpszClassName  = kThreadingWindowClassName;
188     RegisterClassEx(&wcex);
189
190     threadingWindowHandle = CreateWindow(kThreadingWindowClassName, 0, 0,
191        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, Page::instanceHandle(), 0);
192     threadingFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.MainThreadFired");
193 }
194     
195 void callOnMainThread(void(*function)())
196 {
197     ASSERT(function);
198     ASSERT(threadingWindowHandle);
199
200     if (processingCustomThreadingMessage)
201         LOG(Threading, "callOnMainThread() called recursively.  Beware of nested PostMessage()s");
202
203     {
204         MutexLocker locker(functionQueueMutex());
205         functionQueue().append(function);
206     }
207
208     PostMessage(threadingWindowHandle, threadingFiredMessage, 0, 0);
209 }
210
211 } // namespace WebCore