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));