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