Use WTF::Lock and WTF::Condition instead of WTF::Mutex, WTF::ThreadCondition, std...
[WebKit-https.git] / Source / JavaScriptCore / inspector / remote / RemoteInspectorDebuggableConnection.mm
1 /*
2  * Copyright (C) 2013, 2015 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "RemoteInspectorDebuggableConnection.h"
28
29 #if ENABLE(REMOTE_INSPECTOR)
30
31 #import "EventLoop.h"
32 #import "RemoteInspector.h"
33 #import <dispatch/dispatch.h>
34 #import <wtf/Vector.h>
35
36 #if PLATFORM(IOS)
37 #import <wtf/ios/WebCoreThread.h>
38 #endif
39
40 namespace Inspector {
41
42 static StaticLock rwiQueueMutex;
43 static CFRunLoopSourceRef rwiRunLoopSource;
44 static RemoteInspectorQueue* rwiQueue;
45
46 static void RemoteInspectorHandleRunSourceGlobal(void*)
47 {
48     ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
49     ASSERT(rwiRunLoopSource);
50     ASSERT(rwiQueue);
51
52     RemoteInspectorQueue queueCopy;
53     {
54         std::lock_guard<StaticLock> lock(rwiQueueMutex);
55         queueCopy = *rwiQueue;
56         rwiQueue->clear();
57     }
58
59     for (const auto& block : queueCopy)
60         block();
61 }
62
63 static void RemoteInspectorQueueTaskOnGlobalQueue(void (^task)())
64 {
65     ASSERT(rwiRunLoopSource);
66     ASSERT(rwiQueue);
67
68     {
69         std::lock_guard<StaticLock> lock(rwiQueueMutex);
70         rwiQueue->append(RemoteInspectorBlock(task));
71     }
72
73     CFRunLoopSourceSignal(rwiRunLoopSource);
74     CFRunLoopWakeUp(CFRunLoopGetMain());
75 }
76
77 static void RemoteInspectorInitializeGlobalQueue()
78 {
79     static dispatch_once_t pred;
80     dispatch_once(&pred, ^{
81         rwiQueue = new RemoteInspectorQueue;
82
83         CFRunLoopSourceContext runLoopSourceContext = {0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteInspectorHandleRunSourceGlobal};
84         rwiRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext);
85
86         // Add to the default run loop mode for default handling, and the JSContext remote inspector run loop mode when paused.
87         CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, kCFRunLoopDefaultMode);
88         CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, EventLoop::remoteInspectorRunLoopMode());
89     });
90 }
91
92 static void RemoteInspectorHandleRunSourceWithInfo(void* info)
93 {
94     RemoteInspectorDebuggableConnection *debuggableConnection = static_cast<RemoteInspectorDebuggableConnection*>(info);
95
96     RemoteInspectorQueue queueCopy;
97     {
98         std::lock_guard<Lock> lock(debuggableConnection->queueMutex());
99         queueCopy = debuggableConnection->queue();
100         debuggableConnection->clearQueue();
101     }
102
103     for (const auto& block : queueCopy)
104         block();
105 }
106
107
108 RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection(RemoteInspectorDebuggable* debuggable, NSString *connectionIdentifier, NSString *destination, RemoteInspectorDebuggable::DebuggableType)
109     : m_debuggable(debuggable)
110     , m_connectionIdentifier(connectionIdentifier)
111     , m_destination(destination)
112     , m_identifier(debuggable->identifier())
113     , m_connected(false)
114 {
115     setupRunLoop();
116 }
117
118 RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection()
119 {
120     teardownRunLoop();
121 }
122
123 NSString *RemoteInspectorDebuggableConnection::destination() const
124 {
125     return [[m_destination copy] autorelease];
126 }
127
128 NSString *RemoteInspectorDebuggableConnection::connectionIdentifier() const
129 {
130     return [[m_connectionIdentifier copy] autorelease];
131 }
132
133 void RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable(void (^block)())
134 {
135     if (m_runLoop) {
136         queueTaskOnPrivateRunLoop(block);
137         return;
138     }
139
140 #if PLATFORM(IOS)
141     if (WebCoreWebThreadIsEnabled && WebCoreWebThreadIsEnabled()) {
142         WebCoreWebThreadRun(block);
143         return;
144     }
145 #endif
146
147     RemoteInspectorQueueTaskOnGlobalQueue(block);
148 }
149
150 bool RemoteInspectorDebuggableConnection::setup(bool isAutomaticInspection, bool automaticallyPause)
151 {
152     std::lock_guard<Lock> lock(m_debuggableMutex);
153
154     if (!m_debuggable)
155         return false;
156
157     ref();
158     dispatchAsyncOnDebuggable(^{
159         {
160             std::lock_guard<Lock> lock(m_debuggableMutex);
161             if (!m_debuggable || !m_debuggable->remoteDebuggingAllowed() || m_debuggable->hasLocalDebugger()) {
162                 RemoteInspector::singleton().setupFailed(identifier());
163                 m_debuggable = nullptr;
164             } else {
165                 m_debuggable->connect(this, isAutomaticInspection);
166                 m_connected = true;
167
168                 if (automaticallyPause)
169                     m_debuggable->pause();
170             }
171         }
172         deref();
173     });
174
175     return true;
176 }
177
178 void RemoteInspectorDebuggableConnection::closeFromDebuggable()
179 {
180     std::lock_guard<Lock> lock(m_debuggableMutex);
181
182     m_debuggable = nullptr;
183 }
184
185 void RemoteInspectorDebuggableConnection::close()
186 {
187     ref();
188     dispatchAsyncOnDebuggable(^{
189         {
190             std::lock_guard<Lock> lock(m_debuggableMutex);
191
192             if (m_debuggable) {
193                 if (m_connected)
194                     m_debuggable->disconnect();
195
196                 m_debuggable = nullptr;
197             }
198         }
199         deref();
200     });
201 }
202
203 void RemoteInspectorDebuggableConnection::sendMessageToBackend(NSString *message)
204 {
205     ref();
206     dispatchAsyncOnDebuggable(^{
207         {
208             RemoteInspectorDebuggable* debuggable = nullptr;
209             {
210                 std::lock_guard<Lock> lock(m_debuggableMutex);
211                 if (!m_debuggable)
212                     return;
213                 debuggable = m_debuggable;
214             }
215
216             debuggable->dispatchMessageFromRemoteFrontend(message);
217         }
218         deref();
219     });
220 }
221
222 bool RemoteInspectorDebuggableConnection::sendMessageToFrontend(const String& message)
223 {
224     RemoteInspector::singleton().sendMessageToRemoteFrontend(identifier(), message);
225
226     return true;
227 }
228
229 void RemoteInspectorDebuggableConnection::setupRunLoop()
230 {
231     CFRunLoopRef debuggerRunLoop = m_debuggable->debuggerRunLoop();
232     if (!debuggerRunLoop) {
233         RemoteInspectorInitializeGlobalQueue();
234         return;
235     }
236
237     m_runLoop = debuggerRunLoop;
238
239     CFRunLoopSourceContext runLoopSourceContext = {0, this, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteInspectorHandleRunSourceWithInfo};
240     m_runLoopSource = adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext));
241
242     CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode);
243     CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode());
244 }
245
246 void RemoteInspectorDebuggableConnection::teardownRunLoop()
247 {
248     if (!m_runLoop)
249         return;
250
251     CFRunLoopRemoveSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode);
252     CFRunLoopRemoveSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode());
253
254     m_runLoop = nullptr;
255     m_runLoopSource = nullptr;
256 }
257
258 void RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop(void (^block)())
259 {
260     ASSERT(m_runLoop);
261
262     {
263         std::lock_guard<Lock> lock(m_queueMutex);
264         m_queue.append(RemoteInspectorBlock(block));
265     }
266
267     CFRunLoopSourceSignal(m_runLoopSource.get());
268     CFRunLoopWakeUp(m_runLoop.get());
269 }
270
271 } // namespace Inspector
272
273 #endif // ENABLE(REMOTE_INSPECTOR)