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 
SkTaskGroup(SkExecutor & executor)11 SkTaskGroup::SkTaskGroup(SkExecutor& executor) : fPending(0), fExecutor(executor) {}
12 
add(std::function<void (void)> fn)13 void 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 
batch(int N,std::function<void (int)> fn)21 void 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 
done() const32 bool SkTaskGroup::done() const {
33     return fPending.load(std::memory_order_acquire) == 0;
34 }
35 
wait()36 void 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 
Enabler(int threads)46 SkTaskGroup::Enabler::Enabler(int threads) {
47     if (threads) {
48         fThreadPool = SkExecutor::MakeLIFOThreadPool(threads);
49         SkExecutor::SetDefault(fThreadPool.get());
50     }
51 }
52