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
13namespace fml {
14
15class 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
58namespace fml {
59
60class 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
100namespace fml {
101
102class 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
147namespace fml {
148
149Semaphore::Semaphore(uint32_t count) : _impl(new PlatformSemaphore(count)) {}
150
151Semaphore::~Semaphore() = default;
152
153bool Semaphore::IsValid() const {
154 return _impl->IsValid();
155}
156
157bool Semaphore::TryWait() {
158 return _impl->TryWait();
159}
160
161void Semaphore::Signal() {
162 return _impl->Signal();
163}
164
165} // namespace fml
166