Program Listing for File shared_memory_pos.hpp

Return to documentation for file (/tmp/ws/src/ecl_core/ecl_ipc/include/ecl/ipc/shared_memory_pos.hpp)

/*****************************************************************************
** Ifdefs
*****************************************************************************/

#ifndef ECL_IPC_SHARED_MEMORY_RT_HPP_
#define ECL_IPC_SHARED_MEMORY_RT_HPP_

/*****************************************************************************
** Platform Check
*****************************************************************************/

#include <ecl/config.hpp>
#if defined(ECL_IS_POSIX)
#include <unistd.h>
#if !defined(ECL_IS_APPLE)
#include <bits/posix_opt.h>
#endif
#ifdef _POSIX_SHARED_MEMORY_OBJECTS
#if _POSIX_SHARED_MEMORY_OBJECTS > 0

/*****************************************************************************
** Ecl Functionality Defines
*****************************************************************************/

#ifndef ECL_HAS_POSIX_SHARED_MEMORY
  #define ECL_HAS_POSIX_SHARED_MEMORY
#endif
#ifndef ECL_HAS_SHARED_MEMORY
  #define ECL_HAS_SHARED_MEMORY
#endif

/*****************************************************************************
** Includes
*****************************************************************************/

#include <sstream>
#include <string>
#include <sys/mman.h>        /* For shm_open() */
#include <fcntl.h>           /* For O_* constants */
#include <ecl/exceptions/macros.hpp>
#include <ecl/exceptions/standard_exception.hpp>
#include <ecl/config/macros.hpp>

/*****************************************************************************
** Namespaces
*****************************************************************************/

namespace ecl {

/*****************************************************************************
** Exception Handling
*****************************************************************************/

namespace ipc {

#ifndef ECL_DISABLE_EXCEPTIONS
// Have to be public since its called from a template (inline) function.
ECL_PUBLIC ecl::StandardException openSharedSectionException(const char* loc);
ECL_PUBLIC ecl::StandardException memoryMapException(const char* loc);
#endif

class ECL_PUBLIC SharedMemoryBase {
public:
    void unlink();

protected:
    SharedMemoryBase(const std::string &name_id) :
        name(name_id),
        shared_memory_manager(false)
    {};
    int open();

    std::string name;
    bool shared_memory_manager;
};

} // namespace ipc

/*****************************************************************************
** Shared Memory
*****************************************************************************/
template <typename Storage>
class ECL_PUBLIC SharedMemory : public ipc::SharedMemoryBase
{
public:
    /*********************
    ** C&D's
    **********************/
    SharedMemory(const std::string& string_id);
    virtual ~SharedMemory();

    Storage* data() { return storage; }
private:
    SharedMemory() {}
    const int shared_memory_size;
    Storage *storage;
};

/*****************************************************************************
** Implementation
*****************************************************************************/

template <typename Storage>
SharedMemory<Storage>::SharedMemory(const std::string& string_id ) :
    ipc::SharedMemoryBase(std::string("/")+string_id),
    shared_memory_size(sizeof(Storage)),
    storage(NULL)
{
    int shm_descriptor = open();
    if ( shm_descriptor == -1) {
        ecl_throw( ipc::openSharedSectionException(LOC) );
    }
    /*********************
     * Mapping
     *********************/
    /*
     * Map the shared memory into your process's address space.
     *
     * Address: 0 lets posix choose the address.
     * Memory Protections: PROT_READ,WRITE,EXEC,NONE. Tells the MMU what to do. Match with the shm_open parameters.
     *                     PROT_EXEC only useful if you want to run a shared library there.
     * Mapping Flags: Always choose MAP_SHARED for shared memory! Other options almost irrelevant.
     * Descriptor : shm_send_descriptor from above.
     * OFFSET : we should never really want to offset a chunk of memory. Just point it at the start (0).
     *
     * mmap(address,sharedMemSize,memprotections,mappingflags,descriptor,offset);
     */
    void * shm_address;
    if ( (shm_address = mmap(0,shared_memory_size,PROT_READ|PROT_WRITE,MAP_SHARED,shm_descriptor,(long) 0)) == MAP_FAILED )
    {
        shared_memory_manager = false;
        close(shm_descriptor);
        unlink();
        ecl_throw( ipc::memoryMapException(LOC) );
    }
    /*
     * When first created, the shared memory has 0 size. You need to inflate it before
     * you can use it. The second argument, the length is measured in bytes.
     */
    if ( ftruncate(shm_descriptor,shared_memory_size) < 0 )
    {
        shared_memory_manager = false;
        close(shm_descriptor);
        unlink();
        ecl_throw(StandardException(LOC,OpenError,"Shared memory created, but inflation to the desired size failed."));
    }

    /*********************
    ** Close
    **********************/
    /*
     * This does not unmap the memory allocated to the block. It just closes the file
     * descriptor. Should do it early for tidiness if for no other reason.
     */
    close(shm_descriptor);

    storage = (Storage*) shm_address;

    // If just allocated, initialise the shared memory structure.
    if ( shared_memory_manager ) {
        *storage = Storage();
    }
}
template <typename Storage>
SharedMemory<Storage>::~SharedMemory()
{
    /* Might be worth putting a check on this later (i.e. < 0 is an error). */
    munmap( (void*) storage,shared_memory_size);
//    munmap(shm_address,shared_memory_size);

    if ( shared_memory_manager ) {
        unlink();
    }
}

} // namespace ecl


#endif /* _POSIX_SHARED_MEMORY_OBJECTS > 0 */
#endif /* _POSIX_SHARED_MEMORY_OBJECTS */
#endif /* ECL_IS_POSIX */

#endif /* ECL_IPC_SHARED_MEMORY_RT_HPP_ */