1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "flutter/fml/synchronization/semaphore.h" |
6 | |
7 | #include "flutter/fml/build_config.h" |
8 | #include "flutter/fml/logging.h" |
9 | |
10 | #if OS_MACOSX |
11 | #include <dispatch/dispatch.h> |
12 | |
13 | namespace fml { |
14 | |
15 | class PlatformSemaphore { |
16 | public: |
17 | explicit PlatformSemaphore(uint32_t count) |
18 | : _sem(dispatch_semaphore_create(count)), _initial(count) {} |
19 | |
20 | ~PlatformSemaphore() { |
21 | for (uint32_t i = 0; i < _initial; ++i) { |
22 | Signal(); |
23 | } |
24 | if (_sem != nullptr) { |
25 | dispatch_release(reinterpret_cast<dispatch_object_t>(_sem)); |
26 | _sem = nullptr; |
27 | } |
28 | } |
29 | |
30 | bool IsValid() const { return _sem != nullptr; } |
31 | |
32 | bool TryWait() { |
33 | if (_sem == nullptr) { |
34 | return false; |
35 | } |
36 | |
37 | return dispatch_semaphore_wait(_sem, DISPATCH_TIME_NOW) == 0; |
38 | } |
39 | |
40 | void Signal() { |
41 | if (_sem != nullptr) { |
42 | dispatch_semaphore_signal(_sem); |
43 | } |
44 | } |
45 | |
46 | private: |
47 | dispatch_semaphore_t _sem; |
48 | const uint32_t _initial; |
49 | |
50 | FML_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); |
51 | }; |
52 | |
53 | } // namespace fml |
54 | |
55 | #elif OS_WIN |
56 | #include <windows.h> |
57 | |
58 | namespace fml { |
59 | |
60 | class PlatformSemaphore { |
61 | public: |
62 | explicit PlatformSemaphore(uint32_t count) |
63 | : _sem(CreateSemaphore(NULL, count, LONG_MAX, NULL)) {} |
64 | |
65 | ~PlatformSemaphore() { |
66 | if (_sem != nullptr) { |
67 | CloseHandle(_sem); |
68 | _sem = nullptr; |
69 | } |
70 | } |
71 | |
72 | bool IsValid() const { return _sem != nullptr; } |
73 | |
74 | bool TryWait() { |
75 | if (_sem == nullptr) { |
76 | return false; |
77 | } |
78 | |
79 | return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0; |
80 | } |
81 | |
82 | void Signal() { |
83 | if (_sem != nullptr) { |
84 | ReleaseSemaphore(_sem, 1, NULL); |
85 | } |
86 | } |
87 | |
88 | private: |
89 | HANDLE _sem; |
90 | |
91 | FML_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); |
92 | }; |
93 | |
94 | } // namespace fml |
95 | |
96 | #else |
97 | #include <semaphore.h> |
98 | #include "flutter/fml/eintr_wrapper.h" |
99 | |
100 | namespace fml { |
101 | |
102 | class PlatformSemaphore { |
103 | public: |
104 | explicit PlatformSemaphore(uint32_t count) |
105 | : valid_(::sem_init(&sem_, 0 /* not shared */, count) == 0) {} |
106 | |
107 | ~PlatformSemaphore() { |
108 | if (valid_) { |
109 | int result = ::sem_destroy(&sem_); |
110 | // Can only be EINVAL which should not be possible since we checked for |
111 | // validity. |
112 | FML_DCHECK(result == 0); |
113 | } |
114 | } |
115 | |
116 | bool IsValid() const { return valid_; } |
117 | |
118 | bool TryWait() { |
119 | if (!valid_) { |
120 | return false; |
121 | } |
122 | |
123 | return FML_HANDLE_EINTR(::sem_trywait(&sem_)) == 0; |
124 | } |
125 | |
126 | void Signal() { |
127 | if (!valid_) { |
128 | return; |
129 | } |
130 | |
131 | ::sem_post(&sem_); |
132 | |
133 | return; |
134 | } |
135 | |
136 | private: |
137 | bool valid_; |
138 | sem_t sem_; |
139 | |
140 | FML_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); |
141 | }; |
142 | |
143 | } // namespace fml |
144 | |
145 | #endif |
146 | |
147 | namespace fml { |
148 | |
149 | Semaphore::Semaphore(uint32_t count) : _impl(new PlatformSemaphore(count)) {} |
150 | |
151 | Semaphore::~Semaphore() = default; |
152 | |
153 | bool Semaphore::IsValid() const { |
154 | return _impl->IsValid(); |
155 | } |
156 | |
157 | bool Semaphore::TryWait() { |
158 | return _impl->TryWait(); |
159 | } |
160 | |
161 | void Semaphore::Signal() { |
162 | return _impl->Signal(); |
163 | } |
164 | |
165 | } // namespace fml |
166 | |