/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkExecutor.h" #include "SkTaskGroup.h" SkTaskGroup::SkTaskGroup(SkExecutor& executor) : fPending(0), fExecutor(executor) {} void SkTaskGroup::add(std::function<void(void)> fn) { fPending.fetch_add(+1, std::memory_order_relaxed); fExecutor.add([=] { fn(); fPending.fetch_add(-1, std::memory_order_release); }); } void SkTaskGroup::batch(int N, std::function<void(int)> fn) { // TODO: I really thought we had some sort of more clever chunking logic. fPending.fetch_add(+N, std::memory_order_relaxed); for (int i = 0; i < N; i++) { fExecutor.add([=] { fn(i); fPending.fetch_add(-1, std::memory_order_release); }); } } bool SkTaskGroup::done() const { return fPending.load(std::memory_order_acquire) == 0; } void SkTaskGroup::wait() { // Actively help the executor do work until our task group is done. // This lets SkTaskGroups nest arbitrarily deep on a single SkExecutor: // no thread ever blocks waiting for others to do its work. // (We may end up doing work that's not part of our task group. That's fine.) while (!this->done()) { fExecutor.borrow(); } } SkTaskGroup::Enabler::Enabler(int threads) { if (threads) { fThreadPool = SkExecutor::MakeLIFOThreadPool(threads); SkExecutor::SetDefault(fThreadPool.get()); } }