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