11#include <userver/engine/deadline.hpp>
12#include <userver/engine/impl/wait_list_fwd.hpp>
16#include <userver/utils/assert.hpp>
18USERVER_NAMESPACE_BEGIN
24class UnreachableSemaphoreLockError
final :
public std::runtime_error {
26 using std::runtime_error::runtime_error;
30class SemaphoreLockCancelledError
final :
public std::runtime_error {
32 using std::runtime_error::runtime_error;
45class CancellableSemaphore
final {
47 using Counter = std::size_t;
53 ~CancellableSemaphore();
55 CancellableSemaphore(CancellableSemaphore&&) =
delete;
56 CancellableSemaphore(
const CancellableSemaphore&) =
delete;
57 CancellableSemaphore& operator=(CancellableSemaphore&&) =
delete;
58 CancellableSemaphore& operator=(
const CancellableSemaphore&) =
delete;
98 [[nodiscard]]
bool try_lock_shared();
100 template <
typename Rep,
typename Period>
101 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
103 template <
typename Clock,
typename Duration>
104 [[nodiscard]]
bool try_lock_shared_until(
105 std::chrono::time_point<Clock, Duration>);
107 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
109 void lock_shared_count(Counter count);
111 void unlock_shared_count(Counter count);
113 [[nodiscard]]
bool try_lock_shared_count(Counter count);
115 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline,
119 enum class TryLockStatus { kSuccess, kTransientFailure, kPermanentFailure };
121 TryLockStatus DoTryLock(Counter count);
122 TryLockStatus LockFastPath(Counter count);
123 bool LockSlowPath(Deadline, Counter count);
125 impl::FastPimplWaitList lock_waiters_;
126 std::atomic<Counter> acquired_locks_;
127 std::atomic<Counter> capacity_;
141class Semaphore
final {
143 using Counter = std::size_t;
151 Semaphore(Semaphore&&) =
delete;
152 Semaphore(
const Semaphore&) =
delete;
153 Semaphore& operator=(Semaphore&&) =
delete;
154 Semaphore& operator=(
const Semaphore&) =
delete;
193 template <
typename Rep,
typename Period>
194 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
196 template <
typename Clock,
typename Duration>
197 [[nodiscard]]
bool try_lock_shared_until(
198 std::chrono::time_point<Clock, Duration>);
200 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
202 void lock_shared_count(Counter count);
204 void unlock_shared_count(Counter count);
206 [[nodiscard]]
bool try_lock_shared_count(Counter count);
208 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline,
212 CancellableSemaphore sem_;
216class SemaphoreLock
final {
218 SemaphoreLock()
noexcept =
default;
219 explicit SemaphoreLock(Semaphore&);
220 SemaphoreLock(Semaphore&, std::defer_lock_t)
noexcept;
221 SemaphoreLock(Semaphore&, std::try_to_lock_t);
222 SemaphoreLock(Semaphore&, std::adopt_lock_t)
noexcept;
224 template <
typename Rep,
typename Period>
225 SemaphoreLock(Semaphore&, std::chrono::duration<Rep, Period>);
227 template <
typename Clock,
typename Duration>
228 SemaphoreLock(Semaphore&, std::chrono::time_point<Clock, Duration>);
230 SemaphoreLock(Semaphore&, Deadline);
234 SemaphoreLock(
const SemaphoreLock&) =
delete;
235 SemaphoreLock(SemaphoreLock&&)
noexcept;
236 SemaphoreLock& operator=(
const SemaphoreLock&) =
delete;
237 SemaphoreLock& operator=(SemaphoreLock&&)
noexcept;
239 [[nodiscard]]
bool OwnsLock()
const noexcept;
240 explicit operator
bool()
const noexcept {
return OwnsLock(); }
245 template <
typename Rep,
typename Period>
246 bool TryLockFor(std::chrono::duration<Rep, Period>);
248 template <
typename Clock,
typename Duration>
249 bool TryLockUntil(std::chrono::time_point<Clock, Duration>);
251 bool TryLockUntil(Deadline);
257 Semaphore* sem_{
nullptr};
258 bool owns_lock_{
false};
261template <
typename Rep,
typename Period>
262bool Semaphore::try_lock_shared_for(
263 std::chrono::duration<Rep, Period> duration) {
264 return try_lock_shared_until(Deadline::FromDuration(duration));
267template <
typename Clock,
typename Duration>
268bool Semaphore::try_lock_shared_until(
269 std::chrono::time_point<Clock, Duration> until) {
270 return try_lock_shared_until(Deadline::FromTimePoint(until));
273template <
typename Rep,
typename Period>
274bool CancellableSemaphore::try_lock_shared_for(
275 std::chrono::duration<Rep, Period> duration) {
276 return try_lock_shared_until(Deadline::FromDuration(duration));
279template <
typename Clock,
typename Duration>
280bool CancellableSemaphore::try_lock_shared_until(
281 std::chrono::time_point<Clock, Duration> until) {
282 return try_lock_shared_until(Deadline::FromTimePoint(until));
285template <
typename Rep,
typename Period>
286SemaphoreLock::SemaphoreLock(Semaphore& sem,
287 std::chrono::duration<Rep, Period> duration)
289 TryLockFor(duration);
292template <
typename Clock,
typename Duration>
293SemaphoreLock::SemaphoreLock(Semaphore& sem,
294 std::chrono::time_point<Clock, Duration> until)
299template <
typename Rep,
typename Period>
300bool SemaphoreLock::TryLockFor(std::chrono::duration<Rep, Period> duration) {
301 return TryLockUntil(Deadline::FromDuration(duration));
304template <
typename Clock,
typename Duration>
305bool SemaphoreLock::TryLockUntil(
306 std::chrono::time_point<Clock, Duration> until) {
307 return TryLockUntil(Deadline::FromTimePoint(until));