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