<html><head><title>Memory Mapped Files And Shared Memory For C++</title>

<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note
{
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
}
ins {background-color:#FFFFA0}
del {background-color:#FFFFA0}
</style></head><body>

<address align="right">
Document number: N2044=06-0114<br>
<br>
Ion Gazta&ntilde;aga (igaztanaga at gmail dot com)<br>
2006-06-18
</address>
<hr>
<h1 align="center">Memory Mapped Files And Shared Memory For C++</h1>

<h2>Contents</h2>

<ul>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#MemoryMappedFiles">Memory Mapped Files</a></li>
<li><a href="#SharedMemory">Shared Memory</a></li>
<li><a href="#UnifyingMappedRegions">Unifying Mapped Regions: <tt>std::memory_mappable</tt> and <tt>std::mapped_region</tt></a></li>
<ul>
   <li><a href="#ClassMemoryMappable"><tt>class memory_mappable synopsis</tt></a></li>
   <li><a href="#ClassMemoryMappableMembers"><tt>class memory_mappable members</tt></a></li>
   <li><a href="#ClassMappedRegion"><tt>class mapped_region synopsis</tt></a></li>
   <li><a href="#ClassMappedRegionMembers"><tt>class mapped_region members</tt></a></li>
</ul>
<li><a href="#MappingFiles">Mapping Files: <tt>std::file_mapping</tt></a></li>
<ul>
   <li><a href="#ClassFileMapping"><tt>class file_mapping synopsis</tt></a></li>
   <li><a href="#ClassFileMappingMembers"><tt>class file_mapping members</tt></a></li>
   <li><a href="#ClassFileMappingMembers">File Mapping Example</a></li>
</ul>
<li><a href="#SharedMemoryMapping">Shared Memory Mapping: <tt>std::shared_memory_object</tt></a></li>
<ul>
   <li><a href="#ClassSharedMemoryObject"><tt>class shared_memory_object synopsis</tt></a></li>
   <li><a href="#ClassSharedMemoryObjectMembers"><tt>class shared_memory_object members</tt></a></li>
   <li><a href="#ClassSharedMemoryObjectExample">Shared Memory Object Example</a></li>
</ul>
<li><a href="#UnifyingIostreams">Unifying With Iostreams</a></li>
<ul>
   <li><a href="#UnifyingIostreamsFilebuf"><tt>Using basic_filebuf as file mapping source</tt></a></li>
   <li><a href="#UnifyingIostreamsOpenmode"><tt>Using std::ios_base::openmode flags</tt></a></li>
   <li><a href="#UnifyingIostreamsFilebufMappable"><tt>basic_filebuf</tt> is a <tt>mappable</tt> class</tt></a></li>
</ul>
<li><a href="#PortablePaths">Using Portable Paths</a></li>
<li><a href="#PortableSharedMemory">Portable Shared Memory Name</a></li>
<li><a href="#PriorArt">Prior Art</a></li>
<li><a href="#Conclusions">Conclusions</a></li>
<li><a href="#Acknowledgments">Acknowledgments</a></li>
<li><a href="#References">References</a></li>
</ul>

<h2><a name="Introduction"></a>Introduction</h2>

<p>Interprocess communication is an important missing part in the C++ standard library. This paper proposes
some classes to fill two basic areas in interprocess communications: memory mapped files and shared memory.</p>

<p>Standard file mapping and shared memory utilities can offer a wide range of possibilities for many
applications, to achieve data persistence, data cache and complex data serialization between
processes.</p>

<h2><a name="MemoryMappedFiles"></a>Memory Mapped Files</h2>

<p>
File mapping is the association of a file's contents with a portion of the address space of a process. 
The system creates a <b>file mapping</b> to associate the file and the address space of the process. A 
<b>mapped region</b> is the portion of address space that the process uses to access the file's contents.
A single file mapping can have several mapped regions, and the user can associate parts of the file 
with the address space of the process without mapping the entire file in the address space.
Processes read from and write to the file using pointers, just like with dynamic memory.
File mapping has the following advantages:
</p>

<ul>
<li>Uniform resource use. Files and memory can be treated using the same functions.</li> 
<li>Automatic file data synchronization and cache from the OS.</li> 
<li>Reuse of C++ memory utilities (STL containers, algorithms) in files.</li> 
<li>Shared memory between two or more applications.</li> 
<li>Allows efficient work with a large files, without loading the whole file into memory</li>
</ul>

<p>
If several processes use the same file mapping to create mapped regions of a file, each process' 
views contain identical copies of the file on disk. POSIX and Windows mapped file management is
very similar, and highly portable.</p>

<h2><a name="SharedMemory"></a>Shared Memory</h2>

<p>
POSIX defines a shared memory object as <i>"An object that represents memory that can be mapped 
concurrently into the address space of more than one process."</i>
</p>

<p>
Shared memory is similar to file mapping, and the user can map several regions of a shared memory object,
just like with memory mapped files. In some operating systems, like Windows, shared memory
is an special case of file mapping, where the file mapping object accesses memory backed by the system
paging file. However, in Windows, the lifetime of this memory ends when the last process connected to the
shared memory object closes connection or the application exits, so there is no data persistence. 
If an application creates shared memory, fills it with
data and exits, the data is lost. This lifetime is known as <b>process</b> lifetime</p>

<p>In POSIX operating systems the shared memory lifetime is different since for semaphores, shared memory, 
and message queues it's mandatory that the object and its state (including data, if any) is preserved after the
object is no longer referenced by any process. Persistence of an object does not imply that the state of the object
is preserved after a system crash or reboot, but this can be achieved since shared memory objects can actually be 
implemented as mapped files of a permanent file system. The shared memory destruction happens
with an explicit call to <i>unlink()</i>, which is similar to the file destruction mechanism. POSIX shared memory is
required to have <b>kernel</b> lifetime (the object is explicitly destroyed or it's destroyed when the
operating system reboots) or <b>filesystem</b> persistence (the shared memory object has the same lifetime
as a file).</p>

<p>This lifetime difference is important to achieve portability. Many portable runtimes have tried to achieve
perfect portability between Windows and POSIX shared memory but the author of this paper has not seen any
satisfactory effort. Adding a reference count to POSIX shared memory is effective only as long as a process
does not crash, something that it's very usual. Emulating POSIX behaviour in Windows using native shared memory
is not possible since we could try to dump shared memory to a file to obtain persistence, but a process crash 
would avoid persistence. The only viable alternative is to use memory mapped files in Windows
simulating shared memory, but avoiding file-memory synchronization as much as possible.</p>

<p>Many other named synchronization primitives (like named mutexes or semaphores) suffer the same lifetime
portability problem. Automatic shared memory cleanup is useful in many contexts, like shared libraries or DLL-s
communicating with other DLL-s or processes. Even when there is a crash, resources are automatically cleaned up
by the operating systems. POSIX persistence is also useful when a launcher program can create and fill shared
memory that another process can read or modify. Persistence also allows data recovery if a server process
crashes. All the data is still in the shared memory, and the server can recover its state.</p>

<p>This paper proposes POSIX lifetime (kernel or filesystem lifetime) as a more portable solution, but has no strong
opinion about this. The C++ committee should take into account the use cases of both approaches to decide which behaviour
is better or if both options should be available, forcing the modification of both POSIX and Windows systems.</p>

<h2><a name="UnifyingMappedRegions"></a>Unifying Mapped Regions: <tt>std::memory_mappable</tt>
and <tt>std::mapped_region</tt></h2>

<p>In both POSIX and Windows systems shared memory, memory mapping and other input-output device mapping mechanisms
are similar. The memory mapping operation returns a handle that can be used to create a mapped
region using <tt><i>mmap</i></tt> (POSIX) or <tt><i>MapViewOfFile</i></tt> (Windows) functions. This
shows that a mapped region is independent from the memory mapping source, and this paper proposes
a generic class representing a mapped region that can represent a shared memory, a mapped file or 
a mapped device region.</p>

<p>The <tt>memory_mappable</tt> class represents any resource that can be read and written using
the address space of the process. It's an abstract class from which we can derive several mappable
classes, like file mappings, shared memory objects, device mappings... Like the <tt>iostream</tt>
framework, the derived classes must initialize <tt>memory_mappable</tt> in the constructor, calling
<tt>init</tt> to store the mapping handle and the mapping mode. This information will be stored
in the <tt>memory_mappable</tt> class and it will be used to created <tt>mapped_region</tt>
objects:</p>

<h3><a name="ClassMemoryMappable"></a>class memory_mappable sinopsys</h3>

<blockquote><pre>namespace std {

class memory_mappable
{
   private:

   // Non-copyable
   memory_mappable(const memory_mappable &amp;);

   // Non-assignable
   memory_mappable &amp; operator=(const memory_mappable &amp;);

   public:

   typedef /*implementation-defined*/ accessmode_t;
   typedef /*implementation-defined*/ mapping_handle_t;
   static const mapping_handle_t      invalid_handle;
   static const accessmode_t          read_only;
   static const accessmode_t          read_write;
   static const accessmode_t          invalid_mode;

   public:
   memory_mappable();

   protected:
   void init(mapping_handle_t handle, accessmode_t mode);

   public:
   memory_mappable(memory_mappable &amp;&amp;other);

   mapping_handle_t get_handle() const;
   
   accessmode_t get_mode() const;

   virtual ~memory_mappable() = 0;
};

}  //namespace std {</pre></blockquote>

<h3><a name="ClassMemoryMappableMembers"></a>class memory_mappable members</h3>

<blockquote><pre>
memory_mappable();
</pre></blockquote>

<p>
<b>Effects:</b> Default constructs the object.
</p>

<p>
<b>Postconditions:</b> this->get_handle() == <i>invalid_handle</i> &amp; &amp; this->get_mode() == <i>invalid_mode</i>.
</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
void init(mapping_handle_t <i>handle</i>, accessmode_t <i>mode</i>);
</pre></blockquote>

<p>
<b>Effects:</b> Stores internally the mapping handle and the mode of the derived class.
This function is intended to be called by the derived class once the derived class
initialization has been completed.
</p>

<p>
<b>Posconditions:</b> this-&gt;get_handle() == <i>handle</i> &amp;&amp; this-&gt;get_mode() == <i>mode</i>.
</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
memory_mappable(memory_mappable &amp;&amp;<i>other</i>);
</pre></blockquote>

<p>
<b>Effects:</b> Moves resources from <i>other</i> to *this.
</p>

<p>
<b>Posconditions:</b> other.get_handle() == <i>invalid_handle</i> &amp;&amp; other.get_mode() == <i>invalid_mode</i>.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
mapping_handle_t get_handle() const;
</pre></blockquote>

<p>
<b>Effects:</b> Returns the handle registered by the init() function.
</p>

<p>
<b>Returns:</b> Returns the handle registered by the init() function. If init() has not
been called, returns <i>invalid_handle</i>.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
accessmode_t get_mode() const;
</pre></blockquote>

<p>
<b>Effects:</b> Returns the mode registered by the init() function.
</p>

<p>
<b>Returns:</b> Returns the handle registered by the init() function. If init() has not
been called, returns <i>invalid_mode</i>.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
virtual ~memory_mappable() = 0;
</pre></blockquote>

<p>
<b>Effects:</b> Destroys the object. The class does not free the handle registered in init(). 
This task should be performed by the derived class.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<h3><a name="ClassMappedRegion"></a>class mapped_region synopsis</h3>

<p>The <tt>mapped_region</tt> class represents a portion or region created from a <tt>memory_mappable</tt>
object. Once a <tt>mapped_region</tt> object is constructed, a part of the
file, shared memory or device is mapped in the address space of the calling process:</p>

<blockquote><pre>namespace std {

class mapped_region
{
   // Non-copyable
   mapped_region(const mapped_region &amp;);

   // Non-assignable
   mapped_region &amp;operator=(const mapped_region &amp;);

   public:

   typedef /*implementation-defined*/ offset_t;
   typedef /*implementation-defined*/ accessmode_t;
   static const accessmode_t          invalid_mode;
   static const accessmode_t          read_only;
   static const accessmode_t          read_write;
   static const accessmode_t          copy_on_write;

   mapped_region();

   mapped_region( const memory_mappable &amp; mappable
                , accessmode_t            mode
                , offset_t                mappable_offset
                , std::size_t             size = 0
                , const void *            address = 0);

   mapped_region(mapped_region &amp;&amp;other);

   std::size_t get_size() const;

   void*       get_address() const;

   offset_t    get_offset() const;

   accessmode_t get_mode() const;

   void flush(std::size_t region_offset = 0, std::size_t numbytes = 0);

   void swap(mapped_region &amp;other);

   ~mapped_region();
};

}  //namespace std {</pre></blockquote>

<h3><a name="ClassMappedRegionMembers"></a>class mapped_region members</h3>

<blockquote><pre>
mapped_region();
</pre></blockquote>

<p>
<b>Effects:</b> Default constructs a mapped region.

</p>

<p>
<b>Postconditions:</b> this-&gt;get_address() == 0 &amp;&amp; this-&gt;get_size() == 0
&amp;&amp; this-&gt;get_offset() == 0 &amp;&amp; other.get_mode() == <i>invalid_mode</i>.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
mapped_region(mapped_region &amp;&amp;other);
</pre></blockquote>

<p>
<b>Effects:</b> Constructs a mapped region taking ownership of the resources
of another mapped_region.
</p>

<p>
<b>Postconditions:</b> The object is an default constructed state.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
mapped_region( const memory_mappable &amp; mappable
             , accessmode_t            mode
             , offset_t                mappable_offset = 0
             , std::size_t             size = 0
             , const void *            address = 0);
</pre></blockquote>

<p>
<b>Effects:</b> Creates a mapped region of the <tt><i>mappable</i></tt> memory mappable object. 
This <tt><i>mappable</i></tt> object can represent any mappable object that can be mapped using
a generic <tt>mapping_handle_t</tt> (a file, a shared memory object or a input-output device). The <tt><i>mappable</i></tt>
object can be inmediatelly destroyed after the constructor if no more mapped regions are needed
from the <tt><i>mappable</i></tt> object.
</p>

<p>A <tt><i>mappable</i></tt> object with <tt><i>read_only</i></tt> access should only be used to create
<tt><i>read_only</i></tt> <tt>mapped_region</tt> objects. A <tt><i>mappable</i></tt> object with <tt><i>read_write</i></tt>
access can create <tt><i>read_only</i></tt>, <tt><i>read_write</i></tt> or <tt><i>copy_on_write</i></tt> 
<tt>mapped_region</tt> objects.</p>

<p>When an object is created with <tt><i>read_only</i></tt> mode, writing to the memory range expressed by this
object can terminate the process and never will change the <tt><i>mappable</i></tt> object.</p>

<p>When an object is created with <tt><i>read_write</i></tt> mode:</p>

<ul>
<li>If the user writes data to the memory range represented by this object, the modifications will
be transferred to the <i>mappable resource</i> represented by the <tt><i>mappable</i></tt> object (a file, for example)
when the implementation considers it adequate.</li>
<li>If multiple processes map the same <tt><i>mappable</i></tt> resource, the modifications are propagated 
to the other processes, so the change will be visible in the memory regions referring to
the same resource in other processes.</li>
</ul>

<p>A <tt><i>copy_on_write</i></tt> <tt>mapped_region</tt> is an special <tt><i>read_write</i></tt> <tt>mapped_region</tt>:
<ul>
<li>If the user writes data to the memory range represented by this object, the modifications will
<b>not</b> be transferred to the <i>mappable</i> resource represented by the <tt><i>mappable</i></tt> object
(a file, for example...).</li>
<li>If multiple processes refer to the same underlying storage, the modifications are not propagated 
to the other processes.</li>
</ul>

<p>The constructor will map a region of the <tt><i>mappable</i></tt> object starting in
the offset <tt><i>offset</i></tt> of the <tt><i>mappable</i></tt> object (a file, or shared memory object),
and the region's size will be <tt><i>size</i></tt>.</p>

<p>
The user can request a mapping address in the process, using the <tt><i>address</i></tt> parameter. If
<tt><i>address</i></tt> is 0, the implementation will choose the mapping address.
If <tt><i>size</i></tt> is 0, the <tt>mapped_region</tt>'s size will cover from <tt><i>offset</i></tt> until
the end of the <tt><i>mappable</i></tt> object.
</p>

<p>
<b>Postconditions:</b> this-&gt;get_address() != 0 &amp;&amp; this-&gt;get_size() != 0 &amp;&amp; this-&gt;get_offset() == <tt><i>offset</i></tt>.
</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on any error, for example when the
<tt><i>mappable</i></tt> object can't be mapped in the address passed in the constructor or when
the mappable can't be mapped with the required access mode.
</p>

<blockquote><pre>
std::size_t get_size() const;
</pre></blockquote>

<p>
<b>Effects:</b> Returns the size of the mapped region. Never throws.
</p>

<p>
<b>Returns:</b> If default constructed or moved returns 0. Otherwise the size passed in the
non-default constructor.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
void *get_address() const;
</pre></blockquote>

<p>
<b>Effects:</b> Returns the address where the mappable has been mapped. If the non-default constructor's
<i>address</i> argument was 0, this value will be chosen by the implementation.
</p>

<p>
<b>Returns:</b> If the object is default constructed or has been moved returns 0. Otherwise the address
where the mappable object was mapped. 
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
offset_t get_offset() const;
</pre></blockquote>

<p>
<b>Effects:</b>
Returns the offset from the beginning of the mappable where the mapped region starts.
</p>

<p>
<b>Returns:</b> If default constructed or moved returns 0. Otherwise the offset passed in the
non-default constructor.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
accessmode_t get_mode() const;
</pre></blockquote>

<p>
<b>Effects:</b> Returns the mode of the mapped region.
</p>

<p>
<b>Returns:</b> If default constructed or moved returns invalid_mode. Otherwise the mode passed
in the non-default constructor.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
void flush(std::size_t region_offset = 0, std::size_t numbytes = 0);
</pre></blockquote>

<p>
<b>Effects:</b> If we call <i>mapping_address</i> to the result of the expression
<pre>static_cast&lt;char*&gt;(this-&gt;get_address())</pre> the function
flushes the range [<i>mapping_address</i> + region_offset, <i>mapping_address</i> + region_offset + numbytes)
to the mappable object passed in the non-default constructor. If the object is default constructed,
or moved, the function does nothing.
</p>

<p>
<b>Throws:</b> An error derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
void swap(mapped_region &amp;other);
</pre></blockquote>

<p>
<b>Effects:</b> Swaps the resources contents of this object with the resources of <i>other</i>.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
~mapped_region();
</pre></blockquote>

<p>
<b>Effects:</b> Destroys the object. Reading from and writing to the memory address range that the
object was holding is now undefined and might crash the process.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<p>The <tt>mapped_region</tt> class is constructed taking a reference to a <tt>memory_mappable</tt> class.
This class contains the mapping handle needed to map a region of the mapping in the process address space.
The <tt>memory_mappable</tt> object used in the constructor can be destroyed before destroying all the
created <tt>mapped_region</tt> objects from it since both POSIX and Windows support this possibility. This
simplifies mapping management, and there is no need to store the <tt>memory_mappable</tt> object after the 
user has constructed all the needed <tt>mapped_region</tt> objects.</p>

<p><tt>mapped_region</tt> is a single class representing a region of a file, shared memory or a device
in the address space of the process, so the user can develop device independent code without the need
of virtual functions.</p>

<p><tt>memory_mappable</tt> and <tt>mapped_region</tt> are <i>non-copyable</i> and <i>non-assignable</i>
but both are <i><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1952.htm">movable (N1952)</a></i>, so we can store them safely in STL containers, to create groups of mapped
regions of files or shared memory objects.</p>

<h2><a name="MappingFiles"></a>Mapping Files: <tt>std::file_mapping</tt></h2>

<p>This paper proposes a standard file mapping class derived from <tt>memory_mappable</tt>.
The standard interface would allow just linking a file with the process, so that we 
can create several <tt>mapped_region</tt> objects from the file:</p>

<h3><a name="ClassFileMapping"></a>class file_mapping synopsis</h3>

<blockquote><pre>namespace std {

class file_mapping : public memory_mappable
{
   public:

   file_mapping(const char *filename, memory_mappable::accessmode_t mode);

   ~file_mapping();
};

}  //namespace std {</pre></blockquote>

<h3><a name="ClassFileMappingMembers"></a>class file_mapping members</h3>

<blockquote><pre>
file_mapping(const char *filename, memory_mappable::accessmode_t mode);
</pre></blockquote>

<p>
<b>Effects:</b> Allocates resources to so that the user can map parts of a file
using mapped_regions. The constructor initializes the base <tt>memory_mappable</tt> 
class calling <tt>memory_mappable::init().</tt> with valid handle and mode values.
</p>

<p>
<b>Postcondition:</b> this->get_handle() != <tt>memory_mappable::invalid_handle</tt> &&
this->get_mode() != <tt>memory_mappable::invalid_mode</tt>.
</p>

<p>
<b>Throws:</b> Throws a exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
~file_mapping();
</pre></blockquote>

<p>
<b>Effects:</b> Closes the file mapping and frees resources. All mapped regions
created from this object will be valid after the destruction.
</p>

<p>
<b>Throws:</b> Nothing.
</p>

<h3><a name="ClassFileMappingExample"></a>File Mapping Example</h3>

<p>Using <tt>file_mapping</tt> and <tt>mapped_region</tt>, a file can be easily mapped in memory:</p>

<blockquote><pre>//Create a file_mapping object
std::file_mapping  mapping("/home/user/file", std::memory_mappable::read_write);

//Create a mapped_region covering the whole file
std::mapped_region region (mapping, std::mapped_region::read_write);

//Obtain the size and the address of the mapped region
void *address    = region.get_address();
std::size_t size = region.get_size();

//Set the whole file 
std::memset(address, 0xFF, size);

//Make sure all the data is flushed to disk
region.flush();</pre></blockquote>

<h2><a name="SharedMemoryMapping"></a>Shared Memory Mapping: <tt>std::shared_memory_object</tt></h2>

<p>C++ has file management functions, so that it can create, delete, read and write files. That's why
the <tt>file_mapping</tt> class has no functions to create, open or modify files. However, there
are no such functions for shared memory objects. This paper proposes two options:</p>

<ul>
<li>
We can choose to implement new stream classes for shared memory (named, for example, 
<tt>shmistream</tt>, <tt>shmostream</tt> and <tt>shmstream</tt>)
</li>
<li>
Add creation and connection functions to the shared memory object class.</li>
</ul>

<p>This paper does not make any recommendation, but it's clear that adding new stream classes
is more complicated than adding these functions to the mapping class. However, there is no doubt
that a shared memory stream class can be very useful for several applications, like logging
or tracing. This paper proposes an interface for a shared memory object with shared memory
creation and connection interface that can be complementary to the stream classes:</p>

<h3><a name="ClassSharedMemoryObject"></a>class shared_memory_object synopsis</h3>

<blockquote><pre>namespace std {

namespace detail{

typedef /*implementation-defined*/ create_t;
typedef /*implementation-defined*/ open_t;
typedef /*implementation-defined*/ open_or_create_t;

}  //namespace detail{

extern std::detail::create_t create_only;
extern std::detail::create_t open_only;
extern std::detail::create_t open_or_create;

class shared_memory_object : public memory_mappable
{
   public:

   shared_memory_object(detail::create_t, const char *name, memory_mappable::accessmode_t mode);

   shared_memory_object(detail::open_or_create_t, const char *name, memory_mappable::accessmode_t mode);

   shared_memory_object(detail::open_t, const char *name, memory_mappable::accessmode_t mode);

   void truncate(std::size_t new_size);

   static bool remove(const char *name);

   ~shared_memory_object();
};

}  //namespace std {</pre></blockquote>

<h3><a name="ClassSharedMemoryMembers"></a>class shared_memory_object members</h3>

<blockquote><pre>
shared_memory_object(detail::create_t, const char *name, memory_mappable::accessmode_t mode);
</pre></blockquote>

<p>
<b>Effects:</b> Creates a shared memory object with name <tt><i>name</i></tt>, with the accessmode
<tt><i>mode</i></tt>. If the shared memory object previously exists, the construction fails. If successful,
the constructor initializes the base <tt>memory_mappable</tt> class calling <tt>memory_mappable::init()</tt>
with valid handle and mode values.</p>

<p>
<b>Postcondition:</b> this->get_handle() != <tt>memory_mappable::invalid_handle</tt> &&
this->get_mode() != <tt>memory_mappable::invalid_mode</tt>.
</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
shared_memory_object(detail::open_or_create_t, const char *name, memory_mappable::accessmode_t mode);
</pre></blockquote>

<p>
<b>Effects:</b> Tries to create a shared memory object with name <tt><i>name</i></tt>, with the
accessmode <tt><i>mode</i></tt>. If it's previously created, tries to open the shared memory object.
If successful, the constructor initializes the base <tt>memory_mappable</tt> class calling 
<tt>memory_mappable::init()</tt> with valid handle and mode values.</p>

<p>
<b>Postcondition:</b> this->get_handle() != <tt>memory_mappable::invalid_handle</tt> &&
this->get_mode() != <tt>memory_mappable::invalid_mode</tt>.
</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
shared_memory_object(detail::open_t, const char *name, memory_mappable::accessmode_t mode);
</pre></blockquote>

<p><b>Effects:</b> Tries to open a shared memory object with name <tt><i>name</i></tt>, with the
accessmode <tt><i>mode</i></tt>. If successful, the constructor initializes the base <tt>memory_mappable</tt> 
class calling <tt>memory_mappable::init()</tt> with valid handle and mode values.</p>

<p>
<b>Postcondition:</b> this->get_handle() != <tt>memory_mappable::invalid_handle</tt> &&
this->get_mode() != <tt>memory_mappable::invalid_mode</tt>.
</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
void truncate(std::size_t new_size);
</pre></blockquote>

<p><b>Effects:</b> Sets the new size of the shared memory. The object must have been 
opened in <tt><i>read_write</i></tt> mode.</p>

<p>
<b>Throws:</b> An exception derived from <tt>std::exception</tt> on error.
</p>

<blockquote><pre>
static bool remove(const char *name);
</pre></blockquote>

<p><b>Effects:</b> Erases the shared memory object with name <tt><i>name</i></tt> from the system.
This might fail if any process has a <tt>mapped_region</tt> object created from this object, or the
shared memory object does not exist.</p>

<p>
<b>Throws:</b> Nothing.
</p>

<blockquote><pre>
~shared_memory_object();
</pre></blockquote>

<p><b>Effects:</b> Destructor, closes the shared memory object. The shared memory object is not destroyed
and can be again opened using another <tt>shared_memory_object</tt>. All mapped regions are still valid
after destructor ends.</p>

<p>
<b>Throws:</b> Nothing.
</p>

<h3><a name="ClassSharedMemoryObjectExample"></a>Shared Memory Object Example</h3>

<p>Once the shared memory object has been created, any process can map any part of the shared memory
object in the process' address space, creating <tt>mapped_region</tt> objects from the shared memory object:</p>

<blockquote><pre>//Create a shared memory object
std::shared_memory_object shm(std::create_only, "name", std::memory_mappable::read_write);

//Set the size of the shared memory
shm.truncate(1000);

//Create a mapped_region using the shared memory object
std::mapped_region region (shm, std::mapped_region::read_write);

//Obtain the size and the address of the mapped region
void *address    = region.get_address();
std::size_t size = region.get_size();

//Write the whole memory
std::memset(address, 0xFF, size);</pre></blockquote>

<h2><a name="UnifyingIostreams"></a>Unifying With Iostreams</h2>

<h3><a name="#UnifyingIostreamsFilebuf"></a>Using basic_filebuf as file mapping source</h3>

<p>The file mapping class can also offer file mapping possibilities using basic_fstream or basic_filebuf
objects as constructor arguments. This way, libraries with access to a <tt>basic_filebuf</tt> object don't need to know
the path of the file.</p>

<blockquote><pre>class file_mapping
{
   public:
   //...

   template <class E, class T>
   file_mapping(const basic_filebuf&lt;E, T&gt; &amp;file, memory_mappable::accessmode_t mode);
};</pre></blockquote>

<p>In most systems, the implementation just needs to duplicate the operating system's file handle
contained in the basic_filebuf class and also obtain access to the read-write capabilities of the file
to see if the mapping capabilities requested by the user are allowed by <tt>basic_filebuf</tt>.</p>

<h3><a name="#UnifyingIostreamsOpenmode"></a>Using <tt>std::ios_base::openmode</tt> flags</h3>

<p>The library can also be simplified reusing <tt>std::ios_base</tt> bitmask values instead of creating
new <tt><i>read_only</i></tt> and <tt><i>read_write</i></tt> bitmasks. However, <tt>std::ios_base</tt>
is missing <tt><i>copy_on_write</i></tt> and there is no way to express <tt><i>create_only</i></tt>,
<tt><i>open_or_create</i></tt> or <tt><i>open_only</i></tt> creation modes. Expanding <tt>std::ios_base::openmode</tt>
to hold these new values is also a possibility.</p>

<h3><a name="#UnifyingIostreamsFilebufMappable"></a><tt>basic_filebuf</tt> is a <tt>mappable</tt> class</h3>

Another simplification would be to avoid the <tt>file_mapping</tt> class and make <tt>basic_filebuf</tt> a class
derived from <tt>memory_mappable</tt>. This way a C++ file would be used to produce <tt>mapped_region</tt> objects:

<blockquote><pre>//Open a file
std::fstream file("filename");

//Map the whole file
std::mapped_region region(*file.rdbuf(), std::mapped_region::copy_on_write);</pre></blockquote>

<h3><a name="#ShmStreamBuf"></a>Shared memory stream classes</h3>

<p>If <tt>basic_filebuf</tt> is defined as a <i>mappable</i> object, we could create the shared memory equivalent
of this class. This would unify file and shared memory mapping mechanism:

<blockquote><pre>//Open shared memory object
std::shmstream shm("shmname");

//Map the whole shared memory object
std::mapped_region region(*shm.rdbuf(), std::mapped_region::copy_on_write);</pre></blockquote>

<p>As mentioned, we would still need additional <tt>std::ios_base</tt> flags to express creation possibilities
like create only, open or create or open only, independently from the read-write mode.</p>

<h2><a name="PortablePaths"></a>Using Portable Paths</h2>

<p><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1975.html">Filesystem (N1975)</a>
proposal, includes a portable path class named <tt>basic_path</tt>. The proposed <tt>file_mapping</tt>
class could also have a constructor taking a <tt>basic_path</tt> argument, to avoid user conversions:</p>

<blockquote><pre>class file_mapping
{
   public:
   //...

   // Allocates resources to so that the user can map parts of a file
   // using mapped_regions. Throws if there is an error
   template&lt;class String, class Traits&gt;
   file_mapping(const basic_path&lt;String, class Traits&gt; &amp; path, memory_mappable::accessmode_t mode);
};</pre></blockquote>

<h2><a name="PortableSharedMemory"></a>Portable Shared Memory Name</h2>

<p>The portability of the shared memory object name is an old problem even in POSIX. In Posix, the name
of the shared memory object conforms to the construction rules for a pathname. If the name begins with
the slash, then processes opening a shared memory object with the same value of name refer to the same shared
memory object. If the initial slash is not specified, or there are more slashes in the name, the effect
is implementation defined. So the only portable shared memory has the following pattern:
<tt>/SharedMemoryName</tt></p>

<p>In Windows platforms the name can contain any character except the backlash character and the user
must add some special prefix to share the object in the global or session namespace.</p>

<p>So the only portable name between both platforms is to use the <tt>/SharedMemoryName</tt> pattern, but
this name conforms to a UNIX path rule for a file in the root directory. For an easier C++ usage, this
paper proposes a portable name that conforms to a C++ variable name rule or a C++ reserved word:

<ul>
<li>Starts with a letter, lowercase or uppercase, such as a letter from a to z or from A to Z.
Examples: <i>Sharedmemory</i>, <i>sharedmemory</i>, <i>sHaReDmEmOrY</i>...</li>
<li>Can include letters, underscore, or digits. Examples: <i>shm1</i>, <i>shm2and3</i>, <i>ShM3plus4</i>...</li>
</ul>

<p>POSIX implementation just needs to add an initial slash to the name. Windows implementation needs
no change.</p>

<h2><a name="PriorArt"></a>Prior Art</h2>

<p>The proposed shared memory and memory mapped files interface is based in the new interface proposed
for the Boost.Interprocess library (the rework of the <a href="http://ice.prohosting.com/newfunk/boost/libs/shmem/doc/html/index.html">Shmem</a> library).
This library is being used by several projects needing high performance
interprocess communications.</p>

<h2><a name="Conclusions"></a>Conclusions</h2>

<p>This paper is mainly presented to test if there is interest for standard shared memory and memory mapped
classes in the C++ committee. The presented interface is a first approach to the solution and by no means a
definitive proposal.</p>

<p>Shared memory and memory mapped files are basic building blocks for interprocess communication for advanced
interprocess communications, like message queues or named fifos. This paper proposes the standardization of shared
memory and memory mapped files present in nearly all UNIX and Windows operating systems presenting a common 
implementable subset of features.</p>

<p>Memory mapped files can be also useful for a single process environment in order to obtain data persistence.
However, shared memory and memory mapped files for interprocess communications need process synchronization
mechanisms. These should follow the same interface as their thread-synchronization counterparts, so several
utilities like scoped locks could be reused with process-shared synchronization utilities.</p>

<h2><a name="Acknowledgments"></a>Acknowledgments</h2>

Thanks to all Boost mailing list members for their suggestions and the thorough Shmem library review. 
Special thanks to Andrew Bromage, who suggested separating file mapping and mapped region concepts.


<h2><a name="References"></a>References</h2>

<ul>
<li><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1975.html">N1975</a>: Filesystem Library Proposal for TR2 (Revision 3)</li>
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1952.htm">N1952</a>: A Proposal to Add an Rvalue Reference to the C++ Language. Proposed Wording. Revision 2</li>
<li><a href="http://ice.prohosting.com/newfunk/boost/libs/shmem/doc/html/index.html">Shmem</a> library</li>
</ul>

</body></html>