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;
93 [[nodiscard]]
bool try_lock_shared();
95 template <
typename Rep,
typename Period>
96 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
98 template <
typename Clock,
typename Duration>
99 [[nodiscard]]
bool try_lock_shared_until(
100 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,
114 enum class TryLockStatus { kSuccess, kTransientFailure, kPermanentFailure };
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;
182 [[nodiscard]]
bool try_lock_shared();
184 template <
typename Rep,
typename Period>
185 [[nodiscard]]
bool try_lock_shared_for(std::chrono::duration<Rep, Period>);
187 template <
typename Clock,
typename Duration>
188 [[nodiscard]]
bool try_lock_shared_until(
189 std::chrono::time_point<Clock, Duration>);
191 [[nodiscard]]
bool try_lock_shared_until(Deadline deadline);
193 void lock_shared_count(Counter count);
195 void unlock_shared_count(Counter count);
197 [[nodiscard]]
bool try_lock_shared_count(Counter count);
199 [[nodiscard]]
bool try_lock_shared_until_count(Deadline deadline,
203 CancellableSemaphore sem_;
207class SemaphoreLock
final {
209 SemaphoreLock()
noexcept =
default;
210 explicit SemaphoreLock(Semaphore&);
211 SemaphoreLock(Semaphore&, std::defer_lock_t)
noexcept;
212 SemaphoreLock(Semaphore&, std::try_to_lock_t);
213 SemaphoreLock(Semaphore&, std::adopt_lock_t)
noexcept;
215 template <
typename Rep,
typename Period>
216 SemaphoreLock(Semaphore&, std::chrono::duration<Rep, Period>);
218 template <
typename Clock,
typename Duration>
219 SemaphoreLock(Semaphore&, std::chrono::time_point<Clock, Duration>);
221 SemaphoreLock(Semaphore&, Deadline);
225 SemaphoreLock(
const SemaphoreLock&) =
delete;
226 SemaphoreLock(SemaphoreLock&&)
noexcept;
227 SemaphoreLock& operator=(
const SemaphoreLock&) =
delete;
228 SemaphoreLock& operator=(SemaphoreLock&&)
noexcept;
230 bool OwnsLock()
const noexcept;
231 explicit operator
bool()
const noexcept {
return OwnsLock(); }
236 template <
typename Rep,
typename Period>
237 bool TryLockFor(std::chrono::duration<Rep, Period>);
239 template <
typename Clock,
typename Duration>
240 bool TryLockUntil(std::chrono::time_point<Clock, Duration>);
242 bool TryLockUntil(Deadline);
248 Semaphore* sem_{
nullptr};
249 bool owns_lock_{
false};
252template <
typename Rep,
typename Period>
253bool Semaphore::try_lock_shared_for(
254 std::chrono::duration<Rep, Period> duration) {
255 return try_lock_shared_until(Deadline::FromDuration(duration));
258template <
typename Clock,
typename Duration>
259bool Semaphore::try_lock_shared_until(
260 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(
266 std::chrono::duration<Rep, Period> duration) {
267 return try_lock_shared_until(Deadline::FromDuration(duration));
270template <
typename Clock,
typename Duration>
271bool CancellableSemaphore::try_lock_shared_until(
272 std::chrono::time_point<Clock, Duration> until) {
273 return try_lock_shared_until(Deadline::FromTimePoint(until));
276template <
typename Rep,
typename Period>
277SemaphoreLock::SemaphoreLock(Semaphore& sem,
278 std::chrono::duration<Rep, Period> duration)
280 TryLockFor(duration);
283template <
typename Clock,
typename Duration>
284SemaphoreLock::SemaphoreLock(Semaphore& sem,
285 std::chrono::time_point<Clock, Duration> until)
290template <
typename Rep,
typename Period>
291bool SemaphoreLock::TryLockFor(std::chrono::duration<Rep, Period> duration) {
292 return TryLockUntil(Deadline::FromDuration(duration));
295template <
typename Clock,
typename Duration>
296bool SemaphoreLock::TryLockUntil(
297 std::chrono::time_point<Clock, Duration> until) {
298 return TryLockUntil(Deadline::FromTimePoint(until));