| Index: include/private/SkSemaphore.h
|
| diff --git a/include/private/SkSemaphore.h b/include/private/SkSemaphore.h
|
| index adee574bb76c9c1398c4c0528f2cde9d4d39172e..cb2f58da4a27724fa49a1be40080a67ee6c158fd 100644
|
| --- a/include/private/SkSemaphore.h
|
| +++ b/include/private/SkSemaphore.h
|
| @@ -8,26 +8,43 @@
|
| #ifndef SkSemaphore_DEFINED
|
| #define SkSemaphore_DEFINED
|
|
|
| -#include "../private/SkOnce.h"
|
| #include "SkTypes.h"
|
| -#include <atomic>
|
| +#include "../private/SkAtomics.h"
|
| +#include "../private/SkOncePtr.h"
|
|
|
| -class SkSemaphore {
|
| -public:
|
| - constexpr SkSemaphore(int count = 0)
|
| - : fCount(count), fOSSemaphore(nullptr) {}
|
| +struct SkBaseSemaphore {
|
|
|
| - ~SkSemaphore();
|
| + // Increment the counter by 1.
|
| + // This is a specialization for supporting SkMutex.
|
| + void signal() {
|
| + // Since this fetches the value before the add, 0 indicates that this thread is running and
|
| + // no threads are waiting, -1 and below means that threads are waiting, but only signal 1
|
| + // thread to run.
|
| + if (sk_atomic_fetch_add(&fCount, 1, sk_memory_order_release) < 0) {
|
| + this->osSignal(1);
|
| + }
|
| + }
|
|
|
| - // Increment the counter n times.
|
| - // Generally it's better to call signal(n) instead of signal() n times.
|
| - void signal(int n = 1);
|
| + // Increment the counter N times.
|
| + // Generally it's better to call signal(N) instead of signal() N times.
|
| + void signal(int N);
|
|
|
| // Decrement the counter by 1,
|
| // then if the counter is <= 0, sleep this thread until the counter is > 0.
|
| - void wait();
|
| + void wait() {
|
| + // Since this fetches the value before the subtract, zero and below means that there are no
|
| + // resources left, so the thread needs to wait.
|
| + if (sk_atomic_fetch_sub(&fCount, 1, sk_memory_order_acquire) <= 0) {
|
| + this->osWait();
|
| + }
|
| + }
|
|
|
| -private:
|
| + struct OSSemaphore;
|
| +
|
| + void osSignal(int n);
|
| + void osWait();
|
| + void deleteSemaphore();
|
| +
|
| // This implementation follows the general strategy of
|
| // 'A Lightweight Semaphore with Partial Spinning'
|
| // found here
|
| @@ -37,40 +54,33 @@
|
| // We wrap an OS-provided semaphore with a user-space atomic counter that
|
| // lets us avoid interacting with the OS semaphore unless strictly required:
|
| // moving the count from >0 to <=0 or vice-versa, i.e. sleeping or waking threads.
|
| - struct OSSemaphore;
|
| -
|
| - void osSignal(int n);
|
| - void osWait();
|
| -
|
| - std::atomic<int> fCount;
|
| - SkOnce fOSSemaphoreOnce;
|
| - OSSemaphore* fOSSemaphore;
|
| + int fCount;
|
| + SkBaseOncePtr<OSSemaphore> fOSSemaphore;
|
| };
|
|
|
| -inline void SkSemaphore::signal(int n) {
|
| - int prev = fCount.fetch_add(n, std::memory_order_release);
|
| +/**
|
| + * SkSemaphore is a fast mostly-user-space semaphore.
|
| + *
|
| + * A semaphore is logically an atomic integer with a few special properties:
|
| + * - The integer always starts at 0.
|
| + * - You can only increment or decrement it, never read or write it.
|
| + * - Increment is spelled 'signal()'; decrement is spelled 'wait()'.
|
| + * - If a call to wait() decrements the counter to <= 0,
|
| + * the calling thread sleeps until another thread signal()s it back above 0.
|
| + */
|
| +class SkSemaphore : SkNoncopyable {
|
| +public:
|
| + // Initializes the counter to 0.
|
| + // (Though all current implementations could start from an arbitrary value.)
|
| + SkSemaphore();
|
| + ~SkSemaphore();
|
|
|
| - // We only want to call the OS semaphore when our logical count crosses
|
| - // from <= 0 to >0 (when we need to wake sleeping threads).
|
| - //
|
| - // This is easiest to think about with specific examples of prev and n.
|
| - // If n == 5 and prev == -3, there are 3 threads sleeping and we signal
|
| - // SkTMin(-(-3), 5) == 3 times on the OS semaphore, leaving the count at 2.
|
| - //
|
| - // If prev >= 0, no threads are waiting, SkTMin(-prev, n) is always <= 0,
|
| - // so we don't call the OS semaphore, leaving the count at (prev + n).
|
| - int toSignal = SkTMin(-prev, n);
|
| - if (toSignal > 0) {
|
| - this->osSignal(toSignal);
|
| - }
|
| -}
|
| + void wait();
|
|
|
| -inline void SkSemaphore::wait() {
|
| - // Since this fetches the value before the subtract, zero and below means that there are no
|
| - // resources left, so the thread needs to wait.
|
| - if (fCount.fetch_sub(1, std::memory_order_acquire) <= 0) {
|
| - this->osWait();
|
| - }
|
| -}
|
| + void signal(int n = 1);
|
| +
|
| +private:
|
| + SkBaseSemaphore fBaseSemaphore;
|
| +};
|
|
|
| #endif//SkSemaphore_DEFINED
|
|
|