[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / JavaScriptCore / inspector / remote / RemoteConnectionToTarget.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 "RemoteConnectionToTarget.h"
28
29 #if ENABLE(REMOTE_INSPECTOR)
30
31 #import "EventLoop.h"
32 #import "RemoteAutomationTarget.h"
33 #import "RemoteInspectionTarget.h"
34 #import <dispatch/dispatch.h>
35 #import <wtf/Optional.h>
36
37 #if PLATFORM(IOS)
38 #import <wtf/ios/WebCoreThread.h>
39 #endif
40
41 namespace Inspector {
42
43 static StaticLock rwiQueueMutex;
44 static CFRunLoopSourceRef rwiRunLoopSource;
45 static RemoteTargetQueue* rwiQueue;
46
47 static void RemoteTargetHandleRunSourceGlobal(void*)
48 {
49     ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
50     ASSERT(rwiRunLoopSource);
51     ASSERT(rwiQueue);
52
53     RemoteTargetQueue queueCopy;
54     {
55         std::lock_guard<StaticLock> lock(rwiQueueMutex);
56         queueCopy = *rwiQueue;
57         rwiQueue->clear();
58     }
59
60     for (const auto& block : queueCopy)
61         block();
62 }
63
64 static void RemoteTargetQueueTaskOnGlobalQueue(void (^task)())
65 {
66     ASSERT(rwiRunLoopSource);
67     ASSERT(rwiQueue);
68
69     {
70         std::lock_guard<StaticLock> lock(rwiQueueMutex);
71         rwiQueue->append(task);
72     }
73
74     CFRunLoopSourceSignal(rwiRunLoopSource);
75     CFRunLoopWakeUp(CFRunLoopGetMain());
76 }
77
78 static void RemoteTargetInitializeGlobalQueue()
79 {
80     static dispatch_once_t pred;
81     dispatch_once(&pred, ^{
82         rwiQueue = new RemoteTargetQueue;
83
84         CFRunLoopSourceContext runLoopSourceContext = {0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteTargetHandleRunSourceGlobal};
85         rwiRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext);
86
87         // Add to the default run loop mode for default handling, and the JSContext remote inspector run loop mode when paused.
88         CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, kCFRunLoopDefaultMode);
89         CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, EventLoop::remoteInspectorRunLoopMode());
90     });
91 }
92
93 static void RemoteTargetHandleRunSourceWithInfo(void* info)
94 {
95     RemoteConnectionToTarget *connectionToTarget = static_cast<RemoteConnectionToTarget*>(info);
96
97     RemoteTargetQueue queueCopy;
98     {
99         std::lock_guard<Lock> lock(connectionToTarget->queueMutex());
100         queueCopy = connectionToTarget->queue();
101         connectionToTarget->clearQueue();
102     }
103
104     for (const auto& block : queueCopy)
105         block();
106 }
107
108
109 RemoteConnectionToTarget::RemoteConnectionToTarget(RemoteControllableTarget* target, NSString *connectionIdentifier, NSString *destination)
110     : m_target(target)
111     , m_connectionIdentifier(connectionIdentifier)
112     , m_destination(destination)
113 {
114     setupRunLoop();
115 }
116
117 RemoteConnectionToTarget::~RemoteConnectionToTarget()
118 {
119     teardownRunLoop();
120 }
121
122 std::optional<unsigned> RemoteConnectionToTarget::targetIdentifier() const
123 {
124     return m_target ? std::optional<unsigned>(m_target->targetIdentifier()) : std::nullopt;
125 }
126
127 NSString *RemoteConnectionToTarget::connectionIdentifier() const
128 {
129     return [[m_connectionIdentifier copy] autorelease];
130 }
131
132 NSString *RemoteConnectionToTarget::destination() const
133 {
134     return [[m_destination copy] autorelease];
135 }
136
137 void RemoteConnectionToTarget::dispatchAsyncOnTarget(void (^block)())
138 {
139     if (m_runLoop) {
140         queueTaskOnPrivateRunLoop(block);
141         return;
142     }
143
144 #if PLATFORM(IOS)
145     if (WebCoreWebThreadIsEnabled && WebCoreWebThreadIsEnabled()) {
146         WebCoreWebThreadRun(block);
147         return;
148     }
149 #endif
150
151     RemoteTargetQueueTaskOnGlobalQueue(block);
152 }
153
154 bool RemoteConnectionToTarget::setup(bool isAutomaticInspection, bool automaticallyPause)
155 {
156     std::lock_guard<Lock> lock(m_targetMutex);
157
158     if (!m_target)
159         return false;
160
161     ref();
162     dispatchAsyncOnTarget(^{
163         {
164             std::lock_guard<Lock> lock(m_targetMutex);
165             if (!m_target || !m_target->remoteControlAllowed()) {
166                 RemoteInspector::singleton().setupFailed(targetIdentifier().value_or(0));
167                 m_target = nullptr;
168             } else if (is<RemoteInspectionTarget>(m_target)) {
169                 auto castedTarget = downcast<RemoteInspectionTarget>(m_target);
170                 castedTarget->connect(this, isAutomaticInspection);
171                 m_connected = true;
172
173                 if (automaticallyPause)
174                     castedTarget->pause();
175             } else if (is<RemoteAutomationTarget>(m_target)) {
176                 auto castedTarget = downcast<RemoteAutomationTarget>(m_target);
177                 castedTarget->connect(this);
178                 m_connected = true;
179             }
180         }
181         deref();
182     });
183
184     return true;
185 }
186
187 void RemoteConnectionToTarget::targetClosed()
188 {
189     std::lock_guard<Lock> lock(m_targetMutex);
190
191     m_target = nullptr;
192 }
193
194 void RemoteConnectionToTarget::close()
195 {
196     ref();
197     dispatchAsyncOnTarget(^{
198         {
199             std::lock_guard<Lock> lock(m_targetMutex);
200
201             if (m_target) {
202                 if (m_connected)
203                     m_target->disconnect(this);
204
205                 m_target = nullptr;
206             }
207         }
208         deref();
209     });
210 }
211
212 void RemoteConnectionToTarget::sendMessageToTarget(NSString *message)
213 {
214     ref();
215     dispatchAsyncOnTarget(^{
216         {
217             RemoteControllableTarget* target = nullptr;
218             {
219                 std::lock_guard<Lock> lock(m_targetMutex);
220                 if (!m_target)
221                     return;
222                 target = m_target;
223             }
224
225             target->dispatchMessageFromRemote(message);
226         }
227         deref();
228     });
229 }
230
231 void RemoteConnectionToTarget::sendMessageToFrontend(const String& message)
232 {
233     if (!targetIdentifier())
234         return;
235
236     RemoteInspector::singleton().sendMessageToRemote(targetIdentifier().value(), message);
237 }
238
239 void RemoteConnectionToTarget::setupRunLoop()
240 {
241     CFRunLoopRef targetRunLoop = m_target->targetRunLoop();
242     if (!targetRunLoop) {
243         RemoteTargetInitializeGlobalQueue();
244         return;
245     }
246
247     m_runLoop = targetRunLoop;
248
249     CFRunLoopSourceContext runLoopSourceContext = {0, this, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteTargetHandleRunSourceWithInfo};
250     m_runLoopSource = adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext));
251
252     CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode);
253     CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode());
254 }
255
256 void RemoteConnectionToTarget::teardownRunLoop()
257 {
258     if (!m_runLoop)
259         return;
260
261     CFRunLoopRemoveSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode);
262     CFRunLoopRemoveSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode());
263
264     m_runLoop = nullptr;
265     m_runLoopSource = nullptr;
266 }
267
268 void RemoteConnectionToTarget::queueTaskOnPrivateRunLoop(void (^block)())
269 {
270     ASSERT(m_runLoop);
271
272     {
273         std::lock_guard<Lock> lock(m_queueMutex);
274         m_queue.append(block);
275     }
276
277     CFRunLoopSourceSignal(m_runLoopSource.get());
278     CFRunLoopWakeUp(m_runLoop.get());
279 }
280
281 } // namespace Inspector
282
283 #endif // ENABLE(REMOTE_INSPECTOR)