/* * Copyright (C) 2016 Apple Inc. All rights reserved. * * 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 "ResourceUsageThread.h" #if ENABLE(RESOURCE_USAGE) #include "JSDOMWindow.h" #include #include #include namespace WebCore { ResourceUsageThread::ResourceUsageThread() { } ResourceUsageThread& ResourceUsageThread::singleton() { static NeverDestroyed resourceUsageThread; return resourceUsageThread; } void ResourceUsageThread::addObserver(void* key, std::function function) { auto& resourceUsageThread = ResourceUsageThread::singleton(); resourceUsageThread.createThreadIfNeeded(); { LockHolder locker(resourceUsageThread.m_lock); bool wasEmpty = resourceUsageThread.m_observers.isEmpty(); resourceUsageThread.m_observers.set(key, function); if (wasEmpty) resourceUsageThread.m_condition.notifyAll(); } } void ResourceUsageThread::removeObserver(void* key) { auto& resourceUsageThread = ResourceUsageThread::singleton(); { LockHolder locker(resourceUsageThread.m_lock); resourceUsageThread.m_observers.remove(key); } } void ResourceUsageThread::waitUntilObservers() { LockHolder locker(m_lock); while (m_observers.isEmpty()) m_condition.wait(m_lock); } void ResourceUsageThread::notifyObservers(ResourceUsageData& data) { callOnMainThread([data]() mutable { Vector> functions; { auto& resourceUsageThread = ResourceUsageThread::singleton(); LockHolder locker(resourceUsageThread.m_lock); copyValuesToVector(resourceUsageThread.m_observers, functions); } for (auto& function : functions) function(data); }); } void ResourceUsageThread::createThreadIfNeeded() { if (m_threadIdentifier) return; m_vm = &JSDOMWindow::commonVM(); m_threadIdentifier = createThread(threadCallback, this, "WebCore: ResourceUsage"); } void ResourceUsageThread::threadCallback(void* resourceUsageThread) { static_cast(resourceUsageThread)->threadBody(); } NO_RETURN void ResourceUsageThread::threadBody() { while (true) { // Only do work if we have observers. waitUntilObservers(); auto start = std::chrono::system_clock::now(); ResourceUsageData data; platformThreadBody(m_vm, data); notifyObservers(data); auto duration = std::chrono::duration_cast(std::chrono::system_clock::now() - start); auto difference = std::chrono::milliseconds(500) - duration; std::this_thread::sleep_for(difference); } } } // namespace WebCore #endif // ENABLE(RESOURCE_USAGE)