0821266d88f929a267e16c58c511075ecc1328f4
[WebKit-https.git] / Source / JavaScriptCore / inspector / remote / RemoteInspectorDebuggableConnection.mm
1 /*
2  * Copyright (C) 2013 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 std::mutex* rwiQueueMutex;
43 static CFRunLoopSourceRef rwiRunLoopSource;
44 static RemoteInspectorQueue* rwiQueue;
45
46 static void RemoteInspectorHandleRunSourceGlobal(void*)
47 {
48     ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
49     ASSERT(rwiQueueMutex);
50     ASSERT(rwiRunLoopSource);
51     ASSERT(rwiQueue);
52
53     RemoteInspectorQueue queueCopy;
54     {
55         std::lock_guard<std::mutex> lock(*rwiQueueMutex);
56         queueCopy = *rwiQueue;
57         rwiQueue->clear();
58     }
59
60     for (const auto& block : queueCopy)
61         block();
62 }
63
64 static void RemoteInspectorQueueTaskOnGlobalQueue(void (^task)())
65 {
66     ASSERT(rwiQueueMutex);
67     ASSERT(rwiRunLoopSource);
68     ASSERT(rwiQueue);
69
70     {
71         std::lock_guard<std::mutex> lock(*rwiQueueMutex);
72         rwiQueue->append(RemoteInspectorBlock(task));
73     }
74
75     CFRunLoopSourceSignal(rwiRunLoopSource);
76     CFRunLoopWakeUp(CFRunLoopGetMain());
77 }
78
79 static void RemoteInspectorInitializeGlobalQueue()
80 {
81     static dispatch_once_t pred;
82     dispatch_once(&pred, ^{
83         rwiQueue = new RemoteInspectorQueue;
84         rwiQueueMutex = std::make_unique<std::mutex>().release();
85
86         CFRunLoopSourceContext runLoopSourceContext = {0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteInspectorHandleRunSourceGlobal};
87         rwiRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext);
88
89         // Add to the default run loop mode for default handling, and the JSContext remote inspector run loop mode when paused.
90         CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, kCFRunLoopDefaultMode);
91         CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, EventLoop::remoteInspectorRunLoopMode());
92     });
93 }
94
95 static void RemoteInspectorHandleRunSourceWithInfo(void* info)
96 {
97     RemoteInspectorDebuggableConnection *debuggableConnection = static_cast<RemoteInspectorDebuggableConnection*>(info);
98
99     RemoteInspectorQueue queueCopy;
100     {
101         std::lock_guard<std::mutex> lock(debuggableConnection->queueMutex());
102         queueCopy = debuggableConnection->queue();
103         debuggableConnection->clearQueue();
104     }
105
106     for (const auto& block : queueCopy)
107         block();
108 }
109
110
111 RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection(RemoteInspectorDebuggable* debuggable, NSString *connectionIdentifier, NSString *destination, RemoteInspectorDebuggable::DebuggableType)
112     : m_debuggable(debuggable)
113     , m_connectionIdentifier(connectionIdentifier)
114     , m_destination(destination)
115     , m_identifier(debuggable->identifier())
116     , m_connected(false)
117 {
118     setupRunLoop();
119 }
120
121 RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection()
122 {
123     teardownRunLoop();
124 }
125
126 NSString *RemoteInspectorDebuggableConnection::destination() const
127 {
128     return [[m_destination copy] autorelease];
129 }
130
131 NSString *RemoteInspectorDebuggableConnection::connectionIdentifier() const
132 {
133     return [[m_connectionIdentifier copy] autorelease];
134 }
135
136 void RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable(void (^block)())
137 {
138     if (m_runLoop) {
139         queueTaskOnPrivateRunLoop(block);
140         return;
141     }
142
143 #if PLATFORM(IOS)
144     if (WebCoreWebThreadIsEnabled && WebCoreWebThreadIsEnabled()) {
145         WebCoreWebThreadRun(block);
146         return;
147     }
148 #endif
149
150     RemoteInspectorQueueTaskOnGlobalQueue(block);
151 }
152
153 bool RemoteInspectorDebuggableConnection::setup(bool isAutomaticInspection, bool automaticallyPause)
154 {
155     std::lock_guard<std::mutex> lock(m_debuggableMutex);
156
157     if (!m_debuggable)
158         return false;
159
160     ref();
161     dispatchAsyncOnDebuggable(^{
162         {
163             std::lock_guard<std::mutex> lock(m_debuggableMutex);
164             if (!m_debuggable || !m_debuggable->remoteDebuggingAllowed() || m_debuggable->hasLocalDebugger()) {
165                 RemoteInspector::singleton().setupFailed(identifier());
166                 m_debuggable = nullptr;
167             } else {
168                 m_debuggable->connect(this, isAutomaticInspection);
169                 m_connected = true;
170
171                 if (automaticallyPause)
172                     m_debuggable->pause();
173             }
174         }
175         deref();
176     });
177
178     return true;
179 }
180
181 void RemoteInspectorDebuggableConnection::closeFromDebuggable()
182 {
183     std::lock_guard<std::mutex> lock(m_debuggableMutex);
184
185     m_debuggable = nullptr;
186 }
187
188 void RemoteInspectorDebuggableConnection::close()
189 {
190     ref();
191     dispatchAsyncOnDebuggable(^{
192         {
193             std::lock_guard<std::mutex> lock(m_debuggableMutex);
194
195             if (m_debuggable) {
196                 if (m_connected)
197                     m_debuggable->disconnect();
198
199                 m_debuggable = nullptr;
200             }
201         }
202         deref();
203     });
204 }
205
206 void RemoteInspectorDebuggableConnection::sendMessageToBackend(NSString *message)
207 {
208     ref();
209     dispatchAsyncOnDebuggable(^{
210         {
211             RemoteInspectorDebuggable* debuggable = nullptr;
212             {
213                 std::lock_guard<std::mutex> lock(m_debuggableMutex);
214                 if (!m_debuggable)
215                     return;
216                 debuggable = m_debuggable;
217             }
218
219             debuggable->dispatchMessageFromRemoteFrontend(message);
220         }
221         deref();
222     });
223 }
224
225 bool RemoteInspectorDebuggableConnection::sendMessageToFrontend(const String& message)
226 {
227     RemoteInspector::singleton().sendMessageToRemoteFrontend(identifier(), message);
228
229     return true;
230 }
231
232 void RemoteInspectorDebuggableConnection::setupRunLoop()
233 {
234     CFRunLoopRef debuggerRunLoop = m_debuggable->debuggerRunLoop();
235     if (!debuggerRunLoop) {
236         RemoteInspectorInitializeGlobalQueue();
237         return;
238     }
239
240     m_runLoop = debuggerRunLoop;
241
242     CFRunLoopSourceContext runLoopSourceContext = {0, this, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteInspectorHandleRunSourceWithInfo};
243     m_runLoopSource = adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext));
244
245     CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode);
246     CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode());
247 }
248
249 void RemoteInspectorDebuggableConnection::teardownRunLoop()
250 {
251     if (!m_runLoop)
252         return;
253
254     CFRunLoopRemoveSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode);
255     CFRunLoopRemoveSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode());
256
257     m_runLoop = nullptr;
258     m_runLoopSource = nullptr;
259 }
260
261 void RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop(void (^block)())
262 {
263     ASSERT(m_runLoop);
264
265     {
266         std::lock_guard<std::mutex> lock(m_queueMutex);
267         m_queue.append(RemoteInspectorBlock(block));
268     }
269
270     CFRunLoopSourceSignal(m_runLoopSource.get());
271     CFRunLoopWakeUp(m_runLoop.get());
272 }
273
274 } // namespace Inspector
275
276 #endif // ENABLE(REMOTE_INSPECTOR)