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