[iOS] Upstream WAK
[WebKit.git] / Source / WebCore / platform / ios / wak / WebCoreThreadRun.cpp
1 /*
2  * Copyright (C) 2010 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebCoreThreadRun.h"
28
29 #if PLATFORM(IOS)
30
31 #include "WebCoreThread.h"
32 #include "WebCoreThreadInternal.h"
33 #include <wtf/ThreadingPrimitives.h>
34 #include <wtf/Vector.h>
35
36 namespace {
37
38 class WebThreadBlockState {
39 public:
40     WebThreadBlockState()
41         : m_completed(false)
42     {
43     }
44
45     void waitForCompletion()
46     {
47         MutexLocker locker(m_stateMutex);
48         while (!m_completed)
49             m_completionCondition.wait(m_stateMutex);
50     }
51
52     void setCompleted()
53     {
54         MutexLocker locker(m_stateMutex);
55         ASSERT(!m_completed);
56         m_completed = true;
57         m_completionCondition.signal();
58     }
59 private:
60     WTF::Mutex m_stateMutex;
61     WTF::ThreadCondition m_completionCondition;
62     bool m_completed;
63 };
64
65 class WebThreadBlock {
66 public:
67     WebThreadBlock(void (^task)(), WebThreadBlockState* state)
68         : m_task(Block_copy(task))
69         , m_state(state)
70     {
71     }
72
73     WebThreadBlock(const WebThreadBlock& other)
74         : m_task(Block_copy(other.m_task))
75         , m_state(other.m_state)
76     {
77     }
78
79     WebThreadBlock& operator=(const WebThreadBlock& other)
80     {
81         void (^oldTask)() = m_task;
82         m_task = Block_copy(other.m_task);
83         Block_release(oldTask);
84         m_state = other.m_state;
85         return *this;
86     }
87
88     ~WebThreadBlock()
89     {
90         Block_release(m_task);
91     }
92
93     void operator()() const
94     {
95         m_task();
96         if (m_state)
97             m_state->setCompleted();
98     }
99
100 private:
101     void (^m_task)();
102     WebThreadBlockState* m_state;
103 };
104
105 }
106
107 extern "C" {
108
109 typedef WTF::Vector<WebThreadBlock> WebThreadRunQueue;
110
111 static WTF::Mutex *runQueueLock = NULL;
112 static CFRunLoopSourceRef runSource = NULL;
113 static WebThreadRunQueue *runQueue = NULL;
114
115 static void HandleRunSource(void *info)
116 {
117     UNUSED_PARAM(info);
118     ASSERT(WebThreadIsCurrent());
119     ASSERT(runQueueLock);
120     ASSERT(runSource);
121     ASSERT(runQueue);
122
123     WebThreadRunQueue queueCopy;
124     {
125         MutexLocker locker(*runQueueLock);
126         queueCopy = *runQueue;
127         runQueue->clear();
128     }
129
130     for (WebThreadRunQueue::const_iterator it = queueCopy.begin(); it != queueCopy.end(); ++it)
131         (*it)();
132 }
133
134 static void _WebThreadRun(void (^task)(), bool synchronous)
135 {
136     if (WebThreadIsCurrent() || !WebThreadIsEnabled()) {
137         task();
138         return;
139     }
140     
141     ASSERT(runQueueLock);
142     ASSERT(runSource);
143     ASSERT(runQueue);
144
145     WebThreadBlockState* state = 0;
146     if (synchronous)
147         state = new WebThreadBlockState;
148
149     {
150         MutexLocker locker(*runQueueLock);
151         runQueue->append(WebThreadBlock(task, state));
152     }
153
154     CFRunLoopSourceSignal(runSource);
155     CFRunLoopWakeUp(WebThreadRunLoop());
156
157     if (synchronous) {
158         state->waitForCompletion();
159         delete state;
160     }
161 }
162
163 void WebThreadRun(void (^task)())
164 {
165     _WebThreadRun(task, false);
166 }
167
168 void WebThreadRunSync(void (^task)())
169 {
170     _WebThreadRun(task, true);
171 }
172     
173 void WebThreadInitRunQueue()
174 {
175     ASSERT(!runQueue);
176     ASSERT(!runQueueLock);
177     ASSERT(!runSource);
178
179     static dispatch_once_t pred;
180     dispatch_once(&pred, ^{
181         runQueue = new WebThreadRunQueue;
182
183         CFRunLoopSourceContext runSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HandleRunSource};
184         runSource = CFRunLoopSourceCreate(NULL, -1, &runSourceContext);
185         CFRunLoopAddSource(WebThreadRunLoop(), runSource, kCFRunLoopDefaultMode);
186
187         runQueueLock = new WTF::Mutex;
188     });
189 }
190
191 }
192
193 #endif // PLATFORM(IOS)