/* * Copyright (C) 2010 Apple Inc. All rights reserved. * Copyright (C) 2017 Sony Interactive Entertainment Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include namespace WTF { WorkQueue& WorkQueue::main() { static NeverDestroyed> mainWorkQueue; static std::once_flag onceKey; std::call_once(onceKey, [&] { mainWorkQueue.get() = constructMainWorkQueue(); }); return *mainWorkQueue.get(); } Ref WorkQueue::create(const char* name, Type type, QOS qos) { return adoptRef(*new WorkQueue(name, type, qos)); } WorkQueue::WorkQueue(const char* name, Type type, QOS qos) { platformInitialize(name, type, qos); } WorkQueue::~WorkQueue() { platformInvalidate(); } #if !PLATFORM(COCOA) void WorkQueue::dispatchSync(Function&& function) { BinarySemaphore semaphore; dispatch([&semaphore, function = WTFMove(function)]() mutable { function(); semaphore.signal(); }); semaphore.wait(); } void WorkQueue::concurrentApply(size_t iterations, WTF::Function&& function) { if (!iterations) return; if (iterations == 1) { function(0); return; } class ThreadPool { public: ThreadPool() { // We don't need a thread for the current core. unsigned threadCount = numberOfProcessorCores() - 1; m_workers.reserveInitialCapacity(threadCount); for (unsigned i = 0; i < threadCount; ++i) { m_workers.append(Thread::create("ThreadPool Worker", [this] { threadBody(); })); } } size_t workerCount() const { return m_workers.size(); } void dispatch(const WTF::Function* function) { Locker locker { m_lock }; m_queue.append(function); m_condition.notifyOne(); } private: NO_RETURN void threadBody() { while (true) { const WTF::Function* function; { Locker locker { m_lock }; m_condition.wait(m_lock, [this] { assertIsHeld(m_lock); return !m_queue.isEmpty(); }); function = m_queue.takeFirst(); } (*function)(); } } Lock m_lock; Condition m_condition; Deque*> m_queue WTF_GUARDED_BY_LOCK(m_lock); Vector> m_workers; }; static LazyNeverDestroyed threadPool; static std::once_flag onceFlag; std::call_once(onceFlag, [] { threadPool.construct(); }); // Cap the worker count to the number of iterations (excluding this thread) const size_t workerCount = std::min(iterations - 1, threadPool->workerCount()); std::atomic currentIndex(0); std::atomic activeThreads(workerCount + 1); Condition condition; Lock lock; Function applier = [&, function = WTFMove(function)] { size_t index; // Call the function for as long as there are iterations left. while ((index = currentIndex++) < iterations) function(index); // If there are no active threads left, signal the caller. if (!--activeThreads) { Locker locker { lock }; condition.notifyOne(); } }; for (size_t i = 0; i < workerCount; ++i) threadPool->dispatch(&applier); applier(); Locker locker { lock }; condition.wait(lock, [&] { return !activeThreads; }); } #endif }