LCOV - code coverage report
Current view: top level - gfx/skia/skia/include/private - SkSemaphore.h (source / functions) Hit Total Coverage
Test: output.info Lines: 10 14 71.4 %
Date: 2017-07-14 16:53:18 Functions: 3 5 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 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             : #ifndef SkSemaphore_DEFINED
       9             : #define SkSemaphore_DEFINED
      10             : 
      11             : #include "../private/SkOnce.h"
      12             : #include "SkTypes.h"
      13             : #include <atomic>
      14             : 
      15             : class SkBaseSemaphore {
      16             : public:
      17         295 :     constexpr SkBaseSemaphore(int count = 0)
      18         295 :         : fCount(count), fOSSemaphore(nullptr) {}
      19             : 
      20             :     // Increment the counter n times.
      21             :     // Generally it's better to call signal(n) instead of signal() n times.
      22             :     void signal(int n = 1);
      23             : 
      24             :     // Decrement the counter by 1,
      25             :     // then if the counter is < 0, sleep this thread until the counter is >= 0.
      26             :     void wait();
      27             : 
      28             :     // If the counter is positive, decrement it by 1 and return true, otherwise return false.
      29             :     bool try_wait();
      30             : 
      31             :     // SkBaseSemaphore has no destructor.  Call this to clean it up.
      32             :     void cleanup();
      33             : 
      34             : private:
      35             :     // This implementation follows the general strategy of
      36             :     //     'A Lightweight Semaphore with Partial Spinning'
      37             :     // found here
      38             :     //     http://preshing.com/20150316/semaphores-are-surprisingly-versatile/
      39             :     // That article (and entire blog) are very much worth reading.
      40             :     //
      41             :     // We wrap an OS-provided semaphore with a user-space atomic counter that
      42             :     // lets us avoid interacting with the OS semaphore unless strictly required:
      43             :     // moving the count from >=0 to <0 or vice-versa, i.e. sleeping or waking threads.
      44             :     struct OSSemaphore;
      45             : 
      46             :     void osSignal(int n);
      47             :     void osWait();
      48             : 
      49             :     std::atomic<int> fCount;
      50             :     SkOnce           fOSSemaphoreOnce;
      51             :     OSSemaphore*     fOSSemaphore;
      52             : };
      53             : 
      54           0 : class SkSemaphore : public SkBaseSemaphore {
      55             : public:
      56             :     using SkBaseSemaphore::SkBaseSemaphore;
      57           0 :     ~SkSemaphore() { this->cleanup(); }
      58             : };
      59             : 
      60          32 : inline void SkBaseSemaphore::signal(int n) {
      61          64 :     int prev = fCount.fetch_add(n, std::memory_order_release);
      62             : 
      63             :     // We only want to call the OS semaphore when our logical count crosses
      64             :     // from <0 to >=0 (when we need to wake sleeping threads).
      65             :     //
      66             :     // This is easiest to think about with specific examples of prev and n.
      67             :     // If n == 5 and prev == -3, there are 3 threads sleeping and we signal
      68             :     // SkTMin(-(-3), 5) == 3 times on the OS semaphore, leaving the count at 2.
      69             :     //
      70             :     // If prev >= 0, no threads are waiting, SkTMin(-prev, n) is always <= 0,
      71             :     // so we don't call the OS semaphore, leaving the count at (prev + n).
      72          32 :     int toSignal = SkTMin(-prev, n);
      73          32 :     if (toSignal > 0) {
      74           0 :         this->osSignal(toSignal);
      75             :     }
      76          32 : }
      77             : 
      78          32 : inline void SkBaseSemaphore::wait() {
      79             :     // Since this fetches the value before the subtract, zero and below means that there are no
      80             :     // resources left, so the thread needs to wait.
      81          64 :     if (fCount.fetch_sub(1, std::memory_order_acquire) <= 0) {
      82           0 :         this->osWait();
      83             :     }
      84          32 : }
      85             : 
      86             : #endif//SkSemaphore_DEFINED

Generated by: LCOV version 1.13