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