Mixe for Privacy and Anonymity in the Internet
Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
spsc_sema::LightweightSemaphore Class Reference

#include <atomicops.h>

Collaboration diagram for spsc_sema::LightweightSemaphore:

Public Types

typedef std::make_signed< std::size_t >::type ssize_t
 

Public Member Functions

AE_NO_TSAN LightweightSemaphore (ssize_t initialCount=0)
 
bool tryWait () AE_NO_TSAN
 
void wait () AE_NO_TSAN
 
bool wait (std::int64_t timeout_usecs) AE_NO_TSAN
 
void signal (ssize_t count=1) AE_NO_TSAN
 
ssize_t availableApprox () const AE_NO_TSAN
 

Private Member Functions

bool waitWithPartialSpinning (std::int64_t timeout_usecs=-1) AE_NO_TSAN
 

Private Attributes

weak_atomic< ssize_tm_count
 
Semaphore m_sema
 

Detailed Description

Definition at line 564 of file atomicops.h.

Member Typedef Documentation

◆ ssize_t

typedef std::make_signed<std::size_t>::type spsc_sema::LightweightSemaphore::ssize_t

Definition at line 567 of file atomicops.h.

Constructor & Destructor Documentation

◆ LightweightSemaphore()

AE_NO_TSAN spsc_sema::LightweightSemaphore::LightweightSemaphore ( ssize_t  initialCount = 0)
inline

Definition at line 617 of file atomicops.h.

617  : m_count(initialCount)
618  {
619  assert(initialCount >= 0);
620  }
weak_atomic< ssize_t > m_count
Definition: atomicops.h:570

Member Function Documentation

◆ availableApprox()

ssize_t spsc_sema::LightweightSemaphore::availableApprox ( ) const
inline

Definition at line 654 of file atomicops.h.

655  {
656  ssize_t count = m_count.load();
657  return count > 0 ? count : 0;
658  }
std::make_signed< std::size_t >::type ssize_t
Definition: atomicops.h:567
AE_FORCEINLINE T load() const AE_NO_TSAN
Definition: atomicops.h:302

References weak_atomic< T >::load(), and m_count.

Here is the call graph for this function:

◆ signal()

void spsc_sema::LightweightSemaphore::signal ( ssize_t  count = 1)
inline

Definition at line 643 of file atomicops.h.

644  {
645  assert(count >= 0);
646  ssize_t oldCount = m_count.fetch_add_release(count);
647  assert(oldCount >= -1);
648  if (oldCount < 0)
649  {
650  m_sema.signal(1);
651  }
652  }
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN
Definition: atomicops.h:309

References weak_atomic< T >::fetch_add_release(), m_count, and m_sema.

Here is the call graph for this function:

◆ tryWait()

bool spsc_sema::LightweightSemaphore::tryWait ( )
inline

Definition at line 622 of file atomicops.h.

623  {
624  if (m_count.load() > 0)
625  {
627  return true;
628  }
629  return false;
630  }
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN
Definition: atomicops.h:304

References weak_atomic< T >::fetch_add_acquire(), weak_atomic< T >::load(), and m_count.

Referenced by wait().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ wait() [1/2]

void spsc_sema::LightweightSemaphore::wait ( )
inline

Definition at line 632 of file atomicops.h.

633  {
634  if (!tryWait())
636  }
bool tryWait() AE_NO_TSAN
Definition: atomicops.h:622
bool waitWithPartialSpinning(std::int64_t timeout_usecs=-1) AE_NO_TSAN
Definition: atomicops.h:573

References tryWait(), and waitWithPartialSpinning().

Here is the call graph for this function:

◆ wait() [2/2]

bool spsc_sema::LightweightSemaphore::wait ( std::int64_t  timeout_usecs)
inline

Definition at line 638 of file atomicops.h.

639  {
640  return tryWait() || waitWithPartialSpinning(timeout_usecs);
641  }

References tryWait(), and waitWithPartialSpinning().

Here is the call graph for this function:

◆ waitWithPartialSpinning()

bool spsc_sema::LightweightSemaphore::waitWithPartialSpinning ( std::int64_t  timeout_usecs = -1)
inlineprivate

Definition at line 573 of file atomicops.h.

574  {
575  ssize_t oldCount;
576  // Is there a better way to set the initial spin count?
577  // If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
578  // as threads start hitting the kernel semaphore.
579  int spin = 10000;
580  while (--spin >= 0)
581  {
582  if (m_count.load() > 0)
583  {
585  return true;
586  }
587  compiler_fence(memory_order_acquire); // Prevent the compiler from collapsing the loop.
588  }
589  oldCount = m_count.fetch_add_acquire(-1);
590  if (oldCount > 0)
591  return true;
592  if (timeout_usecs < 0)
593  {
594  m_sema.wait();
595  return true;
596  }
597  if (m_sema.timed_wait(timeout_usecs))
598  return true;
599  // At this point, we've timed out waiting for the semaphore, but the
600  // count is still decremented indicating we may still be waiting on
601  // it. So we have to re-adjust the count, but only if the semaphore
602  // wasn't signaled enough times for us too since then. If it was, we
603  // need to release the semaphore too.
604  while (true)
605  {
606  oldCount = m_count.fetch_add_release(1);
607  if (oldCount < 0)
608  return false; // successfully restored things to the way they were
609  // Oh, the producer thread just signaled the semaphore after all. Try again:
610  oldCount = m_count.fetch_add_acquire(-1);
611  if (oldCount > 0 && m_sema.try_wait())
612  return true;
613  }
614  }
@ memory_order_acquire
Definition: atomicops.h:84
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
Definition: atomicops.h:191

References compiler_fence(), weak_atomic< T >::fetch_add_acquire(), weak_atomic< T >::fetch_add_release(), weak_atomic< T >::load(), m_count, m_sema, and memory_order_acquire.

Referenced by wait().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_count

weak_atomic<ssize_t> spsc_sema::LightweightSemaphore::m_count
private

Definition at line 570 of file atomicops.h.

Referenced by availableApprox(), signal(), tryWait(), and waitWithPartialSpinning().

◆ m_sema

Semaphore spsc_sema::LightweightSemaphore::m_sema
private

Definition at line 571 of file atomicops.h.

Referenced by signal(), and waitWithPartialSpinning().


The documentation for this class was generated from the following file: