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:
PlatformSemaphore(uint32_t count)17 explicit PlatformSemaphore(uint32_t count)
18 : _sem(dispatch_semaphore_create(count)), _initial(count) {}
19
~PlatformSemaphore()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
IsValid() const30 bool IsValid() const { return _sem != nullptr; }
31
TryWait()32 bool TryWait() {
33 if (_sem == nullptr) {
34 return false;
35 }
36
37 return dispatch_semaphore_wait(_sem, DISPATCH_TIME_NOW) == 0;
38 }
39
Signal()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:
PlatformSemaphore(uint32_t count)62 explicit PlatformSemaphore(uint32_t count)
63 : _sem(CreateSemaphore(NULL, count, LONG_MAX, NULL)) {}
64
~PlatformSemaphore()65 ~PlatformSemaphore() {
66 if (_sem != nullptr) {
67 CloseHandle(_sem);
68 _sem = nullptr;
69 }
70 }
71
IsValid() const72 bool IsValid() const { return _sem != nullptr; }
73
TryWait()74 bool TryWait() {
75 if (_sem == nullptr) {
76 return false;
77 }
78
79 return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0;
80 }
81
Signal()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:
PlatformSemaphore(uint32_t count)104 explicit PlatformSemaphore(uint32_t count)
105 : valid_(::sem_init(&sem_, 0 /* not shared */, count) == 0) {}
106
~PlatformSemaphore()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
IsValid() const116 bool IsValid() const { return valid_; }
117
TryWait()118 bool TryWait() {
119 if (!valid_) {
120 return false;
121 }
122
123 return FML_HANDLE_EINTR(::sem_trywait(&sem_)) == 0;
124 }
125
Signal()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
Semaphore(uint32_t count)149 Semaphore::Semaphore(uint32_t count) : _impl(new PlatformSemaphore(count)) {}
150
151 Semaphore::~Semaphore() = default;
152
IsValid() const153 bool Semaphore::IsValid() const {
154 return _impl->IsValid();
155 }
156
TryWait()157 bool Semaphore::TryWait() {
158 return _impl->TryWait();
159 }
160
Signal()161 void Semaphore::Signal() {
162 return _impl->Signal();
163 }
164
165 } // namespace fml
166