UHD
003.005.003-781-g91040b6f
|
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 */