1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkExecutor.h" 9cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ciSkTaskGroup::SkTaskGroup(SkExecutor& executor) : fPending(0), fExecutor(executor) {} 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_civoid SkTaskGroup::add(std::function<void(void)> fn) { 14cb93a386Sopenharmony_ci fPending.fetch_add(+1, std::memory_order_relaxed); 15cb93a386Sopenharmony_ci fExecutor.add([this, fn{std::move(fn)}] { 16cb93a386Sopenharmony_ci fn(); 17cb93a386Sopenharmony_ci fPending.fetch_add(-1, std::memory_order_release); 18cb93a386Sopenharmony_ci }); 19cb93a386Sopenharmony_ci} 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_civoid SkTaskGroup::batch(int N, std::function<void(int)> fn) { 22cb93a386Sopenharmony_ci // TODO: I really thought we had some sort of more clever chunking logic. 23cb93a386Sopenharmony_ci fPending.fetch_add(+N, std::memory_order_relaxed); 24cb93a386Sopenharmony_ci for (int i = 0; i < N; i++) { 25cb93a386Sopenharmony_ci fExecutor.add([=] { 26cb93a386Sopenharmony_ci fn(i); 27cb93a386Sopenharmony_ci fPending.fetch_add(-1, std::memory_order_release); 28cb93a386Sopenharmony_ci }); 29cb93a386Sopenharmony_ci } 30cb93a386Sopenharmony_ci} 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_cibool SkTaskGroup::done() const { 33cb93a386Sopenharmony_ci return fPending.load(std::memory_order_acquire) == 0; 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_civoid SkTaskGroup::wait() { 37cb93a386Sopenharmony_ci // Actively help the executor do work until our task group is done. 38cb93a386Sopenharmony_ci // This lets SkTaskGroups nest arbitrarily deep on a single SkExecutor: 39cb93a386Sopenharmony_ci // no thread ever blocks waiting for others to do its work. 40cb93a386Sopenharmony_ci // (We may end up doing work that's not part of our task group. That's fine.) 41cb93a386Sopenharmony_ci while (!this->done()) { 42cb93a386Sopenharmony_ci fExecutor.borrow(); 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci} 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ciSkTaskGroup::Enabler::Enabler(int threads) { 47cb93a386Sopenharmony_ci if (threads) { 48cb93a386Sopenharmony_ci fThreadPool = SkExecutor::MakeLIFOThreadPool(threads); 49cb93a386Sopenharmony_ci SkExecutor::SetDefault(fThreadPool.get()); 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci} 52