| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/fml/synchronization/semaphore.h" |
| |
| #include "flutter/fml/build_config.h" |
| #include "flutter/fml/logging.h" |
| |
| #if FML_OS_MACOSX |
| #include <dispatch/dispatch.h> |
| |
| namespace fml { |
| |
| class PlatformSemaphore { |
| public: |
| explicit PlatformSemaphore(uint32_t count) |
| : _sem(dispatch_semaphore_create(count)), _initial(count) {} |
| |
| ~PlatformSemaphore() { |
| for (uint32_t i = 0; i < _initial; ++i) { |
| Signal(); |
| } |
| if (_sem != nullptr) { |
| dispatch_release(reinterpret_cast<dispatch_object_t>(_sem)); |
| _sem = nullptr; |
| } |
| } |
| |
| bool IsValid() const { return _sem != nullptr; } |
| |
| bool Wait() { |
| if (_sem == nullptr) { |
| return false; |
| } |
| return dispatch_semaphore_wait(_sem, DISPATCH_TIME_FOREVER) == 0; |
| } |
| |
| bool TryWait() { |
| if (_sem == nullptr) { |
| return false; |
| } |
| |
| return dispatch_semaphore_wait(_sem, DISPATCH_TIME_NOW) == 0; |
| } |
| |
| void Signal() { |
| if (_sem != nullptr) { |
| dispatch_semaphore_signal(_sem); |
| } |
| } |
| |
| private: |
| dispatch_semaphore_t _sem; |
| const uint32_t _initial; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); |
| }; |
| |
| } // namespace fml |
| |
| #elif FML_OS_WIN |
| #include <windows.h> |
| |
| namespace fml { |
| |
| class PlatformSemaphore { |
| public: |
| explicit PlatformSemaphore(uint32_t count) |
| : _sem(CreateSemaphore(NULL, count, LONG_MAX, NULL)) {} |
| |
| ~PlatformSemaphore() { |
| if (_sem != nullptr) { |
| CloseHandle(_sem); |
| _sem = nullptr; |
| } |
| } |
| |
| bool IsValid() const { return _sem != nullptr; } |
| |
| bool Wait() { |
| if (_sem == nullptr) { |
| return false; |
| } |
| |
| return WaitForSingleObject(_sem, INFINITE) == WAIT_OBJECT_0; |
| } |
| |
| bool TryWait() { |
| if (_sem == nullptr) { |
| return false; |
| } |
| |
| return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0; |
| } |
| |
| void Signal() { |
| if (_sem != nullptr) { |
| ReleaseSemaphore(_sem, 1, NULL); |
| } |
| } |
| |
| private: |
| HANDLE _sem; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); |
| }; |
| |
| } // namespace fml |
| |
| #else |
| #include <semaphore.h> |
| #include "flutter/fml/eintr_wrapper.h" |
| |
| namespace fml { |
| |
| class PlatformSemaphore { |
| public: |
| explicit PlatformSemaphore(uint32_t count) |
| : valid_(::sem_init(&sem_, 0 /* not shared */, count) == 0) {} |
| |
| ~PlatformSemaphore() { |
| if (valid_) { |
| int result = ::sem_destroy(&sem_); |
| (void)result; |
| // Can only be EINVAL which should not be possible since we checked for |
| // validity. |
| FML_DCHECK(result == 0); |
| } |
| } |
| |
| bool IsValid() const { return valid_; } |
| |
| bool Wait() { |
| if (!valid_) { |
| return false; |
| } |
| |
| return FML_HANDLE_EINTR(::sem_wait(&sem_)) == 0; |
| } |
| |
| bool TryWait() { |
| if (!valid_) { |
| return false; |
| } |
| |
| return FML_HANDLE_EINTR(::sem_trywait(&sem_)) == 0; |
| } |
| |
| void Signal() { |
| if (!valid_) { |
| return; |
| } |
| |
| ::sem_post(&sem_); |
| |
| return; |
| } |
| |
| private: |
| bool valid_; |
| sem_t sem_; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); |
| }; |
| |
| } // namespace fml |
| |
| #endif |
| |
| namespace fml { |
| |
| Semaphore::Semaphore(uint32_t count) : _impl(new PlatformSemaphore(count)) {} |
| |
| Semaphore::~Semaphore() = default; |
| |
| bool Semaphore::IsValid() const { |
| return _impl->IsValid(); |
| } |
| |
| bool Semaphore::Wait() { |
| return _impl->Wait(); |
| } |
| |
| bool Semaphore::TryWait() { |
| return _impl->TryWait(); |
| } |
| |
| void Semaphore::Signal() { |
| return _impl->Signal(); |
| } |
| |
| } // namespace fml |