libfoedus-core
FOEDUS Core Library
foedus::soc::SharedPolling Class Referencefinal

A polling-wait mechanism that can be placed in shared memory and used from multiple processes. More...

Detailed Description

A polling-wait mechanism that can be placed in shared memory and used from multiple processes.

This class automatically switches from spinning to polling with sleeps, then exponentially increases the sleep interval with some upper limit. Usually, a condition-variable packages such a functionality. BUT, we got so many troubles with glibc's bugs. A fix was pushed to upstream, but there will be many environments that still have older glibc. This class is pthread-free. No glibc versioning issue. Also, does not need signaling functionality in underlying OS/hardware, which we might not have in The Machine.

A typical usage is:

// waiter-side
while (true) {
uint64_t demand = polling.acquire_ticket();
// the check AFTER acquiring the ticket is required to avoid lost signal
if (real_condition_is_met) break;
polling.wait(demand);
}
// signaller-side
set_real_condition(); // set the real condition BEFORE signal. otherwise lost signal possible.
polling.signal();

Definition at line 63 of file shared_polling.hpp.

#include <shared_polling.hpp>

Public Member Functions

 SharedPolling ()
 
 SharedPolling (const SharedPolling &)=delete
 
SharedPollingoperator= (const SharedPolling &)=delete
 
void initialize ()
 
uint64_t acquire_ticket () const
 Gives the ticket to. More...
 
void wait (uint64_t demanded_ticket, uint64_t polling_spins=kDefaultPollingSpins, uint64_t max_interval_us=kDefaultPollingMaxIntervalUs) const
 Unconditionally wait for signal. More...
 
bool timedwait (uint64_t demanded_ticket, uint64_t timeout_microsec, uint64_t polling_spins=kDefaultPollingSpins, uint64_t max_interval_us=kDefaultPollingMaxIntervalUs) const
 Wait for signal up to the given timeout. More...
 
void signal ()
 Signal it to let waiters exit. More...
 

Constructor & Destructor Documentation

foedus::soc::SharedPolling::SharedPolling ( )
inline

Definition at line 65 of file shared_polling.hpp.

References initialize().

Here is the call graph for this function:

foedus::soc::SharedPolling::SharedPolling ( const SharedPolling )
delete

Member Function Documentation

uint64_t foedus::soc::SharedPolling::acquire_ticket ( ) const
SharedPolling& foedus::soc::SharedPolling::operator= ( const SharedPolling )
delete
void foedus::soc::SharedPolling::signal ( )

Signal it to let waiters exit.

This method first takes a release fence to avoid lost signal. The signaller should set the real condition variable before calling this method to avoid lost signal.

Definition at line 100 of file shared_polling.cpp.

References foedus::assorted::memory_fence_acq_rel(), and foedus::soc::ugly_atomic_inc().

Referenced by foedus::log::LogManagerPimpl::announce_new_durable_global_epoch(), foedus::xct::XctManagerPimpl::handle_epoch_chime(), foedus::snapshot::SnapshotManagerPimpl::handle_snapshot_triggered(), foedus::log::LogManagerPimpl::refresh_global_durable_epoch(), foedus::savepoint::SavepointManagerPimpl::savepoint_main(), foedus::soc::SharedRendezvous::signal(), foedus::savepoint::SavepointManagerPimpl::take_savepoint(), foedus::savepoint::SavepointManagerPimpl::take_savepoint_after_snapshot(), foedus::thread::ThreadRef::try_impersonate(), foedus::log::MetaLogger::uninitialize_once(), foedus::xct::XctManagerPimpl::uninitialize_once(), foedus::savepoint::SavepointManagerPimpl::uninitialize_once(), foedus::thread::ThreadPimpl::uninitialize_once(), foedus::snapshot::SnapshotManagerPimpl::wakeup(), foedus::xct::XctManagerPimpl::wakeup_epoch_chime_thread(), and foedus::snapshot::SnapshotManagerControlBlock::wakeup_snapshot_children().

100  {
101  assorted::memory_fence_acq_rel(); // well, atomic op implies a full barrier, but to make sure.
102  ugly_atomic_inc(&cur_ticket_);
103 }
void ugly_atomic_inc(uint32_t *address)
Definition: shared_cond.cpp:83
void memory_fence_acq_rel()
Equivalent to std::atomic_thread_fence(std::memory_order_acq_rel).

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::soc::SharedPolling::timedwait ( uint64_t  demanded_ticket,
uint64_t  timeout_microsec,
uint64_t  polling_spins = kDefaultPollingSpins,
uint64_t  max_interval_us = kDefaultPollingMaxIntervalUs 
) const

Wait for signal up to the given timeout.

Parameters
[in]demanded_ticketreturns when cur_ticket_ becomes this value or larger.
[in]timeout_microsectimeout in microsec
[in]polling_spinswe stop spinning and switch to sleeps after this number of spins
[in]max_interval_usthe sleep interval exponentially grows up to this value in microsec.
Returns
whether this thread received a signal

Definition at line 63 of file shared_polling.cpp.

References foedus::soc::get_now_microsec(), and foedus::soc::kInitialPollingIntervalUs.

Referenced by foedus::xct::XctManagerPimpl::handle_epoch_chime(), foedus::snapshot::SnapshotManagerPimpl::handle_snapshot_child(), foedus::savepoint::SavepointManagerPimpl::savepoint_main(), foedus::snapshot::SnapshotManagerPimpl::sleep_a_while(), foedus::snapshot::SnapshotManagerPimpl::trigger_snapshot_immediate(), foedus::thread::ImpersonateSession::wait(), foedus::soc::SharedRendezvous::wait_for(), foedus::thread::ImpersonateSession::wait_for(), foedus::xct::XctManagerPimpl::wait_for_current_global_epoch(), and foedus::log::LogManagerPimpl::wait_until_durable().

67  {
68  if (cur_ticket_ >= demanded_ticket) {
69  return true;
70  }
71  uint64_t start_us = get_now_microsec();
72  uint64_t end_us = start_us + timeout_microsec; // might overflow as a rare case, but not an issue
73  spin_poll(demanded_ticket, polling_spins);
74 
75  uint64_t interval_us = kInitialPollingIntervalUs;
76  while (cur_ticket_ < demanded_ticket) {
77  uint64_t now_us = get_now_microsec();
78  if (now_us > end_us) {
79  return false; // ah, oh, timeout
80  }
81  std::this_thread::sleep_for(std::chrono::microseconds(interval_us));
82  interval_us = std::min<uint64_t>(interval_us * 2ULL, max_interval_us);
83  }
84  return true;
85 }
uint64_t get_now_microsec()
const uint64_t kInitialPollingIntervalUs
Initial value of sleep interval in us.

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::soc::SharedPolling::wait ( uint64_t  demanded_ticket,
uint64_t  polling_spins = kDefaultPollingSpins,
uint64_t  max_interval_us = kDefaultPollingMaxIntervalUs 
) const

Unconditionally wait for signal.

Parameters
[in]demanded_ticketreturns when cur_ticket_ becomes this value or larger.
[in]polling_spinswe stop spinning and switch to sleeps after this number of spins
[in]max_interval_usthe sleep interval exponentially grows up to this value in microsec.

Definition at line 42 of file shared_polling.cpp.

References foedus::soc::kInitialPollingIntervalUs.

Referenced by foedus::xct::XctManagerPimpl::advance_current_global_epoch(), foedus::savepoint::SavepointManagerPimpl::take_savepoint(), foedus::savepoint::SavepointManagerPimpl::take_savepoint_after_snapshot(), foedus::soc::SharedRendezvous::wait(), foedus::xct::XctManagerPimpl::wait_for_current_global_epoch(), and foedus::log::LogManagerPimpl::wait_until_durable().

45  {
46  if (cur_ticket_ >= demanded_ticket) {
47  return;
48  }
49  spin_poll(demanded_ticket, polling_spins);
50 
51  uint64_t interval_us = kInitialPollingIntervalUs;
52  while (cur_ticket_ < demanded_ticket) {
53  std::this_thread::sleep_for(std::chrono::microseconds(interval_us));
54  interval_us = std::min<uint64_t>(interval_us * 2ULL, max_interval_us);
55  }
56 }
const uint64_t kInitialPollingIntervalUs
Initial value of sleep interval in us.

Here is the caller graph for this function:


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