123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- //////////////////////////////////////////////////////////////////////////////
- //
- // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
- // Software License, Version 1.0. (See accompanying file
- // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // See http://www.boost.org/libs/interprocess for documentation.
- //
- //////////////////////////////////////////////////////////////////////////////
- #ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
- #define BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
- #ifndef BOOST_CONFIG_HPP
- # include <boost/config.hpp>
- #endif
- #
- #if defined(BOOST_HAS_PRAGMA_ONCE)
- # pragma once
- #endif
- #include <boost/interprocess/detail/config_begin.hpp>
- #include <boost/interprocess/detail/workaround.hpp>
- #include <boost/interprocess/sync/scoped_lock.hpp>
- #include <boost/interprocess/sync/detail/locks.hpp>
- #include <limits>
- namespace boost {
- namespace interprocess {
- namespace ipcdetail {
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- //
- // Condition variable algorithm taken from pthreads-win32 discussion.
- //
- // The algorithm was developed by Alexander Terekhov in colaboration with
- // Louis Thomas.
- //
- // Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
- //
- // semBlockLock - bin.semaphore
- // semBlockQueue - semaphore
- // mtxExternal - mutex or CS
- // mtxUnblockLock - mutex or CS
- // nWaitersGone - int
- // nWaitersBlocked - int
- // nWaitersToUnblock - int
- //
- // wait( timeout ) {
- //
- // [auto: register int result ] // error checking omitted
- // [auto: register int nSignalsWasLeft ]
- // [auto: register int nWaitersWasGone ]
- //
- // sem_wait( semBlockLock );
- // nWaitersBlocked++;
- // sem_post( semBlockLock );
- //
- // unlock( mtxExternal );
- // bTimedOut = sem_wait( semBlockQueue,timeout );
- //
- // lock( mtxUnblockLock );
- // if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
- // if ( bTimedOut ) { // timeout (or canceled)
- // if ( 0 != nWaitersBlocked ) {
- // nWaitersBlocked--;
- // }
- // else {
- // nWaitersGone++; // count spurious wakeups.
- // }
- // }
- // if ( 0 == --nWaitersToUnblock ) {
- // if ( 0 != nWaitersBlocked ) {
- // sem_post( semBlockLock ); // open the gate.
- // nSignalsWasLeft = 0; // do not open the gate
- // // below again.
- // }
- // else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
- // nWaitersGone = 0;
- // }
- // }
- // }
- // else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
- // // spurious semaphore :-)
- // sem_wait( semBlockLock );
- // nWaitersBlocked -= nWaitersGone; // something is going on here
- // // - test of timeouts? :-)
- // sem_post( semBlockLock );
- // nWaitersGone = 0;
- // }
- // unlock( mtxUnblockLock );
- //
- // if ( 1 == nSignalsWasLeft ) {
- // if ( 0 != nWaitersWasGone ) {
- // // sem_adjust( semBlockQueue,-nWaitersWasGone );
- // while ( nWaitersWasGone-- ) {
- // sem_wait( semBlockQueue ); // better now than spurious later
- // }
- // } sem_post( semBlockLock ); // open the gate
- // }
- //
- // lock( mtxExternal );
- //
- // return ( bTimedOut ) ? ETIMEOUT : 0;
- // }
- //
- // signal(bAll) {
- //
- // [auto: register int result ]
- // [auto: register int nSignalsToIssue]
- //
- // lock( mtxUnblockLock );
- //
- // if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- // if ( 0 == nWaitersBlocked ) { // NO-OP
- // return unlock( mtxUnblockLock );
- // }
- // if (bAll) {
- // nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
- // nWaitersBlocked = 0;
- // }
- // else {
- // nSignalsToIssue = 1;
- // nWaitersToUnblock++;
- // nWaitersBlocked--;
- // }
- // }
- // else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- // sem_wait( semBlockLock ); // close the gate
- // if ( 0 != nWaitersGone ) {
- // nWaitersBlocked -= nWaitersGone;
- // nWaitersGone = 0;
- // }
- // if (bAll) {
- // nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
- // nWaitersBlocked = 0;
- // }
- // else {
- // nSignalsToIssue = nWaitersToUnblock = 1;
- // nWaitersBlocked--;
- // }
- // }
- // else { // NO-OP
- // return unlock( mtxUnblockLock );
- // }
- //
- // unlock( mtxUnblockLock );
- // sem_post( semBlockQueue,nSignalsToIssue );
- // return result;
- // }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- // Required interface for ConditionMembers
- // class ConditionMembers
- // {
- // typedef implementation_defined semaphore_type;
- // typedef implementation_defined mutex_type;
- // typedef implementation_defined integer_type;
- //
- // integer_type &get_nwaiters_blocked()
- // integer_type &get_nwaiters_gone()
- // integer_type &get_nwaiters_to_unblock()
- // semaphore_type &get_sem_block_queue()
- // semaphore_type &get_sem_block_lock()
- // mutex_type &get_mtx_unblock_lock()
- // };
- //
- // Must be initialized as following
- //
- // get_nwaiters_blocked() == 0
- // get_nwaiters_gone() == 0
- // get_nwaiters_to_unblock() == 0
- // get_sem_block_queue() == initial count 0
- // get_sem_block_lock() == initial count 1
- // get_mtx_unblock_lock() (unlocked)
- //
- template<class ConditionMembers>
- class condition_algorithm_8a
- {
- private:
- condition_algorithm_8a();
- ~condition_algorithm_8a();
- condition_algorithm_8a(const condition_algorithm_8a &);
- condition_algorithm_8a &operator=(const condition_algorithm_8a &);
- typedef typename ConditionMembers::semaphore_type semaphore_type;
- typedef typename ConditionMembers::mutex_type mutex_type;
- typedef typename ConditionMembers::integer_type integer_type;
- public:
- template<bool TimeoutEnabled, class Lock, class TimePoint>
- static bool wait ( ConditionMembers &data, Lock &lock, const TimePoint &abs_time)
- {
- //Initialize to avoid warnings
- integer_type nsignals_was_left = 0;
- integer_type nwaiters_was_gone = 0;
- data.get_sem_block_lock().wait();
- ++data.get_nwaiters_blocked();
- data.get_sem_block_lock().post();
- //Unlock external lock and program for relock
- lock_inverter<Lock> inverted_lock(lock);
- scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
- bool bTimedOut = !do_sem_timed_wait(data.get_sem_block_queue(), abs_time, bool_<TimeoutEnabled>());
- {
- scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock());
- if ( 0 != (nsignals_was_left = data.get_nwaiters_to_unblock()) ) {
- if ( bTimedOut ) { // timeout (or canceled)
- if ( 0 != data.get_nwaiters_blocked() ) {
- data.get_nwaiters_blocked()--;
- }
- else {
- data.get_nwaiters_gone()++; // count spurious wakeups.
- }
- }
- if ( 0 == --data.get_nwaiters_to_unblock() ) {
- if ( 0 != data.get_nwaiters_blocked() ) {
- data.get_sem_block_lock().post(); // open the gate.
- nsignals_was_left = 0; // do not open the gate below again.
- }
- else if ( 0 != (nwaiters_was_gone = data.get_nwaiters_gone()) ) {
- data.get_nwaiters_gone() = 0;
- }
- }
- }
- else if ( (std::numeric_limits<integer_type>::max)()/2
- == ++data.get_nwaiters_gone() ) { // timeout/canceled or spurious semaphore :-)
- data.get_sem_block_lock().wait();
- data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); // something is going on here - test of timeouts? :-)
- data.get_sem_block_lock().post();
- data.get_nwaiters_gone() = 0;
- }
- //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
- }
- if ( 1 == nsignals_was_left ) {
- if ( 0 != nwaiters_was_gone ) {
- // sem_adjust( data.get_sem_block_queue(),-nwaiters_was_gone );
- while ( nwaiters_was_gone-- ) {
- data.get_sem_block_queue().wait(); // better now than spurious later
- }
- }
- data.get_sem_block_lock().post(); // open the gate
- }
- //lock.lock(); called from unlocker destructor
- return ( bTimedOut ) ? false : true;
- }
- static void signal(ConditionMembers &data, bool broadcast)
- {
- integer_type nsignals_to_issue;
- {
- scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock());
- if ( 0 != data.get_nwaiters_to_unblock() ) { // the gate is closed!!!
- if ( 0 == data.get_nwaiters_blocked() ) { // NO-OP
- //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
- return;
- }
- if (broadcast) {
- data.get_nwaiters_to_unblock() += nsignals_to_issue = data.get_nwaiters_blocked();
- data.get_nwaiters_blocked() = 0;
- }
- else {
- nsignals_to_issue = 1;
- data.get_nwaiters_to_unblock()++;
- data.get_nwaiters_blocked()--;
- }
- }
- else if ( data.get_nwaiters_blocked() > data.get_nwaiters_gone() ) { // HARMLESS RACE CONDITION!
- data.get_sem_block_lock().wait(); // close the gate
- if ( 0 != data.get_nwaiters_gone() ) {
- data.get_nwaiters_blocked() -= data.get_nwaiters_gone();
- data.get_nwaiters_gone() = 0;
- }
- if (broadcast) {
- nsignals_to_issue = data.get_nwaiters_to_unblock() = data.get_nwaiters_blocked();
- data.get_nwaiters_blocked() = 0;
- }
- else {
- nsignals_to_issue = data.get_nwaiters_to_unblock() = 1;
- data.get_nwaiters_blocked()--;
- }
- }
- else { // NO-OP
- //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
- return;
- }
- //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
- }
- data.get_sem_block_queue().post(nsignals_to_issue);
- }
- private:
- template<class TimePoint>
- static bool do_sem_timed_wait(semaphore_type &sem, const TimePoint &abs_time, bool_<true>)
- { return sem.timed_wait(abs_time); }
- template<class TimePoint>
- static bool do_sem_timed_wait(semaphore_type &sem, const TimePoint &, bool_<false>)
- { sem.wait(); return true; }
- };
- template<class ConditionMembers>
- class condition_8a_wrapper
- {
- //Non-copyable
- condition_8a_wrapper(const condition_8a_wrapper &);
- condition_8a_wrapper &operator=(const condition_8a_wrapper &);
- ConditionMembers m_data;
- typedef condition_algorithm_8a<ConditionMembers> algo_type;
- public:
- condition_8a_wrapper(){}
- //Compiler-generated destructor is OK
- //~condition_8a_wrapper(){}
- ConditionMembers & get_members()
- { return m_data; }
- const ConditionMembers & get_members() const
- { return m_data; }
- void notify_one()
- { algo_type::signal(m_data, false); }
- void notify_all()
- { algo_type::signal(m_data, true); }
- template <typename L>
- void wait(L& lock)
- {
- if (!lock)
- throw lock_exception();
- algo_type::template wait<false>(m_data, lock, 0);
- }
- template <typename L, typename Pr>
- void wait(L& lock, Pr pred)
- {
- if (!lock)
- throw lock_exception();
- while (!pred())
- algo_type::template wait<false>(m_data, lock, 0);
- }
- template <typename L, class TimePoint>
- bool timed_wait(L& lock, const TimePoint &abs_time)
- {
- if (!lock)
- throw lock_exception();
- return algo_type::template wait<true>(m_data, lock, abs_time);
- }
- template <typename L, class TimePoint, typename Pr>
- bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred)
- {
- if (!lock)
- throw lock_exception();
- while (!pred()){
- if (!algo_type::template wait<true>(m_data, lock, abs_time))
- return pred();
- }
- return true;
- }
- };
- } //namespace ipcdetail
- } //namespace interprocess
- } //namespace boost
- #include <boost/interprocess/detail/config_end.hpp>
- #endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
|