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