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