1 ////////////////////////////////////////////////////////////////////////////// 2 // 3 // (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost 4 // Software License, Version 1.0. (See accompanying file 5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // See http://www.boost.org/libs/interprocess for documentation. 8 // 9 ////////////////////////////////////////////////////////////////////////////// 10 11 #ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP 12 #define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP 13 14 #if (defined _MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif 17 18 #include <boost/interprocess/detail/config_begin.hpp> 19 #include <boost/interprocess/detail/workaround.hpp> 20 21 #include <boost/interprocess/detail/managed_memory_impl.hpp> 22 #include <boost/interprocess/creation_tags.hpp> 23 #include <boost/detail/no_exceptions_support.hpp> 24 #include <boost/interprocess/detail/multi_segment_services.hpp> 25 #include <boost/interprocess/detail/utilities.hpp> 26 #include <boost/interprocess/shared_memory_object.hpp> 27 #include <boost/interprocess/containers/list.hpp>//list 28 #include <boost/interprocess/mapped_region.hpp> //mapped_region 29 #include <boost/interprocess/shared_memory_object.hpp> 30 #include <boost/interprocess/permissions.hpp> 31 #include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl 32 #include <new> 33 #include <boost/interprocess/containers/string.hpp> 34 #include <boost/interprocess/streams/vectorstream.hpp> 35 #include <memory> 36 #include <boost/assert.hpp> 37 38 //!\file 39 //!Describes a named shared memory object allocation user class. 40 41 namespace boost { 42 43 namespace interprocess { 44 45 //TODO: We must somehow obtain the permissions of the first segment 46 //to apply them to subsequent segments 47 //-Use GetSecurityInfo? 48 //-Change everything to use only a shared memory object expanded via truncate()? 49 50 //!A basic shared memory named object creation class. Initializes the 51 //!shared memory segment. Inherits all basic functionality from 52 //!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType> 53 template 54 < 55 class CharType, 56 class MemoryAlgorithm, 57 template<class IndexConfig> class IndexType 58 > 59 class basic_managed_multi_shared_memory 60 : public detail::basic_managed_memory_impl 61 <CharType, MemoryAlgorithm, IndexType> 62 { 63 64 typedef basic_managed_multi_shared_memory 65 <CharType, MemoryAlgorithm, IndexType> self_t; 66 typedef typename MemoryAlgorithm::void_pointer void_pointer; 67 typedef typename detail:: 68 managed_open_or_create_impl<shared_memory_object> managed_impl; 69 typedef typename void_pointer::segment_group_id segment_group_id; 70 //////////////////////////////////////////////////////////////////////// 71 // 72 // Some internal helper structs/functors 73 // 74 //////////////////////////////////////////////////////////////////////// 75 //!This class defines an operator() that creates a shared memory 76 //!of the requested size. The rest of the parameters are 77 //!passed in the constructor. The class a template parameter 78 //!to be used with create_from_file/create_from_istream functions 79 //!of basic_named_object classes 80 81 // class segment_creator 82 // { 83 // public: 84 // segment_creator(shared_memory &shmem, 85 // const char *mem_name, 86 // const void *addr) 87 // : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){} 88 // 89 // void *operator()(std::size_t size) 90 // { 91 // if(!m_shmem.create(m_mem_name, size, m_addr)) 92 // return 0; 93 // return m_shmem.get_address(); 94 // } 95 // private: 96 // shared_memory &m_shmem; 97 // const char *m_mem_name; 98 // const void *m_addr; 99 // }; 100 101 class group_services 102 : public multi_segment_services 103 { 104 public: 105 typedef std::pair<void *, std::size_t> result_type; 106 typedef basic_managed_multi_shared_memory frontend_t; 107 typedef typename 108 basic_managed_multi_shared_memory::void_pointer void_pointer; 109 typedef typename void_pointer::segment_group_id segment_group_id; group_services(frontend_t * const frontend)110 group_services(frontend_t *const frontend) 111 : mp_frontend(frontend), m_group(0), m_min_segment_size(0){} 112 create_new_segment(std::size_t alloc_size)113 virtual std::pair<void *, std::size_t> create_new_segment(std::size_t alloc_size) 114 { 115 //We should allocate an extra byte so that the 116 //[base_addr + alloc_size] byte belongs to this segment 117 alloc_size += 1; 118 119 //If requested size is less than minimum, update that 120 alloc_size = (m_min_segment_size > alloc_size) ? 121 m_min_segment_size : alloc_size; 122 if(mp_frontend->priv_new_segment(create_open_func::DoCreate, 123 alloc_size, 0, permissions())){ 124 shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin(); 125 return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1); 126 } 127 return result_type(static_cast<void *>(0), 0); 128 } 129 update_segments()130 virtual bool update_segments () 131 { return true; } 132 ~group_services()133 virtual ~group_services(){} 134 set_group(segment_group_id group)135 void set_group(segment_group_id group) 136 { m_group = group; } 137 get_group() const138 segment_group_id get_group() const 139 { return m_group; } 140 set_min_segment_size(std::size_t min_segment_size)141 void set_min_segment_size(std::size_t min_segment_size) 142 { m_min_segment_size = min_segment_size; } 143 get_min_segment_size() const144 std::size_t get_min_segment_size() const 145 { return m_min_segment_size; } 146 147 private: 148 149 frontend_t * const mp_frontend; 150 segment_group_id m_group; 151 std::size_t m_min_segment_size; 152 }; 153 154 //!Functor to execute atomically when opening or creating a shared memory 155 //!segment. 156 struct create_open_func 157 { 158 enum type_t { DoCreate, DoOpen, DoOpenOrCreate }; 159 typedef typename 160 basic_managed_multi_shared_memory::void_pointer void_pointer; 161 create_open_funcboost::interprocess::basic_managed_multi_shared_memory::create_open_func162 create_open_func(self_t * const frontend, 163 type_t type, std::size_t segment_number) 164 : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){} 165 operator ()boost::interprocess::basic_managed_multi_shared_memory::create_open_func166 bool operator()(void *addr, std::size_t size, bool created) const 167 { 168 if(((m_type == DoOpen) && created) || 169 ((m_type == DoCreate) && !created)) 170 return false; 171 segment_group_id group = mp_frontend->m_group_services.get_group(); 172 bool mapped = false; 173 bool impl_done = false; 174 175 //Associate this newly created segment as the 176 //segment id = 0 of this group 177 void_pointer::insert_mapping 178 ( group 179 , static_cast<char*>(addr) - managed_impl::ManagedOpenOrCreateUserOffset 180 , size + managed_impl::ManagedOpenOrCreateUserOffset); 181 //Check if this is the master segment 182 if(!m_segment_number){ 183 //Create or open the Interprocess machinery 184 if((impl_done = created ? 185 mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){ 186 return true; 187 } 188 } 189 else{ 190 return true; 191 } 192 193 //This is the cleanup part 194 //--------------- 195 if(impl_done){ 196 mp_frontend->close_impl(); 197 } 198 if(mapped){ 199 bool ret = void_pointer::erase_last_mapping(group); 200 BOOST_ASSERT(ret);(void)ret; 201 } 202 return false; 203 } 204 self_t * const mp_frontend; 205 type_t m_type; 206 std::size_t m_segment_number; 207 }; 208 209 //!Functor to execute atomically when closing a shared memory segment. 210 struct close_func 211 { 212 typedef typename 213 basic_managed_multi_shared_memory::void_pointer void_pointer; 214 close_funcboost::interprocess::basic_managed_multi_shared_memory::close_func215 close_func(self_t * const frontend) 216 : mp_frontend(frontend){} 217 operator ()boost::interprocess::basic_managed_multi_shared_memory::close_func218 void operator()(const mapped_region ®ion, bool last) const 219 { 220 if(last) mp_frontend->destroy_impl(); 221 else mp_frontend->close_impl(); 222 } 223 self_t * const mp_frontend; 224 }; 225 226 typedef detail::basic_managed_memory_impl 227 <CharType, MemoryAlgorithm, IndexType> base_t; 228 229 //Friend declarations 230 friend struct basic_managed_multi_shared_memory::create_open_func; 231 friend struct basic_managed_multi_shared_memory::close_func; 232 friend class basic_managed_multi_shared_memory::group_services; 233 234 typedef list<managed_impl> shmem_list_t; 235 get_this_pointer()236 basic_managed_multi_shared_memory *get_this_pointer() 237 { return this; } 238 239 public: 240 basic_managed_multi_shared_memory(create_only_t,const char * name,std::size_t size,const permissions & perm=permissions ())241 basic_managed_multi_shared_memory(create_only_t, 242 const char *name, 243 std::size_t size, 244 const permissions &perm = permissions()) 245 : m_group_services(get_this_pointer()) 246 { 247 priv_open_or_create(create_open_func::DoCreate,name, size, perm); 248 } 249 basic_managed_multi_shared_memory(open_or_create_t,const char * name,std::size_t size,const permissions & perm=permissions ())250 basic_managed_multi_shared_memory(open_or_create_t, 251 const char *name, 252 std::size_t size, 253 const permissions &perm = permissions()) 254 : m_group_services(get_this_pointer()) 255 { 256 priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm); 257 } 258 basic_managed_multi_shared_memory(open_only_t,const char * name)259 basic_managed_multi_shared_memory(open_only_t, const char *name) 260 : m_group_services(get_this_pointer()) 261 { 262 priv_open_or_create(create_open_func::DoOpen, name, 0, permissions()); 263 } 264 ~basic_managed_multi_shared_memory()265 ~basic_managed_multi_shared_memory() 266 { this->priv_close(); } 267 268 private: priv_open_or_create(typename create_open_func::type_t type,const char * name,std::size_t size,const permissions & perm)269 bool priv_open_or_create(typename create_open_func::type_t type, 270 const char *name, 271 std::size_t size, 272 const permissions &perm) 273 { 274 if(!m_shmem_list.empty()) 275 return false; 276 typename void_pointer::segment_group_id group = 0; 277 BOOST_TRY{ 278 m_root_name = name; 279 //Insert multi segment services and get a group identifier 280 group = void_pointer::new_segment_group(&m_group_services); 281 size = void_pointer::round_size(size); 282 m_group_services.set_group(group); 283 m_group_services.set_min_segment_size(size); 284 285 if(group){ 286 if(this->priv_new_segment(type, size, 0, perm)){ 287 return true; 288 } 289 } 290 } 291 BOOST_CATCH(const std::bad_alloc&){ 292 } 293 BOOST_CATCH_END 294 if(group){ 295 void_pointer::delete_group(group); 296 } 297 return false; 298 } 299 priv_new_segment(typename create_open_func::type_t type,std::size_t size,const void * addr,const permissions & perm)300 bool priv_new_segment(typename create_open_func::type_t type, 301 std::size_t size, 302 const void *addr, 303 const permissions &perm) 304 { 305 BOOST_TRY{ 306 //Get the number of groups of this multi_segment group 307 std::size_t segment_id = m_shmem_list.size(); 308 //Format the name of the shared memory: append segment number. 309 boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter; 310 //Pre-reserve string size 311 std::size_t str_size = m_root_name.length()+10; 312 if(formatter.vector().size() < str_size){ 313 //This can throw. 314 formatter.reserve(str_size); 315 } 316 //Format segment's name 317 formatter << m_root_name 318 << static_cast<unsigned int>(segment_id) << std::ends; 319 //This functor will be executed when constructing 320 create_open_func func(this, type, segment_id); 321 const char *name = formatter.vector().c_str(); 322 //This can throw. 323 managed_impl mshm; 324 325 switch(type){ 326 case create_open_func::DoCreate: 327 { 328 managed_impl shm(create_only, name, size, read_write, addr, func, perm); 329 mshm = boost::interprocess::move(shm); 330 } 331 break; 332 333 case create_open_func::DoOpen: 334 { 335 managed_impl shm(open_only, name,read_write, addr, func); 336 mshm = boost::interprocess::move(shm); 337 } 338 break; 339 340 case create_open_func::DoOpenOrCreate: 341 { 342 managed_impl shm(open_or_create, name, size, read_write, addr, func, perm); 343 mshm = boost::interprocess::move(shm); 344 } 345 break; 346 347 default: 348 return false; 349 break; 350 } 351 352 //This can throw. 353 m_shmem_list.push_back(boost::interprocess::move(mshm)); 354 return true; 355 } 356 BOOST_CATCH(const std::bad_alloc&){ 357 } 358 BOOST_CATCH_END 359 return false; 360 } 361 362 //!Frees resources. Never throws. priv_close()363 void priv_close() 364 { 365 if(!m_shmem_list.empty()){ 366 bool ret; 367 //Obtain group identifier 368 segment_group_id group = m_group_services.get_group(); 369 //Erase main segment and its resources 370 shmem_list_t::iterator itbeg = m_shmem_list.begin(), 371 itend = m_shmem_list.end(), 372 it = itbeg; 373 //(*itbeg)->close_with_func(close_func(this)); 374 //Delete group. All mappings are erased too. 375 ret = void_pointer::delete_group(group); 376 BOOST_ASSERT(ret); 377 m_shmem_list.clear(); 378 } 379 } 380 381 private: 382 shmem_list_t m_shmem_list; 383 group_services m_group_services; 384 std::string m_root_name; 385 }; 386 387 typedef basic_managed_multi_shared_memory 388 < char 389 , rbtree_best_fit<mutex_family, intersegment_ptr<void> > 390 , iset_index> 391 managed_multi_shared_memory; 392 393 } //namespace interprocess { 394 395 } //namespace boost { 396 397 #include <boost/interprocess/detail/config_end.hpp> 398 399 #endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP 400 401