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