Branch data Line data Source code
1 : : /* 2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved. 3 : : * Author: Thun Lu <thun.lu@zohomail.cn> 4 : : * Repo: https://github.com/thun-res/vlink 5 : : * _ __ __ _ __ 6 : : * | | / / / / (_) ____ / /__ 7 : : * | | / / / / / / / __ \ / //_/ 8 : : * | |/ / / /___ / / / / / / / ,< 9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_| 10 : : * 11 : : * Licensed under the Apache License, Version 2.0 (the "License"); 12 : : * you may not use this file except in compliance with the License. 13 : : * You may obtain a copy of the License at 14 : : * 15 : : * http://www.apache.org/licenses/LICENSE-2.0 16 : : * 17 : : * Unless required by applicable law or agreed to in writing, software 18 : : * distributed under the License is distributed on an "AS IS" BASIS, 19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 : : * See the License for the specific language governing permissions and 21 : : * limitations under the License. 22 : : */ 23 : : 24 : : #include "./base/semaphore.h" 25 : : 26 : : #include <chrono> 27 : : #include <mutex> 28 : : 29 : : #include "./base/condition_variable.h" 30 : : 31 : : namespace vlink { 32 : : 33 : : // Semaphore::Impl 34 : : struct Semaphore::Impl final { 35 : : mutable std::mutex mtx; 36 : : ConditionVariable cv; 37 : : size_t count{0}; 38 : : size_t initial_count{0}; 39 : : size_t in_flight_count{0}; 40 : : bool quit_flag{false}; 41 : : }; 42 : : 43 : : // Semaphore 44 : 19 : Semaphore::Semaphore(size_t count) noexcept : impl_(std::make_unique<Impl>()) { 45 : 19 : impl_->count = count; 46 : 19 : impl_->initial_count = count; 47 : 19 : } 48 : : 49 : 19 : Semaphore::~Semaphore() noexcept { 50 : 19 : std::unique_lock lock(impl_->mtx); 51 : 19 : impl_->quit_flag = true; 52 : 19 : impl_->cv.notify_all(); 53 : 38 : impl_->cv.wait(lock, [this]() -> bool { return impl_->in_flight_count == 0; }); 54 : 19 : } 55 : : 56 : 24 : bool Semaphore::acquire(size_t n, int timeout_ms) noexcept { 57 : 24 : std::unique_lock lock(impl_->mtx); 58 : 24 : ++impl_->in_flight_count; 59 : : 60 [ + + + + ]: 40 : auto predicate = [this, n] { return impl_->count >= n || impl_->quit_flag; }; 61 : : 62 : : bool acquired; 63 : : 64 [ + + ]: 24 : if (timeout_ms < 0) { 65 : 18 : impl_->cv.wait(lock, predicate); 66 : 18 : acquired = (impl_->count >= n); 67 : : } else { 68 [ + + + - ]: 6 : acquired = impl_->cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), predicate) && (impl_->count >= n); 69 : : } 70 : : 71 : : bool result; 72 : : 73 [ + + ]: 24 : if VUNLIKELY (impl_->quit_flag) { 74 : 4 : result = false; 75 : : } else { 76 [ + + ]: 20 : if (acquired) { 77 : 17 : impl_->count -= n; 78 : : } 79 : : 80 : 20 : result = acquired; 81 : : } 82 : : 83 [ + + ]: 24 : if (--impl_->in_flight_count == 0) { 84 : 19 : impl_->cv.notify_all(); 85 : : } 86 : : 87 : 48 : return result; 88 : 24 : } 89 : : 90 : 11 : void Semaphore::release(size_t n) noexcept { 91 : : { 92 : 11 : std::lock_guard lock(impl_->mtx); 93 : 11 : impl_->count += n; 94 : 11 : } 95 : : 96 : 11 : impl_->cv.notify_all(); 97 : 11 : } 98 : : 99 : 6 : void Semaphore::reset(bool interrupt_waiters) noexcept { 100 : : { 101 : 6 : std::lock_guard lock(impl_->mtx); 102 : 6 : impl_->count = impl_->initial_count; 103 : 6 : impl_->quit_flag = interrupt_waiters; 104 : 6 : } 105 : : 106 [ + + + - : 6 : if (interrupt_waiters || impl_->initial_count > 0) { + - ] 107 : 6 : impl_->cv.notify_all(); 108 : : } 109 : 6 : } 110 : : 111 : 25 : size_t Semaphore::get_count() const noexcept { 112 : 25 : std::lock_guard lock(impl_->mtx); 113 : : 114 : 25 : return impl_->count; 115 : 25 : } 116 : : 117 : : } // namespace vlink