11#include <userver/engine/deadline.hpp>
12#include <userver/engine/impl/wait_list_fwd.hpp>
14USERVER_NAMESPACE_BEGIN
20class UnreachableSemaphoreLockError
final :
public std::runtime_error {
22 using std::runtime_error::runtime_error;
26class SemaphoreLockCancelledError
final :
public std::runtime_error {
28 using std::runtime_error::runtime_error;
41class CancellableSemaphore
final {
43 using Counter = std::size_t;
49 ~CancellableSemaphore();
51 CancellableSemaphore(CancellableSemaphore&&) =
delete;
52 CancellableSemaphore(
const CancellableSemaphore&) =
delete;
53 CancellableSemaphore& operator=(CancellableSemaphore&&) =
delete;
54 CancellableSemaphore& operator=(
const CancellableSemaphore&) =
delete;
94 [[nodiscard]]
bool try_lock_shared();
96 template <
typename Rep,
typename Period>
97 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
99 template <
typename Clock,
typename Duration>
100 [[nodiscard]]
bool try_lock_shared_until(std::chrono::time_point<Clock, Duration>);
102 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
104 void lock_shared_count(Counter count);
106 void unlock_shared_count(Counter count);
108 [[nodiscard]]
bool try_lock_shared_count(Counter count);
110 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline, Counter count);
113 enum class TryLockStatus { kSuccess, kTransientFailure, kPermanentFailure };
114 class SemaphoreWaitStrategy;
116 TryLockStatus DoTryLock(Counter count);
117 TryLockStatus LockFastPath(Counter count);
118 bool LockSlowPath(Deadline, Counter count);
120 impl::FastPimplWaitList lock_waiters_;
121 std::atomic<Counter> acquired_locks_;
122 std::atomic<Counter> capacity_;
136class Semaphore
final {
138 using Counter = std::size_t;
146 Semaphore(Semaphore&&) =
delete;
147 Semaphore(
const Semaphore&) =
delete;
148 Semaphore& operator=(Semaphore&&) =
delete;
149 Semaphore& operator=(
const Semaphore&) =
delete;
188 template <
typename Rep,
typename Period>
189 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
191 template <
typename Clock,
typename Duration>
192 [[nodiscard]]
bool try_lock_shared_until(std::chrono::time_point<Clock, Duration>);
194 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
196 void lock_shared_count(Counter count);
198 void unlock_shared_count(Counter count);
200 [[nodiscard]]
bool try_lock_shared_count(Counter count);
202 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline, Counter count);
205 CancellableSemaphore sem_;
209class SemaphoreLock
final {
211 SemaphoreLock()
noexcept =
default;
212 explicit SemaphoreLock(Semaphore&);
213 SemaphoreLock(Semaphore&, std::defer_lock_t)
noexcept;
214 SemaphoreLock(Semaphore&, std::try_to_lock_t);
215 SemaphoreLock(Semaphore&, std::adopt_lock_t)
noexcept;
217 template <
typename Rep,
typename Period>
218 SemaphoreLock(Semaphore&, std::chrono::duration<Rep, Period>);
220 template <
typename Clock,
typename Duration>
221 SemaphoreLock(Semaphore&, std::chrono::time_point<Clock, Duration>);
223 SemaphoreLock(Semaphore&, Deadline);
227 SemaphoreLock(
const SemaphoreLock&) =
delete;
228 SemaphoreLock(SemaphoreLock&&)
noexcept;
229 SemaphoreLock& operator=(
const SemaphoreLock&) =
delete;
230 SemaphoreLock& operator=(SemaphoreLock&&)
noexcept;
232 [[nodiscard]]
bool OwnsLock()
const noexcept;
233 explicit operator
bool()
const noexcept {
return OwnsLock(); }
238 template <
typename Rep,
typename Period>
239 bool TryLockFor(std::chrono::duration<Rep, Period>);
241 template <
typename Clock,
typename Duration>
242 bool TryLockUntil(std::chrono::time_point<Clock, Duration>);
244 bool TryLockUntil(Deadline);
250 Semaphore* sem_{
nullptr};
251 bool owns_lock_{
false};
254template <
typename Rep,
typename Period>
255bool Semaphore::try_lock_shared_for(std::chrono::duration<Rep, Period> duration) {
256 return try_lock_shared_until(Deadline::FromDuration(duration));
259template <
typename Clock,
typename Duration>
260bool Semaphore::try_lock_shared_until(std::chrono::time_point<Clock, Duration> until) {
261 return try_lock_shared_until(Deadline::FromTimePoint(until));
264template <
typename Rep,
typename Period>
265bool CancellableSemaphore::try_lock_shared_for(std::chrono::duration<Rep, Period> duration) {
266 return try_lock_shared_until(Deadline::FromDuration(duration));
269template <
typename Clock,
typename Duration>
270bool CancellableSemaphore::try_lock_shared_until(std::chrono::time_point<Clock, Duration> until) {
271 return try_lock_shared_until(Deadline::FromTimePoint(until));
274template <
typename Rep,
typename Period>
275SemaphoreLock::SemaphoreLock(Semaphore& sem, std::chrono::duration<Rep, Period> duration) : sem_(&sem) {
276 TryLockFor(duration);
279template <
typename Clock,
typename Duration>
280SemaphoreLock::SemaphoreLock(Semaphore& sem, std::chrono::time_point<Clock, Duration> until) : sem_(&sem) {
284template <
typename Rep,
typename Period>
285bool SemaphoreLock::TryLockFor(std::chrono::duration<Rep, Period> duration) {
286 return TryLockUntil(Deadline::FromDuration(duration));
289template <
typename Clock,
typename Duration>
290bool SemaphoreLock::TryLockUntil(std::chrono::time_point<Clock, Duration> until) {
291 return TryLockUntil(Deadline::FromTimePoint(until));