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