Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / interprocess / shared_memory_object.hpp
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_SHARED_MEMORY_OBJECT_HPP
12 #define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
13
14 #if defined(_MSC_VER)
15 #  pragma once
16 #endif
17
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/workaround.hpp>
20 #include <boost/interprocess/creation_tags.hpp>
21 #include <boost/interprocess/exceptions.hpp>
22 #include <boost/move/utility_core.hpp>
23 #include <boost/interprocess/interprocess_fwd.hpp>
24 #include <boost/interprocess/exceptions.hpp>
25 #include <boost/interprocess/detail/os_file_functions.hpp>
26 #include <boost/interprocess/detail/shared_dir_helpers.hpp>
27 #include <boost/interprocess/permissions.hpp>
28 #include <cstddef>
29 #include <string>
30 #include <algorithm>
31
32 #if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY)
33 #  include <sys/shm.h>      //System V shared memory...
34 #elif defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
35 #  include <fcntl.h>        //O_CREAT, O_*...
36 #  include <sys/mman.h>     //shm_xxx
37 #  include <unistd.h>       //ftruncate, close
38 #  include <sys/stat.h>     //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
39 #  if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
40 #     if defined(__FreeBSD__)
41 #        include <sys/sysctl.h>
42 #     endif
43 #  endif
44 #else
45 //
46 #endif
47
48 //!\file
49 //!Describes a shared memory object management class.
50
51 namespace boost {
52 namespace interprocess {
53
54 //!A class that wraps a shared memory mapping that can be used to
55 //!create mapped regions from the mapped files
56 class shared_memory_object
57 {
58    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
59    //Non-copyable and non-assignable
60    BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object)
61    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
62
63    public:
64    //!Default constructor. Represents an empty shared_memory_object.
65    shared_memory_object();
66
67    //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
68    //!If the file previously exists, throws an error.*/
69    shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
70    {  this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm);  }
71
72    //!Tries to create a shared memory object with name "name" and mode "mode", with the
73    //!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
74    //!Otherwise throws an error.
75    shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
76    {  this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm);  }
77
78    //!Tries to open a shared memory object with name "name", with the access mode "mode".
79    //!If the file does not previously exist, it throws an error.
80    shared_memory_object(open_only_t, const char *name, mode_t mode)
81    {  this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions());  }
82
83    //!Moves the ownership of "moved"'s shared memory object to *this.
84    //!After the call, "moved" does not represent any shared memory object.
85    //!Does not throw
86    shared_memory_object(BOOST_RV_REF(shared_memory_object) moved)
87       :  m_handle(file_handle_t(ipcdetail::invalid_file()))
88       ,  m_mode(read_only)
89    {  this->swap(moved);   }
90
91    //!Moves the ownership of "moved"'s shared memory to *this.
92    //!After the call, "moved" does not represent any shared memory.
93    //!Does not throw
94    shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
95    {
96       shared_memory_object tmp(boost::move(moved));
97       this->swap(tmp);
98       return *this;
99    }
100
101    //!Swaps the shared_memory_objects. Does not throw
102    void swap(shared_memory_object &moved);
103
104    //!Erases a shared memory object from the system.
105    //!Returns false on error. Never throws
106    static bool remove(const char *name);
107
108    //!Sets the size of the shared memory mapping
109    void truncate(offset_t length);
110
111    //!Destroys *this and indicates that the calling process is finished using
112    //!the resource. All mapped regions are still
113    //!valid after destruction. The destructor function will deallocate
114    //!any system resources allocated by the system for use by this process for
115    //!this resource. The resource can still be opened again calling
116    //!the open constructor overload. To erase the resource from the system
117    //!use remove().
118    ~shared_memory_object();
119
120    //!Returns the name of the shared memory object.
121    const char *get_name() const;
122
123    //!Returns true if the size of the shared memory object
124    //!can be obtained and writes the size in the passed reference
125    bool get_size(offset_t &size) const;
126
127    //!Returns access mode
128    mode_t get_mode() const;
129
130    //!Returns mapping handle. Never throws.
131    mapping_handle_t get_mapping_handle() const;
132
133    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
134    private:
135
136    //!Closes a previously opened file mapping. Never throws.
137    void priv_close();
138
139    //!Opens or creates a shared memory object.
140    bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);
141
142    file_handle_t  m_handle;
143    mode_t         m_mode;
144    std::string    m_filename;
145    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
146 };
147
148 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
149
150 inline shared_memory_object::shared_memory_object()
151    :  m_handle(file_handle_t(ipcdetail::invalid_file()))
152    ,  m_mode(read_only)
153 {}
154
155 inline shared_memory_object::~shared_memory_object()
156 {  this->priv_close(); }
157
158
159 inline const char *shared_memory_object::get_name() const
160 {  return m_filename.c_str(); }
161
162 inline bool shared_memory_object::get_size(offset_t &size) const
163 {  return ipcdetail::get_file_size((file_handle_t)m_handle, size);  }
164
165 inline void shared_memory_object::swap(shared_memory_object &other)
166 {
167    std::swap(m_handle,  other.m_handle);
168    std::swap(m_mode,    other.m_mode);
169    m_filename.swap(other.m_filename);
170 }
171
172 inline mapping_handle_t shared_memory_object::get_mapping_handle() const
173 {
174    return ipcdetail::mapping_handle_from_file_handle(m_handle);
175 }
176
177 inline mode_t shared_memory_object::get_mode() const
178 {  return m_mode; }
179
180 #if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
181
182 inline bool shared_memory_object::priv_open_or_create
183    (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
184 {
185    m_filename = filename;
186    std::string shmfile;
187    ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile);
188
189    //Set accesses
190    if (mode != read_write && mode != read_only){
191       error_info err = other_error;
192       throw interprocess_exception(err);
193    }
194
195    switch(type){
196       case ipcdetail::DoOpen:
197          m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
198       break;
199       case ipcdetail::DoCreate:
200          m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
201       break;
202       case ipcdetail::DoOpenOrCreate:
203          m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
204       break;
205       default:
206          {
207             error_info err = other_error;
208             throw interprocess_exception(err);
209          }
210    }
211
212    //Check for error
213    if(m_handle == ipcdetail::invalid_file()){
214       error_info err = system_error_code();
215       this->priv_close();
216       throw interprocess_exception(err);
217    }
218
219    m_mode = mode;
220    return true;
221 }
222
223 inline bool shared_memory_object::remove(const char *filename)
224 {
225    try{
226       //Make sure a temporary path is created for shared memory
227       std::string shmfile;
228       ipcdetail::shared_filepath(filename, shmfile);
229       return ipcdetail::delete_file(shmfile.c_str());
230    }
231    catch(...){
232       return false;
233    }
234 }
235
236 inline void shared_memory_object::truncate(offset_t length)
237 {
238    if(!ipcdetail::truncate_file(m_handle, length)){
239       error_info err = system_error_code();
240       throw interprocess_exception(err);
241    }
242 }
243
244 inline void shared_memory_object::priv_close()
245 {
246    if(m_handle != ipcdetail::invalid_file()){
247       ipcdetail::close_file(m_handle);
248       m_handle = ipcdetail::invalid_file();
249    }
250 }
251
252 #else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
253
254 namespace shared_memory_object_detail {
255
256 #ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
257
258 #if defined(__FreeBSD__)
259
260 inline bool use_filesystem_based_posix()
261 {
262    int jailed = 0;
263    std::size_t len = sizeof(jailed);
264    ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0);
265    return jailed != 0;
266 }
267
268 #else
269 #error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY"
270 #endif
271
272 #endif
273
274 }  //shared_memory_object_detail
275
276 inline bool shared_memory_object::priv_open_or_create
277    (ipcdetail::create_enum_t type,
278     const char *filename,
279     mode_t mode, const permissions &perm)
280 {
281    #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
282    const bool add_leading_slash = false;
283    #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
284    const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
285    #else
286    const bool add_leading_slash = true;
287    #endif
288    if(add_leading_slash){
289       ipcdetail::add_leading_slash(filename, m_filename);
290    }
291    else{
292       ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename);
293    }
294
295    //Create new mapping
296    int oflag = 0;
297    if(mode == read_only){
298       oflag |= O_RDONLY;
299    }
300    else if(mode == read_write){
301       oflag |= O_RDWR;
302    }
303    else{
304       error_info err(mode_error);
305       throw interprocess_exception(err);
306    }
307    int unix_perm = perm.get_permissions();
308
309    switch(type){
310       case ipcdetail::DoOpen:
311       {
312          //No oflag addition
313          m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
314       }
315       break;
316       case ipcdetail::DoCreate:
317       {
318          oflag |= (O_CREAT | O_EXCL);
319          m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
320          if(m_handle >= 0){
321             ::fchmod(m_handle, unix_perm);
322          }
323       }
324       break;
325       case ipcdetail::DoOpenOrCreate:
326       {
327          //We need a create/open loop to change permissions correctly using fchmod, since
328          //with "O_CREAT" only we don't know if we've created or opened the shm.
329          while(1){
330             //Try to create shared memory
331             m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm);
332             //If successful change real permissions
333             if(m_handle >= 0){
334                ::fchmod(m_handle, unix_perm);
335             }
336             //If already exists, try to open
337             else if(errno == EEXIST){
338                m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
339                //If open fails and errno tells the file does not exist
340                //(shm was removed between creation and opening tries), just retry
341                if(m_handle < 0 && errno == ENOENT){
342                   continue;
343                }
344             }
345             //Exit retries
346             break;
347          }
348       }
349       break;
350       default:
351       {
352          error_info err = other_error;
353          throw interprocess_exception(err);
354       }
355    }
356
357    //Check for error
358    if(m_handle < 0){
359       error_info err = errno;
360       this->priv_close();
361       throw interprocess_exception(err);
362    }
363
364    m_filename = filename;
365    m_mode = mode;
366    return true;
367 }
368
369 inline bool shared_memory_object::remove(const char *filename)
370 {
371    try{
372       std::string filepath;
373       #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
374       const bool add_leading_slash = false;
375       #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
376       const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
377       #else
378       const bool add_leading_slash = true;
379       #endif
380       if(add_leading_slash){
381          ipcdetail::add_leading_slash(filename, filepath);
382       }
383       else{
384          ipcdetail::shared_filepath(filename, filepath);
385       }
386       return 0 == shm_unlink(filepath.c_str());
387    }
388    catch(...){
389       return false;
390    }
391 }
392
393 inline void shared_memory_object::truncate(offset_t length)
394 {
395    if(0 != ftruncate(m_handle, length)){
396       error_info err(system_error_code());
397       throw interprocess_exception(err);
398    }
399 }
400
401 inline void shared_memory_object::priv_close()
402 {
403    if(m_handle != -1){
404       ::close(m_handle);
405       m_handle = -1;
406    }
407 }
408
409 #endif
410
411 //!A class that stores the name of a shared memory
412 //!and calls shared_memory_object::remove(name) in its destructor
413 //!Useful to remove temporary shared memory objects in the presence
414 //!of exceptions
415 class remove_shared_memory_on_destroy
416 {
417    const char * m_name;
418    public:
419    remove_shared_memory_on_destroy(const char *name)
420       :  m_name(name)
421    {}
422
423    ~remove_shared_memory_on_destroy()
424    {  shared_memory_object::remove(m_name);  }
425 };
426
427 #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
428
429 }  //namespace interprocess {
430 }  //namespace boost {
431
432 #include <boost/interprocess/detail/config_end.hpp>
433
434 #endif   //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP