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 <condition_variable> 34#include <wtf/Vector.h> 35 36namespace { 37 38class WebThreadBlockState { 39public: 40 WebThreadBlockState() 41 : m_completed(false) 42 { 43 } 44 45 void waitForCompletion() 46 { 47 std::unique_lock<std::mutex> lock(m_stateMutex); 48 49 m_completionConditionVariable.wait(lock, [this] { return m_completed; }); 50 } 51 52 void setCompleted() 53 { 54 std::lock_guard<std::mutex> lock(m_stateMutex); 55 56 ASSERT(!m_completed); 57 m_completed = true; 58 m_completionConditionVariable.notify_one(); 59 } 60 61private: 62 std::mutex m_stateMutex; 63 std::condition_variable m_completionConditionVariable; 64 bool m_completed; 65}; 66 67class WebThreadBlock { 68public: 69 WebThreadBlock(void (^task)(), WebThreadBlockState* state) 70 : m_task(Block_copy(task)) 71 , m_state(state) 72 { 73 } 74 75 WebThreadBlock(const WebThreadBlock& other) 76 : m_task(Block_copy(other.m_task)) 77 , m_state(other.m_state) 78 { 79 } 80 81 WebThreadBlock& operator=(const WebThreadBlock& other) 82 { 83 void (^oldTask)() = m_task; 84 m_task = Block_copy(other.m_task); 85 Block_release(oldTask); 86 m_state = other.m_state; 87 return *this; 88 } 89 90 ~WebThreadBlock() 91 { 92 Block_release(m_task); 93 } 94 95 void operator()() const 96 { 97 m_task(); 98 if (m_state) 99 m_state->setCompleted(); 100 } 101 102private: 103 void (^m_task)(); 104 WebThreadBlockState* m_state; 105}; 106 107} 108 109extern "C" { 110 111typedef WTF::Vector<WebThreadBlock> WebThreadRunQueue; 112 113static std::mutex* runQueueMutex; 114static CFRunLoopSourceRef runSource; 115static WebThreadRunQueue* runQueue; 116 117static void HandleRunSource(void *info) 118{ 119 UNUSED_PARAM(info); 120 ASSERT(WebThreadIsCurrent()); 121 ASSERT(runQueueMutex); 122 ASSERT(runSource); 123 ASSERT(runQueue); 124 125 WebThreadRunQueue queueCopy; 126 { 127 std::lock_guard<std::mutex> lock(*runQueueMutex); 128 queueCopy = *runQueue; 129 runQueue->clear(); 130 } 131 132 for (const auto& block : queueCopy) 133 block(); 134} 135 136static void _WebThreadRun(void (^task)(), bool synchronous) 137{ 138 if (WebThreadIsCurrent() || !WebThreadIsEnabled()) { 139 task(); 140 return; 141 } 142 143 ASSERT(runQueueMutex); 144 ASSERT(runSource); 145 ASSERT(runQueue); 146 147 WebThreadBlockState* state = 0; 148 if (synchronous) 149 state = new WebThreadBlockState; 150 151 { 152 std::lock_guard<std::mutex> lock(*runQueueMutex); 153 runQueue->append(WebThreadBlock(task, state)); 154 } 155 156 CFRunLoopSourceSignal(runSource); 157 CFRunLoopWakeUp(WebThreadRunLoop()); 158 159 if (synchronous) { 160 state->waitForCompletion(); 161 delete state; 162 } 163} 164 165void WebThreadRun(void (^task)()) 166{ 167 _WebThreadRun(task, false); 168} 169 170void WebThreadRunSync(void (^task)()) 171{ 172 _WebThreadRun(task, true); 173} 174 175void WebThreadInitRunQueue() 176{ 177 ASSERT(!runQueue); 178 ASSERT(!runQueueMutex); 179 ASSERT(!runSource); 180 181 static dispatch_once_t pred; 182 dispatch_once(&pred, ^{ 183 runQueue = new WebThreadRunQueue; 184 185 CFRunLoopSourceContext runSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HandleRunSource}; 186 runSource = CFRunLoopSourceCreate(NULL, -1, &runSourceContext); 187 CFRunLoopAddSource(WebThreadRunLoop(), runSource, kCFRunLoopDefaultMode); 188 189 runQueueMutex = std::make_unique<std::mutex>().release(); 190 }); 191} 192 193} 194 195#endif // PLATFORM(IOS) 196