xref: /aosp_15_r20/external/cronet/base/task/thread_pool/semaphore.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file is a clone of "v8/src/base/platform/semaphore.h" in v8.
6 // Keep in sync, especially when fixing bugs.
7 
8 // Copyright 2013 the V8 project authors. All rights reserved.
9 // Use of this source code is governed by a BSD-style license that can be
10 // found in the LICENSE file.
11 
12 #ifndef BASE_TASK_THREAD_POOL_SEMAPHORE_H_
13 #define BASE_TASK_THREAD_POOL_SEMAPHORE_H_
14 
15 #include "base/base_export.h"
16 #include "build/build_config.h"
17 
18 #if BUILDFLAG(IS_WIN)
19 #include <windows.h>
20 #elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_IOS)
21 #include <dispatch/dispatch.h>
22 #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL) || BUILDFLAG(IS_FUCHSIA)
23 #include <semaphore.h>
24 #else
25 #include "base/synchronization/condition_variable.h"
26 #include "base/synchronization/lock.h"
27 #endif
28 
29 namespace base {
30 class TimeDelta;
31 namespace internal {
32 
33 // ----------------------------------------------------------------------------
34 // Semaphore
35 //
36 // A semaphore object is a synchronization object that maintains a count. The
37 // count is decremented each time a thread completes a wait for the semaphore
38 // object and incremented each time a thread signals the semaphore. When the
39 // count reaches zero,  threads waiting for the semaphore blocks until the
40 // count becomes non-zero.
41 
42 class BASE_EXPORT Semaphore {
43  public:
44   explicit Semaphore(int count);
45   Semaphore(const Semaphore&) = delete;
46   Semaphore& operator=(const Semaphore&) = delete;
47   ~Semaphore();
48 
49   // Increments the semaphore counter.
50   void Signal();
51 
52   // Decrements the semaphore counter if it is positive, or blocks until it
53   // becomes positive and then decrements the counter.
54   //
55   // Wait's return "happens-after" |Signal| has completed. This means that it's
56   // safe for a WaitableEvent to synchronise its own destruction, like this:
57   //
58   //   Semaphore* s = new Semaphore;
59   //   SendToOtherThread(s);
60   //   s->Wait();
61   //   delete s;
62   void Wait();
63 
64   // Like Wait() but returns after `timeout` time has passed. If the call times
65   // out, the return value is false and the counter is unchanged. Otherwise the
66   // semaphore counter is decremented and true is returned.
67   //
68   // Note: Timeout is checked to be no more than DWORD-size (24 days).
69   [[nodiscard]] bool TimedWait(TimeDelta timeout);
70 
71 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_IOS)
72   using NativeHandle = dispatch_semaphore_t;
73 #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL) || BUILDFLAG(IS_FUCHSIA)
74   using NativeHandle = sem_t;
75 #elif BUILDFLAG(IS_WIN)
76   using NativeHandle = HANDLE;
77 #else  // default implementation
78   using NativeHandle = struct DefaultSemaphore {
79    private:
80     friend class Semaphore;
DefaultSemaphoreDefaultSemaphore81     DefaultSemaphore(int count) : condition_var(&lock), value(count) {}
82 
83     Lock lock;
84     ConditionVariable condition_var GUARDED_BY(lock);
85     int value GUARDED_BY(lock);
86   };
87 #endif
88 
89  private:
native_handle()90   NativeHandle& native_handle() { return native_handle_; }
native_handle()91   const NativeHandle& native_handle() const { return native_handle_; }
92 
93   NativeHandle native_handle_;
94 };
95 
96 }  // namespace internal
97 }  // namespace base
98 
99 #endif  // BASE_TASK_THREAD_POOL_SEMAPHORE_H_
100