Orocos Real-Time Toolkit
2.5.0
|
00001 /*************************************************************************** 00002 tag: Peter Soetens Thu Oct 22 11:59:08 CEST 2009 ReadOnlyPointer.hpp 00003 00004 ReadOnlyPointer.hpp - description 00005 ------------------- 00006 begin : Thu October 22 2009 00007 copyright : (C) 2009 Sylvain Joyeux 00008 email : Sylvain Joyeux <sylvain.joyeux@m4x.org> 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU General Public * 00013 * License as published by the Free Software Foundation; * 00014 * version 2 of the License. * 00015 * * 00016 * As a special exception, you may use this file as part of a free * 00017 * software library without restriction. Specifically, if other files * 00018 * instantiate templates or use macros or inline functions from this * 00019 * file, or you compile this file and link it with other files to * 00020 * produce an executable, this file does not by itself cause the * 00021 * resulting executable to be covered by the GNU General Public * 00022 * License. This exception does not however invalidate any other * 00023 * reasons why the executable file might be covered by the GNU General * 00024 * Public License. * 00025 * * 00026 * This library is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00029 * Lesser General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public * 00032 * License along with this library; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place, * 00034 * Suite 330, Boston, MA 02111-1307 USA * 00035 * * 00036 ***************************************************************************/ 00037 00038 00039 #ifndef RTT_READ_WRITE_POINTER_HPP 00040 #define RTT_READ_WRITE_POINTER_HPP 00041 00042 #include <boost/intrusive_ptr.hpp> 00043 #include <boost/call_traits.hpp> 00044 00045 #include "../os/Mutex.hpp" 00046 #include "../os/MutexLock.hpp" 00047 00048 namespace RTT 00049 { namespace extras { 00050 00051 template<typename T> 00052 struct ROPtrInternal 00053 { 00054 os::Mutex lock; 00055 T* value; 00056 size_t readers; 00057 00058 ROPtrInternal(T* value) 00059 : value(value), readers(0) {} 00060 ~ROPtrInternal() { delete value; } 00061 00062 void ref() 00063 { os::MutexLock do_lock(lock); 00064 ++readers; 00065 } 00066 bool deref() 00067 { os::MutexLock do_lock(lock); 00068 return (--readers) != 0; 00069 } 00070 }; 00071 00072 template<typename T> 00073 void intrusive_ptr_add_ref(ROPtrInternal<T>* data) 00074 { 00075 data->ref(); 00076 } 00077 template<typename T> 00078 void intrusive_ptr_release(ROPtrInternal<T>* data) 00079 { 00080 if (!data->deref()) 00081 delete data; 00082 } 00083 00097 template<typename T> 00098 class ReadOnlyPointer 00099 { 00100 typedef ROPtrInternal<T> Internal; 00101 boost::intrusive_ptr<Internal> internal; 00102 typedef boost::call_traits<T> traits; 00103 00104 public: 00105 ReadOnlyPointer(T* ptr = 0) 00106 : internal(new Internal(ptr)) {} 00107 00108 typename traits::const_reference operator *() const { return *(internal->value); } 00109 T* operator ->() const { return internal->value; } 00110 00112 bool valid() const 00113 { return internal->value != 0; } 00114 00136 void reset(T* ptr) 00137 { 00138 boost::intrusive_ptr<Internal> safe = this->internal; 00139 if (!safe) 00140 { 00141 internal = new Internal(ptr); 00142 return; 00143 } 00144 00145 00146 { os::MutexLock do_lock(safe->lock); 00147 if (safe->readers == 2) // we are sole owner 00148 { 00149 delete safe->value; 00150 safe->value = ptr; 00151 return; 00152 } 00153 } 00154 00155 // We must *not* change 'internal' while safe->lock is taken. The 00156 // above block returns in case we don't need to reallocate a new 00157 // Internal structure. 00158 // 00159 // In other words, if we are here, it is because we *need* to 00160 // reallocate. 00161 internal = new Internal(ptr); 00162 } 00163 00173 T* try_write_access() 00174 { 00175 boost::intrusive_ptr<Internal> safe = this->internal; 00176 if (!safe) 00177 return 0; 00178 00179 { os::MutexLock do_lock(safe->lock); 00180 if (safe->readers == 2) 00181 { // we're the only owner (don't forget +safe+ above). 00182 // Just promote the current copy 00183 T* value = 0; 00184 std::swap(value, safe->value); 00185 return value; 00186 } 00187 else 00188 { // there are other owners 00189 return NULL; 00190 } 00191 } 00192 } 00193 00205 T* write_access() 00206 { 00207 boost::intrusive_ptr<Internal> safe = this->internal; 00208 if (!safe) 00209 return 0; 00210 00211 { os::MutexLock do_lock(safe->lock); 00212 if (safe->readers == 2) 00213 { // we're the only owner (don't forget +safe+ above). 00214 // Just promote the current copy 00215 T* value = 0; 00216 std::swap(value, safe->value); 00217 return value; 00218 } 00219 else 00220 { // there are other owners, do a copy 00221 return new T(*safe->value); 00222 } 00223 } 00224 } 00225 }; 00226 }} 00227 00228 #endif 00229