UHD  003.005.003-781-g91040b6f
include/uhd/utils/atomic.hpp
Go to the documentation of this file.
00001 //
00002 // Copyright 2012-2013 Ettus Research LLC
00003 //
00004 // This program is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #ifndef INCLUDED_UHD_UTILS_ATOMIC_HPP
00019 #define INCLUDED_UHD_UTILS_ATOMIC_HPP
00020 
00021 #include <uhd/config.hpp>
00022 #include <uhd/types/time_spec.hpp>
00023 #include <boost/thread/thread.hpp>
00024 #include <boost/thread/mutex.hpp>
00025 #include <boost/thread/condition_variable.hpp>
00026 #include <boost/interprocess/detail/atomic.hpp>
00027 
00028 #include <boost/version.hpp>
00029 #if BOOST_VERSION >= 104800
00030 #  define BOOST_IPC_DETAIL boost::interprocess::ipcdetail
00031 #else
00032 #  define BOOST_IPC_DETAIL boost::interprocess::detail
00033 #endif
00034 
00035 namespace uhd{
00036 
00038     class UHD_API atomic_uint32_t{
00039     public:
00040 
00042         UHD_INLINE atomic_uint32_t(void){
00043             this->write(0);
00044         }
00045 
00047         UHD_INLINE boost::uint32_t cas(boost::uint32_t newval, boost::uint32_t cmp){
00048             return BOOST_IPC_DETAIL::atomic_cas32(&_num, newval, cmp);
00049         }
00050 
00052         UHD_INLINE void write(const boost::uint32_t newval){
00053             BOOST_IPC_DETAIL::atomic_write32(&_num, newval);
00054         }
00055 
00057         UHD_INLINE boost::uint32_t read(void){
00058             return BOOST_IPC_DETAIL::atomic_read32(&_num);
00059         }
00060 
00062         UHD_INLINE boost::uint32_t inc(void){
00063             return BOOST_IPC_DETAIL::atomic_inc32(&_num);
00064         }
00065 
00067         UHD_INLINE boost::uint32_t dec(void){
00068             return BOOST_IPC_DETAIL::atomic_dec32(&_num);
00069         }
00070 
00071     private: volatile boost::uint32_t _num;
00072     };
00073 
00078     class UHD_API reusable_barrier{
00079     public:
00080 
00082         void resize(const size_t size){
00083             _size = size;
00084         }
00085 
00090         void interrupt(void)
00091         {
00092             _done.inc();
00093         }
00094 
00096         UHD_INLINE void wait(void)
00097         {
00098             if (_size == 1) return;
00099 
00100             //entry barrier with condition variable
00101             _entry_counter.inc();
00102             _entry_counter.cas(0, _size);
00103             boost::mutex::scoped_lock lock(_mutex);
00104             while (_entry_counter.read() != 0)
00105             {
00106                 this->check_interrupt();
00107                 _cond.timed_wait(lock, boost::posix_time::milliseconds(1));
00108             }
00109             lock.unlock(); //unlock before notify
00110             _cond.notify_one();
00111 
00112             //exit barrier to ensure known condition of entry count
00113             _exit_counter.inc();
00114             _exit_counter.cas(0, _size);
00115             while (_exit_counter.read() != 0) this->check_interrupt();
00116         }
00117 
00119         UHD_INLINE void wait_others(void)
00120         {
00121             while (_entry_counter.read() != (_size-1)) this->check_interrupt();
00122         }
00123 
00124     private:
00125         size_t _size;
00126         atomic_uint32_t _entry_counter;
00127         atomic_uint32_t _exit_counter;
00128         atomic_uint32_t _done;
00129         boost::mutex _mutex;
00130         boost::condition_variable _cond;
00131 
00132         UHD_INLINE void check_interrupt(void)
00133         {
00134             if (_done.read() != 0) throw boost::thread_interrupted();
00135             boost::this_thread::interruption_point();
00136             boost::this_thread::yield();
00137         }
00138     };
00139 
00147     UHD_INLINE bool spin_wait_with_timeout(
00148         atomic_uint32_t &cond,
00149         boost::uint32_t value,
00150         const double timeout
00151     ){
00152         if (cond.read() == value) return true;
00153         const time_spec_t exit_time = time_spec_t::get_system_time() + time_spec_t(timeout);
00154         while (cond.read() != value){
00155             if (time_spec_t::get_system_time() > exit_time) return false;
00156             boost::this_thread::interruption_point();
00157             boost::this_thread::yield();
00158         }
00159         return true;
00160     }
00161 
00166     class simple_claimer{
00167     public:
00168         simple_claimer(void){
00169             this->release();
00170         }
00171 
00172         UHD_INLINE void release(void){
00173             _locked.write(0);
00174         }
00175 
00176         UHD_INLINE bool claim_with_wait(const double timeout){
00177             if (spin_wait_with_timeout(_locked, 0, timeout)){
00178                 _locked.write(1);
00179                 return true;
00180             }
00181             return false;
00182         }
00183 
00184     private:
00185         atomic_uint32_t _locked;
00186     };
00187 
00188 } //namespace uhd
00189 
00190 #endif /* INCLUDED_UHD_UTILS_ATOMIC_HPP */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines