Merge "Better solution for Docomo 1339 bug." into tizen_2.1
[framework/web/webkit-efl.git] / Source / WTF / wtf / MainThread.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 #include "config.h"
30 #include "MainThread.h"
31
32 #include "CurrentTime.h"
33 #include "Deque.h"
34 #include "Functional.h"
35 #include "StdLibExtras.h"
36 #include "Threading.h"
37 #include <wtf/ThreadSpecific.h>
38
39 #if PLATFORM(CHROMIUM)
40 #error Chromium uses a different main thread implementation
41 #endif
42
43 namespace WTF {
44
45 struct FunctionWithContext {
46     MainThreadFunction* function;
47     void* context;
48     ThreadCondition* syncFlag;
49
50     FunctionWithContext(MainThreadFunction* function = 0, void* context = 0, ThreadCondition* syncFlag = 0)
51         : function(function)
52         , context(context)
53         , syncFlag(syncFlag)
54     { 
55     }
56     bool operator == (const FunctionWithContext& o)
57     {
58         return function == o.function
59             && context == o.context
60             && syncFlag == o.syncFlag;
61     }
62 };
63
64 class FunctionWithContextFinder {
65 public:
66     FunctionWithContextFinder(const FunctionWithContext& m) : m(m) {}
67     bool operator() (FunctionWithContext& o) { return o == m; }
68     FunctionWithContext m;
69 };
70
71
72 typedef Deque<FunctionWithContext> FunctionQueue;
73
74 static bool callbacksPaused; // This global variable is only accessed from main thread.
75 #if !PLATFORM(MAC)
76 static ThreadIdentifier mainThreadIdentifier;
77 #endif
78
79 static Mutex& mainThreadFunctionQueueMutex()
80 {
81     DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
82     return staticMutex;
83 }
84
85 static FunctionQueue& functionQueue()
86 {
87     DEFINE_STATIC_LOCAL(FunctionQueue, staticFunctionQueue, ());
88     return staticFunctionQueue;
89 }
90
91
92 #if !PLATFORM(MAC)
93
94 void initializeMainThread()
95 {
96     static bool initializedMainThread;
97     if (initializedMainThread)
98         return;
99     initializedMainThread = true;
100
101     mainThreadIdentifier = currentThread();
102
103     mainThreadFunctionQueueMutex();
104     initializeMainThreadPlatform();
105     initializeGCThreads();
106 }
107
108 #else
109
110 static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT;
111
112 static void initializeMainThreadOnce()
113 {
114     mainThreadFunctionQueueMutex();
115     initializeMainThreadPlatform();
116 }
117
118 void initializeMainThread()
119 {
120     pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce);
121 }
122
123 static void initializeMainThreadToProcessMainThreadOnce()
124 {
125     mainThreadFunctionQueueMutex();
126     initializeMainThreadToProcessMainThreadPlatform();
127 }
128
129 void initializeMainThreadToProcessMainThread()
130 {
131     pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce);
132 }
133 #endif
134
135 // 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that.
136 static const double maxRunLoopSuspensionTime = 0.05;
137
138 void dispatchFunctionsFromMainThread()
139 {
140     ASSERT(isMainThread());
141
142     if (callbacksPaused)
143         return;
144
145     double startTime = currentTime();
146
147     FunctionWithContext invocation;
148     while (true) {
149         {
150             MutexLocker locker(mainThreadFunctionQueueMutex());
151             if (!functionQueue().size())
152                 break;
153             invocation = functionQueue().takeFirst();
154         }
155
156         invocation.function(invocation.context);
157         if (invocation.syncFlag) {
158             MutexLocker locker(mainThreadFunctionQueueMutex());
159             invocation.syncFlag->signal();
160         }
161
162         // If we are running accumulated functions for too long so UI may become unresponsive, we need to
163         // yield so the user input can be processed. Otherwise user may not be able to even close the window.
164         // This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that
165         // allows input events to be processed before we are back here.
166         if (currentTime() - startTime > maxRunLoopSuspensionTime) {
167             scheduleDispatchFunctionsOnMainThread();
168             break;
169         }
170     }
171 }
172
173 void callOnMainThread(MainThreadFunction* function, void* context)
174 {
175     ASSERT(function);
176     bool needToSchedule = false;
177     {
178         MutexLocker locker(mainThreadFunctionQueueMutex());
179         needToSchedule = functionQueue().size() == 0;
180         functionQueue().append(FunctionWithContext(function, context));
181     }
182     if (needToSchedule)
183         scheduleDispatchFunctionsOnMainThread();
184 }
185
186 void callOnMainThreadAndWait(MainThreadFunction* function, void* context)
187 {
188     ASSERT(function);
189
190     if (isMainThread()) {
191         function(context);
192         return;
193     }
194
195     ThreadCondition syncFlag;
196     Mutex& functionQueueMutex = mainThreadFunctionQueueMutex();
197     MutexLocker locker(functionQueueMutex);
198     functionQueue().append(FunctionWithContext(function, context, &syncFlag));
199     if (functionQueue().size() == 1)
200         scheduleDispatchFunctionsOnMainThread();
201     syncFlag.wait(functionQueueMutex);
202 }
203
204 void cancelCallOnMainThread(MainThreadFunction* function, void* context)
205 {
206     ASSERT(function);
207
208     MutexLocker locker(mainThreadFunctionQueueMutex());
209
210     FunctionWithContextFinder pred(FunctionWithContext(function, context));
211
212     while (true) {
213         // We must redefine 'i' each pass, because the itererator's operator= 
214         // requires 'this' to be valid, and remove() invalidates all iterators
215         FunctionQueue::iterator i(functionQueue().findIf(pred));
216         if (i == functionQueue().end())
217             break;
218         functionQueue().remove(i);
219     }
220 }
221
222 static void callFunctionObject(void* context)
223 {
224     Function<void ()>* function = static_cast<Function<void ()>*>(context);
225     (*function)();
226     delete function;
227 }
228
229 void callOnMainThread(const Function<void ()>& function)
230 {
231     callOnMainThread(callFunctionObject, new Function<void ()>(function));
232 }
233
234 void setMainThreadCallbacksPaused(bool paused)
235 {
236     ASSERT(isMainThread());
237
238     if (callbacksPaused == paused)
239         return;
240
241     callbacksPaused = paused;
242
243     if (!callbacksPaused)
244         scheduleDispatchFunctionsOnMainThread();
245 }
246
247 #if !PLATFORM(MAC)
248 bool isMainThread()
249 {
250     return currentThread() == mainThreadIdentifier;
251 }
252 #endif
253
254 #if ENABLE(PARALLEL_GC)
255 static ThreadSpecific<bool>* isGCThread;
256 #endif
257
258 void initializeGCThreads()
259 {
260 #if ENABLE(PARALLEL_GC)
261     isGCThread = new ThreadSpecific<bool>();
262 #endif
263 }
264
265 #if ENABLE(PARALLEL_GC)
266 void registerGCThread()
267 {
268     if (!isGCThread) {
269         // This happens if we're running in a process that doesn't care about
270         // MainThread.
271         return;
272     }
273
274     **isGCThread = true;
275 }
276
277 bool isMainThreadOrGCThread()
278 {
279     if (isGCThread->isSet() && **isGCThread)
280         return true;
281
282     return isMainThread();
283 }
284 #elif PLATFORM(MAC)
285 // This is necessary because JavaScriptCore.exp doesn't support preprocessor macros.
286 bool isMainThreadOrGCThread()
287 {
288     return isMainThread();
289 }
290 #endif
291
292 } // namespace WTF