Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:53:29

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
0004 // Software License, Version 1.0. (See accompanying file
0005 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // See http://www.boost.org/libs/interprocess for documentation.
0008 //
0009 //////////////////////////////////////////////////////////////////////////////
0010 
0011 #ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
0012 #define BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP
0013 
0014 #ifndef BOOST_CONFIG_HPP
0015 #  include <boost/config.hpp>
0016 #endif
0017 #
0018 #if defined(BOOST_HAS_PRAGMA_ONCE)
0019 #  pragma once
0020 #endif
0021 
0022 #include <boost/interprocess/detail/config_begin.hpp>
0023 #include <boost/interprocess/detail/workaround.hpp>
0024 #include <boost/interprocess/sync/scoped_lock.hpp>
0025 #include <boost/interprocess/sync/detail/locks.hpp>
0026 #include <limits>
0027 
0028 namespace boost {
0029 namespace interprocess {
0030 namespace ipcdetail {
0031 
0032 ////////////////////////////////////////////////////////////////////////
0033 ////////////////////////////////////////////////////////////////////////
0034 ////////////////////////////////////////////////////////////////////////
0035 //
0036 // Condition variable algorithm taken from pthreads-win32 discussion.
0037 //
0038 // The algorithm was developed by Alexander Terekhov in colaboration with
0039 // Louis Thomas.
0040 //
0041 //     Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
0042 //
0043 // semBlockLock - bin.semaphore
0044 // semBlockQueue - semaphore
0045 // mtxExternal - mutex or CS
0046 // mtxUnblockLock - mutex or CS
0047 // nWaitersGone - int
0048 // nWaitersBlocked - int
0049 // nWaitersToUnblock - int
0050 //
0051 // wait( timeout ) {
0052 //
0053 //   [auto: register int result          ]     // error checking omitted
0054 //   [auto: register int nSignalsWasLeft ]
0055 //   [auto: register int nWaitersWasGone ]
0056 //
0057 //   sem_wait( semBlockLock );
0058 //   nWaitersBlocked++;
0059 //   sem_post( semBlockLock );
0060 //
0061 //   unlock( mtxExternal );
0062 //   bTimedOut = sem_wait( semBlockQueue,timeout );
0063 //
0064 //   lock( mtxUnblockLock );
0065 //   if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
0066 //     if ( bTimedOut ) {                       // timeout (or canceled)
0067 //       if ( 0 != nWaitersBlocked ) {
0068 //         nWaitersBlocked--;
0069 //       }
0070 //       else {
0071 //         nWaitersGone++;                     // count spurious wakeups.
0072 //       }
0073 //     }
0074 //     if ( 0 == --nWaitersToUnblock ) {
0075 //       if ( 0 != nWaitersBlocked ) {
0076 //         sem_post( semBlockLock );           // open the gate.
0077 //         nSignalsWasLeft = 0;                // do not open the gate
0078 //                                             // below again.
0079 //       }
0080 //       else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
0081 //         nWaitersGone = 0;
0082 //       }
0083 //     }
0084 //   }
0085 //   else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
0086 //                                             // spurious semaphore :-)
0087 //     sem_wait( semBlockLock );
0088 //     nWaitersBlocked -= nWaitersGone;     // something is going on here
0089 //                                          //  - test of timeouts? :-)
0090 //     sem_post( semBlockLock );
0091 //     nWaitersGone = 0;
0092 //   }
0093 //   unlock( mtxUnblockLock );
0094 //
0095 //   if ( 1 == nSignalsWasLeft ) {
0096 //     if ( 0 != nWaitersWasGone ) {
0097 //       // sem_adjust( semBlockQueue,-nWaitersWasGone );
0098 //       while ( nWaitersWasGone-- ) {
0099 //         sem_wait( semBlockQueue );       // better now than spurious later
0100 //       }
0101 //     } sem_post( semBlockLock );          // open the gate
0102 //   }
0103 //
0104 //   lock( mtxExternal );
0105 //
0106 //   return ( bTimedOut ) ? ETIMEOUT : 0;
0107 // }
0108 //
0109 // signal(bAll) {
0110 //
0111 //   [auto: register int result         ]
0112 //   [auto: register int nSignalsToIssue]
0113 //
0114 //   lock( mtxUnblockLock );
0115 //
0116 //   if ( 0 != nWaitersToUnblock ) {        // the gate is closed!!!
0117 //     if ( 0 == nWaitersBlocked ) {        // NO-OP
0118 //       return unlock( mtxUnblockLock );
0119 //     }
0120 //     if (bAll) {
0121 //       nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
0122 //       nWaitersBlocked = 0;
0123 //     }
0124 //     else {
0125 //       nSignalsToIssue = 1;
0126 //       nWaitersToUnblock++;
0127 //       nWaitersBlocked--;
0128 //     }
0129 //   }
0130 //   else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
0131 //     sem_wait( semBlockLock );                  // close the gate
0132 //     if ( 0 != nWaitersGone ) {
0133 //       nWaitersBlocked -= nWaitersGone;
0134 //       nWaitersGone = 0;
0135 //     }
0136 //     if (bAll) {
0137 //       nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
0138 //       nWaitersBlocked = 0;
0139 //     }
0140 //     else {
0141 //       nSignalsToIssue = nWaitersToUnblock = 1;
0142 //       nWaitersBlocked--;
0143 //     }
0144 //   }
0145 //   else { // NO-OP
0146 //     return unlock( mtxUnblockLock );
0147 //   }
0148 //
0149 //   unlock( mtxUnblockLock );
0150 //   sem_post( semBlockQueue,nSignalsToIssue );
0151 //   return result;
0152 // }
0153 ////////////////////////////////////////////////////////////////////////
0154 ////////////////////////////////////////////////////////////////////////
0155 ////////////////////////////////////////////////////////////////////////
0156 
0157 
0158 // Required interface for ConditionMembers
0159 // class ConditionMembers
0160 // {
0161 //    typedef implementation_defined semaphore_type;
0162 //    typedef implementation_defined mutex_type;
0163 //    typedef implementation_defined integer_type;
0164 //
0165 //    integer_type    &get_nwaiters_blocked()
0166 //    integer_type    &get_nwaiters_gone()
0167 //    integer_type    &get_nwaiters_to_unblock()
0168 //    semaphore_type  &get_sem_block_queue()
0169 //    semaphore_type  &get_sem_block_lock()
0170 //    mutex_type      &get_mtx_unblock_lock()
0171 // };
0172 //
0173 // Must be initialized as following
0174 //
0175 //    get_nwaiters_blocked() == 0
0176 //    get_nwaiters_gone() == 0
0177 //    get_nwaiters_to_unblock() == 0
0178 //    get_sem_block_queue() == initial count 0
0179 //    get_sem_block_lock() == initial count 1
0180 //    get_mtx_unblock_lock() (unlocked)
0181 //
0182 template<class ConditionMembers>
0183 class condition_algorithm_8a
0184 {
0185    private:
0186    condition_algorithm_8a();
0187    ~condition_algorithm_8a();
0188    condition_algorithm_8a(const condition_algorithm_8a &);
0189    condition_algorithm_8a &operator=(const condition_algorithm_8a &);
0190 
0191    typedef typename ConditionMembers::semaphore_type  semaphore_type;
0192    typedef typename ConditionMembers::mutex_type      mutex_type;
0193    typedef typename ConditionMembers::integer_type    integer_type;
0194 
0195    public:
0196    template<bool TimeoutEnabled, class Lock, class TimePoint>
0197    static bool wait  ( ConditionMembers &data, Lock &lock, const TimePoint &abs_time)
0198    {
0199       //Initialize to avoid warnings
0200       integer_type nsignals_was_left = 0;
0201       integer_type nwaiters_was_gone = 0;
0202 
0203       data.get_sem_block_lock().wait();
0204       ++data.get_nwaiters_blocked();
0205       data.get_sem_block_lock().post();
0206 
0207       //Unlock external lock and program for relock
0208       lock_inverter<Lock> inverted_lock(lock);
0209       scoped_lock<lock_inverter<Lock> >   external_unlock(inverted_lock);
0210 
0211       bool bTimedOut = !do_sem_timed_wait(data.get_sem_block_queue(), abs_time, bool_<TimeoutEnabled>());
0212 
0213       {
0214          scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock());
0215          if ( 0 != (nsignals_was_left = data.get_nwaiters_to_unblock()) ) {
0216             if ( bTimedOut ) {                       // timeout (or canceled)
0217                if ( 0 != data.get_nwaiters_blocked() ) {
0218                   data.get_nwaiters_blocked()--;
0219                }
0220                else {
0221                   data.get_nwaiters_gone()++;                     // count spurious wakeups.
0222                }
0223             }
0224             if ( 0 == --data.get_nwaiters_to_unblock() ) {
0225                if ( 0 != data.get_nwaiters_blocked() ) {
0226                   data.get_sem_block_lock().post();          // open the gate.
0227                   nsignals_was_left = 0;          // do not open the gate below again.
0228                }
0229                else if ( 0 != (nwaiters_was_gone = data.get_nwaiters_gone()) ) {
0230                   data.get_nwaiters_gone() = 0;
0231                }
0232             }
0233          }
0234          else if ( (std::numeric_limits<integer_type>::max)()/2
0235                    == ++data.get_nwaiters_gone() ) { // timeout/canceled or spurious semaphore :-)
0236             data.get_sem_block_lock().wait();
0237             data.get_nwaiters_blocked() -= data.get_nwaiters_gone();       // something is going on here - test of timeouts? :-)
0238             data.get_sem_block_lock().post();
0239             data.get_nwaiters_gone() = 0;
0240          }
0241          //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
0242       }
0243 
0244       if ( 1 == nsignals_was_left ) {
0245          if ( 0 != nwaiters_was_gone ) {
0246             // sem_adjust( data.get_sem_block_queue(),-nwaiters_was_gone );
0247             while ( nwaiters_was_gone-- ) {
0248                data.get_sem_block_queue().wait();       // better now than spurious later
0249             }
0250          }
0251          data.get_sem_block_lock().post(); // open the gate
0252       }
0253 
0254       //lock.lock(); called from unlocker destructor
0255 
0256       return ( bTimedOut ) ? false : true;
0257    }
0258 
0259    static void signal(ConditionMembers &data, bool broadcast)
0260    {
0261       integer_type nsignals_to_issue;
0262 
0263       {
0264          scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock());
0265 
0266          if ( 0 != data.get_nwaiters_to_unblock() ) {        // the gate is closed!!!
0267             if ( 0 == data.get_nwaiters_blocked() ) {        // NO-OP
0268                //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
0269                return;
0270             }
0271             if (broadcast) {
0272                data.get_nwaiters_to_unblock() += nsignals_to_issue = data.get_nwaiters_blocked();
0273                data.get_nwaiters_blocked() = 0;
0274             }
0275             else {
0276                nsignals_to_issue = 1;
0277                data.get_nwaiters_to_unblock()++;
0278                data.get_nwaiters_blocked()--;
0279             }
0280          }
0281          else if ( data.get_nwaiters_blocked() > data.get_nwaiters_gone() ) { // HARMLESS RACE CONDITION!
0282             data.get_sem_block_lock().wait();                      // close the gate
0283             if ( 0 != data.get_nwaiters_gone() ) {
0284                data.get_nwaiters_blocked() -= data.get_nwaiters_gone();
0285                data.get_nwaiters_gone() = 0;
0286             }
0287             if (broadcast) {
0288                nsignals_to_issue = data.get_nwaiters_to_unblock() = data.get_nwaiters_blocked();
0289                data.get_nwaiters_blocked() = 0;
0290             }
0291             else {
0292                nsignals_to_issue = data.get_nwaiters_to_unblock() = 1;
0293                data.get_nwaiters_blocked()--;
0294             }
0295          }
0296          else { // NO-OP
0297             //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
0298             return;
0299          }
0300          //locker's destructor triggers data.get_mtx_unblock_lock().unlock()
0301       }
0302       data.get_sem_block_queue().post(nsignals_to_issue);
0303    }
0304 
0305    private:
0306    template<class TimePoint>
0307    static bool do_sem_timed_wait(semaphore_type &sem, const TimePoint &abs_time, bool_<true>)
0308    {  return sem.timed_wait(abs_time); }
0309 
0310    template<class TimePoint>
0311    static bool do_sem_timed_wait(semaphore_type &sem, const TimePoint &, bool_<false>)
0312    {  sem.wait();  return true;  }
0313 };
0314 
0315 template<class ConditionMembers>
0316 class condition_8a_wrapper
0317 {
0318    //Non-copyable
0319    condition_8a_wrapper(const condition_8a_wrapper &);
0320    condition_8a_wrapper &operator=(const condition_8a_wrapper &);
0321 
0322    ConditionMembers m_data;
0323    typedef condition_algorithm_8a<ConditionMembers> algo_type;
0324 
0325    public:
0326 
0327    condition_8a_wrapper(){}
0328 
0329    //Compiler-generated destructor is OK
0330    //~condition_8a_wrapper(){}
0331 
0332    ConditionMembers & get_members()
0333    {  return m_data; }
0334 
0335    const ConditionMembers & get_members() const
0336    {  return m_data; }
0337 
0338    void notify_one()
0339    {  algo_type::signal(m_data, false);  }
0340 
0341    void notify_all()
0342    {  algo_type::signal(m_data, true);  }
0343 
0344    template <typename L>
0345    void wait(L& lock)
0346    {
0347       if (!lock)
0348          throw lock_exception();
0349       algo_type::template wait<false>(m_data, lock, 0);
0350    }
0351 
0352    template <typename L, typename Pr>
0353    void wait(L& lock, Pr pred)
0354    {
0355       if (!lock)
0356          throw lock_exception();
0357 
0358       while (!pred())
0359          algo_type::template wait<false>(m_data, lock, 0);
0360    }
0361 
0362    template <typename L, class TimePoint>
0363    bool timed_wait(L& lock, const TimePoint &abs_time)
0364    {
0365       if (!lock)
0366          throw lock_exception();
0367       return algo_type::template wait<true>(m_data, lock, abs_time);
0368    }
0369 
0370    template <typename L, class TimePoint, typename Pr>
0371    bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred)
0372    {
0373       if (!lock)
0374             throw lock_exception();
0375       while (!pred()){
0376          if (!algo_type::template wait<true>(m_data, lock, abs_time))
0377             return pred();
0378       }
0379       return true;
0380    }
0381 };
0382 
0383 }  //namespace ipcdetail
0384 }  //namespace interprocess
0385 }  //namespace boost
0386 
0387 #include <boost/interprocess/detail/config_end.hpp>
0388 
0389 #endif   //BOOST_INTERPROCESS_DETAIL_CONDITION_ALGORITHM_8A_HPP