LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkExecutor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 50 2.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2017 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 "SkMakeUnique.h"
      10             : #include "SkMutex.h"
      11             : #include "SkSemaphore.h"
      12             : #include "SkSpinlock.h"
      13             : #include "SkTArray.h"
      14             : #include "SkThreadUtils.h"
      15             : 
      16             : #if defined(_MSC_VER)
      17             :     #include <windows.h>
      18             :     static int num_cores() {
      19             :         SYSTEM_INFO sysinfo;
      20             :         GetNativeSystemInfo(&sysinfo);
      21             :         return (int)sysinfo.dwNumberOfProcessors;
      22             :     }
      23             : #else
      24             :     #include <unistd.h>
      25           0 :     static int num_cores() {
      26           0 :         return (int)sysconf(_SC_NPROCESSORS_ONLN);
      27             :     }
      28             : #endif
      29             : 
      30           0 : SkExecutor::~SkExecutor() {}
      31             : 
      32             : // The default default SkExecutor is an SkTrivialExecutor, which just runs the work right away.
      33           0 : class SkTrivialExecutor final : public SkExecutor {
      34           0 :     void add(std::function<void(void)> work) override {
      35           0 :         work();
      36           0 :     }
      37             : };
      38             : 
      39           3 : static SkTrivialExecutor gTrivial;
      40             : static SkExecutor* gDefaultExecutor = &gTrivial;
      41             : 
      42           0 : SkExecutor& SkExecutor::GetDefault() {
      43           0 :     return *gDefaultExecutor;
      44             : }
      45           0 : void SkExecutor::SetDefault(SkExecutor* executor) {
      46           0 :     gDefaultExecutor = executor ? executor : &gTrivial;
      47           0 : }
      48             : 
      49             : // An SkThreadPool is an executor that runs work on a fixed pool of OS threads.
      50             : class SkThreadPool final : public SkExecutor {
      51             : public:
      52           0 :     explicit SkThreadPool(int threads) {
      53           0 :         for (int i = 0; i < threads; i++) {
      54           0 :             fThreads.emplace_back(new SkThread(&Loop, this));
      55           0 :             fThreads.back()->start();
      56             :         }
      57           0 :     }
      58             : 
      59           0 :     ~SkThreadPool() override {
      60             :         // Signal each thread that it's time to shut down.
      61           0 :         for (int i = 0; i < fThreads.count(); i++) {
      62           0 :             this->add(nullptr);
      63             :         }
      64             :         // Wait for each thread to shut down.
      65           0 :         for (int i = 0; i < fThreads.count(); i++) {
      66           0 :             fThreads[i]->join();
      67             :         }
      68           0 :     }
      69             : 
      70           0 :     virtual void add(std::function<void(void)> work) override {
      71             :         // Add some work to our pile of work to do.
      72             :         {
      73           0 :             SkAutoExclusive lock(fWorkLock);
      74           0 :             fWork.emplace_back(std::move(work));
      75             :         }
      76             :         // Tell the Loop() threads to pick it up.
      77           0 :         fWorkAvailable.signal(1);
      78           0 :     }
      79             : 
      80           0 :     virtual void borrow() override {
      81             :         // If there is work waiting, do it.
      82           0 :         if (fWorkAvailable.try_wait()) {
      83           0 :             SkAssertResult(this->do_work());
      84             :         }
      85           0 :     }
      86             : 
      87             : private:
      88             :     // This method should be called only when fWorkAvailable indicates there's work to do.
      89           0 :     bool do_work() {
      90           0 :         std::function<void(void)> work;
      91             :         {
      92           0 :             SkAutoExclusive lock(fWorkLock);
      93           0 :             SkASSERT(!fWork.empty());        // TODO: if (fWork.empty()) { return true; } ?
      94           0 :             work = std::move(fWork.back());
      95           0 :             fWork.pop_back();
      96             :         }
      97             : 
      98           0 :         if (!work) {
      99           0 :             return false;  // This is Loop()'s signal to shut down.
     100             :         }
     101             : 
     102           0 :         work();
     103           0 :         return true;
     104             :     }
     105             : 
     106           0 :     static void Loop(void* ctx) {
     107           0 :         auto pool = (SkThreadPool*)ctx;
     108           0 :         do {
     109           0 :             pool->fWorkAvailable.wait();
     110             :         } while (pool->do_work());
     111           0 :     }
     112             : 
     113             :     // Both SkMutex and SkSpinlock can work here.
     114             :     using Lock = SkMutex;
     115             : 
     116             :     SkTArray<std::unique_ptr<SkThread>> fThreads;
     117             :     SkTArray<std::function<void(void)>> fWork;
     118             :     Lock                                fWorkLock;
     119             :     SkSemaphore                         fWorkAvailable;
     120             : };
     121             : 
     122           0 : std::unique_ptr<SkExecutor> SkExecutor::MakeThreadPool(int threads) {
     123           0 :     return skstd::make_unique<SkThreadPool>(threads > 0 ? threads : num_cores());
     124             : }

Generated by: LCOV version 1.13