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(
101 std::chrono::time_point<Clock, Duration>);
103 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
105 void lock_shared_count(Counter count);
107 void unlock_shared_count(Counter count);
109 [[nodiscard]]
bool try_lock_shared_count(Counter count);
111 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline,
115 enum class TryLockStatus { kSuccess, kTransientFailure, kPermanentFailure };
116 class SemaphoreWaitStrategy;
118 TryLockStatus DoTryLock(Counter count);
119 TryLockStatus LockFastPath(Counter count);
120 bool LockSlowPath(Deadline, Counter count);
122 impl::FastPimplWaitList lock_waiters_;
123 std::atomic<Counter> acquired_locks_;
124 std::atomic<Counter> capacity_;
138class Semaphore
final {
140 using Counter = std::size_t;
148 Semaphore(Semaphore&&) =
delete;
149 Semaphore(
const Semaphore&) =
delete;
150 Semaphore& operator=(Semaphore&&) =
delete;
151 Semaphore& operator=(
const Semaphore&) =
delete;
190 template <
typename Rep,
typename Period>
191 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
193 template <
typename Clock,
typename Duration>
194 [[nodiscard]]
bool try_lock_shared_until(
195 std::chrono::time_point<Clock, Duration>);
197 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
199 void lock_shared_count(Counter count);
201 void unlock_shared_count(Counter count);
203 [[nodiscard]]
bool try_lock_shared_count(Counter count);
205 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline,
209 CancellableSemaphore sem_;
213class SemaphoreLock
final {
215 SemaphoreLock()
noexcept =
default;
216 explicit SemaphoreLock(Semaphore&);
217 SemaphoreLock(Semaphore&, std::defer_lock_t)
noexcept;
218 SemaphoreLock(Semaphore&, std::try_to_lock_t);
219 SemaphoreLock(Semaphore&, std::adopt_lock_t)
noexcept;
221 template <
typename Rep,
typename Period>
222 SemaphoreLock(Semaphore&, std::chrono::duration<Rep, Period>);
224 template <
typename Clock,
typename Duration>
225 SemaphoreLock(Semaphore&, std::chrono::time_point<Clock, Duration>);
227 SemaphoreLock(Semaphore&, Deadline);
231 SemaphoreLock(
const SemaphoreLock&) =
delete;
232 SemaphoreLock(SemaphoreLock&&)
noexcept;
233 SemaphoreLock& operator=(
const SemaphoreLock&) =
delete;
234 SemaphoreLock& operator=(SemaphoreLock&&)
noexcept;
236 [[nodiscard]]
bool OwnsLock()
const noexcept;
237 explicit operator
bool()
const noexcept {
return OwnsLock(); }
242 template <
typename Rep,
typename Period>
243 bool TryLockFor(std::chrono::duration<Rep, Period>);
245 template <
typename Clock,
typename Duration>
246 bool TryLockUntil(std::chrono::time_point<Clock, Duration>);
248 bool TryLockUntil(Deadline);
254 Semaphore* sem_{
nullptr};
255 bool owns_lock_{
false};
258template <
typename Rep,
typename Period>
259bool Semaphore::try_lock_shared_for(
260 std::chrono::duration<Rep, Period> duration) {
261 return try_lock_shared_until(Deadline::FromDuration(duration));
264template <
typename Clock,
typename Duration>
265bool Semaphore::try_lock_shared_until(
266 std::chrono::time_point<Clock, Duration> until) {
267 return try_lock_shared_until(Deadline::FromTimePoint(until));
270template <
typename Rep,
typename Period>
271bool CancellableSemaphore::try_lock_shared_for(
272 std::chrono::duration<Rep, Period> duration) {
273 return try_lock_shared_until(Deadline::FromDuration(duration));
276template <
typename Clock,
typename Duration>
277bool CancellableSemaphore::try_lock_shared_until(
278 std::chrono::time_point<Clock, Duration> until) {
279 return try_lock_shared_until(Deadline::FromTimePoint(until));
282template <
typename Rep,
typename Period>
283SemaphoreLock::SemaphoreLock(Semaphore& sem,
284 std::chrono::duration<Rep, Period> duration)
286 TryLockFor(duration);
289template <
typename Clock,
typename Duration>
290SemaphoreLock::SemaphoreLock(Semaphore& sem,
291 std::chrono::time_point<Clock, Duration> until)
296template <
typename Rep,
typename Period>
297bool SemaphoreLock::TryLockFor(std::chrono::duration<Rep, Period> duration) {
298 return TryLockUntil(Deadline::FromDuration(duration));
301template <
typename Clock,
typename Duration>
302bool SemaphoreLock::TryLockUntil(
303 std::chrono::time_point<Clock, Duration> until) {
304 return TryLockUntil(Deadline::FromTimePoint(until));