Click here to Skip to main content
15,896,154 members
Articles / Desktop Programming / MFC

Memory Map Class : Policy Based Design

Rate me:
Please Sign up or sign in to vote.
4.94/5 (16 votes)
26 Feb 2005CPOL6 min read 98.2K   1.1K   53  
Memory Map class provides IPC using shared memory. The Policy based design provides flexibility, extensibility and easy to use class.
#ifndef _MEMMAP_H_
#define _MEMMAP_H_
///////////////////////////////////////////////////////////////////////////////
// MemMap.h
// Rohit Joshi
// 12/14/2004
// Policy based design of Memory mapped file.
// Following policies are define.
// 1. CreationPolicy: Default value: Create
//    It allows user to create file for mapping memory.
//    Currently two implementations are available in which Create
//    creates new file where as Open opens existing file. If doesn't
//    exist, it throws error
// 2. DeletionPolicy: Default value:  Delete
//    It allows user to decide whether to delete memory mapped file
//    when object goes outof scope or keep the file for other processes to
//    use. The default value is Delete which will delete the file. Other
//    is NoDelete which won't delete the file.
// 3. MappingPolicy: Default Value: SharedMap
//    It allows user to decided whether to create memory mapped filed as
//    shared among processes or private to process
// 4. MemorySyncPolicy: Default value MemSync
//    In shared mode,data written in memory needs to be syncronized with
//    data in file. It allows user to sync data immidiatly or in asyncronous 
//    mode. Inconsistent data can be invalidate using MemInvalidate policy
////////////////////////////////////////////////////////////////////////////////
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <cerrno>
#include <cstdio>
#include <cstdarg>


namespace Joshi
{
///////////////////////////////////////////////////////////////////////////////
// CREATION POLICY:
//  1. CreateReadWrite
//  2. CreateReadWriteTruncate
//  3. OpenReadWrite

///////////////////////////////////////////////////////////////////////////////
// CreateReadWrite:Create a file new file if not exist. Open in read/write mode
///////////////////////////////////////////////////////////////////////////////
    class CreateReadWrite 
    {
    public:
        // create a file and open in read/write mode
        static int OpenFile(const std::string &sFileName)
        {
             return open(sFileName.c_str(), O_CREAT | O_RDWR, 0666);
        }
        // current opearion
        static bool TruncateFile(int nFd, unsigned nFileSize, void **pMemFile)
        {
            return true;
        }
    };
///////////////////////////////////////////////////////////////////////////////
// CreateReadWriteTruncate:Create a file new file if not exist. Open in 
// read/write and trucate mode
///////////////////////////////////////////////////////////////////////////////
    class CreateReadWriteTruncate 
    {
    public:
        // Open in read/write and truncate mode
        static int OpenFile(const std::string &sFileName)
        {
             return open(sFileName.c_str(), O_CREAT | O_TRUNC| O_RDWR, 0666);
        }
        //truncate the file and set it to zero
        static bool TruncateFile(int nFd, unsigned nFileSize, void **pMemFile)
        {
            char cZero = 0;
            if ((lseek(nFd, nFileSize - 1, SEEK_SET) == -1) ||
                (write(nFd, &cZero, 1) == -1))
               return false;
            memset(*pMemFile, 0, nFileSize);
            return true;
        }
    };
///////////////////////////////////////////////////////////////////////////////
// OpenReadWrite:Open file in read/write mode if exist
///////////////////////////////////////////////////////////////////////////////
    class OpenReadWrite 
    {
    public:
        // Open in read/write mode
        static int OpenFile(const std::string &sFileName)
        {
             return open(sFileName.c_str(), O_RDWR, 0666);
        }
        // current opearion
        static bool TruncateFile(int nFd, unsigned nFileSize, void **pMemFile)
        {
            return true;
        }
    };
///////////////////////////////////////////////////////////////////////////////
// OpenReadOnly:Open file in read only mode if exist
///////////////////////////////////////////////////////////////////////////////
    class OpenReadOnly 
    {
    public:
        // create a file and open in read/write mode
        static int OpenFile(const std::string &sFileName)
        {
             return open(sFileName.c_str(), O_RDWR, 0666);
        }
        // current opearion
        static bool TruncateFile(int nFd, unsigned nFileSize, void **pMemFile)
        {
            return true;
        }
    };
///////////////////////////////////////////////////////////////////////////////
// MAPPING POLICY:
//  1. SharedMapReadWrite
//  2. PrivateMapReadWrite

/////////////////////////////////////////////////////////////////////////////
// SharedMap: Maps the memory for shared access among the proceces
// //////////////////////////////////////////////////////////////////////////
    class SharedMapReadWrite
    {
    public:
        // map the file
        static void* Map(unsigned nFileSize, int nMapFd)
        {
            return mmap(0, nFileSize, PROT_READ|PROT_WRITE,
                    MAP_SHARED, nMapFd, 0);
        }
    };
/////////////////////////////////////////////////////////////////////////////
// PrivateMap: Maps the memory for private access to process
// //////////////////////////////////////////////////////////////////////////
    class PrivateMapReadWrite
    {
    public:
        // map the file
        static void* Map(unsigned nFileSize, int nMapFd)
        {
            return mmap(0, nFileSize, PROT_READ|PROT_WRITE,
                    MAP_PRIVATE, nMapFd, 0);
        }

    };
///////////////////////////////////////////////////////////////////////////////
// DELETION POLICY:
// 1. Delete
// 2. DoNotDelete

///////////////////////////////////////////////////////////////////////////////
// Delete: It deletes (unlink) the file
//////////////////////////////////////////////////////////////////////////////
    class  Delete
    {
    public:
        static void DeleteFile(const std::string &sFileName) 
        {
            if (sFileName.length() > 0) {
                unlink(sFileName.c_str());
            }
        }
    };
///////////////////////////////////////////////////////////////////////////////
// DoNotDelete: It doesn't delete the file
//////////////////////////////////////////////////////////////////////////////
    class DoNotDelete
    {
    public:
        static void DeleteFile(const std::string &sFileName) {}
    };
 
///////////////////////////////////////////////////////////////////////////////
// MEMSYNC POLICY:
// 1. MemAsync
// 2. MemSync
// 3. MemInvalidate
///////////////////////////////////////////////////////////////////////////////
// MemAsync: It syncs the data asyncronously
//////////////////////////////////////////////////////////////////////////////
    class  MemAsync
    {
    public:
        // syncronize data
        static bool Sync(void **pMemFile, unsigned nFileSize) 
        {
            if(msync(*pMemFile, nFileSize, MS_ASYNC) == -1)
               return false;
            return true;
        }
    };
///////////////////////////////////////////////////////////////////////////////
// MemSync: It syncs the data syncronously
//////////////////////////////////////////////////////////////////////////////
    class MemSync
    {
    public:
        // syncronize data
        static bool Sync(void **pMemFile, unsigned nFileSize) 
        {
            if(msync(*pMemFile, nFileSize, MS_SYNC) == -1)
               return false;
            return true;
        }
    };
///////////////////////////////////////////////////////////////////////////////
// MemInvalidate: Invalidate memory region
//////////////////////////////////////////////////////////////////////////////
    class MemInvalidate
    {
    public:
        // syncronize data
        static bool Sync(void **pMemFile, unsigned nFileSize) 
        {
            if(msync(*pMemFile, nFileSize, MS_INVALIDATE) == -1)
               return false;
            return true;
        }
    };
/////////////////////////////////////////////////////////////////////////////
// MemMapFileException: Memory map exception class
// It concatinates the user error message with system error message.
////////////////////////////////////////////////////////////////////////////
    class MemMapFileException : public std::exception
    {
    private:
        std::string message;
    public:
        explicit MemMapFileException(const char* format, ...): message("Error: ")
        {
            va_list args;
            char buffer[256];
            memset(buffer, '\0', sizeof(buffer));
            va_start(args, format);
            vsnprintf(buffer, sizeof(buffer), format, args);
            va_end(args);
            message += buffer;
            message += ':';
            message += strerror(errno);

        }
        ~MemMapFileException() throw() {}
        const char* what() const throw()
        {
            return message.c_str();
        }
    };

//////////////////////////////////////////////////////////////////////////////
// MemMapFilePtr: It is a memory map wrapper class which provides the memory
// mapping functionality based on below defined policies.
// 1. CreationPolicy
// 2. DeletionPolicy
// 3. MappingPolicy
// 4. MemSyncPolicy
//////////////////////////////////////////////////////////////////////////////

    template<typename CreationPolicy,
             typename DeletionPolicy, 
             typename MappingPolicy,
             typename MemSyncPolicy
             >
    class MemMapFile
    {
        int m_nMapFd;  // file descriptor
        unsigned m_nFileSize;
        std::string m_sFileName;
        void *m_pMemFile;

        // private functions not implemented
        MemMapFile();
        MemMapFile(const MemMapFile &);
        MemMapFile& operator=(const MemMapFile&);

    public:

        // constructor
        MemMapFile(const unsigned nSize, const std::string &sFileName) throw(MemMapFileException):
                               m_nMapFd(-1),m_nFileSize(nSize),m_sFileName(sFileName),
                               m_pMemFile(MAP_FAILED) 
        {

        }
        // destructor
        virtual ~MemMapFile() throw()
        {
            DeleteFile();
        }    
        // Create memory mapped file
        void OpenFile() throw (MemMapFileException)
        {
            // create the memory-mapped file
            int fd = CreationPolicy::OpenFile(m_sFileName);
            if (fd < 0) {
                std::string sFileName(m_sFileName);
                m_sFileName = "";
                throw MemMapFileException("Cannot open file [%s]",
                        sFileName.c_str());
            }
            m_nMapFd = fd;
        }

        // Map the file
        void* MapFile() throw (MemMapFileException)
        {
            // map the file to memory
            m_pMemFile = MappingPolicy::Map(m_nFileSize, m_nMapFd);
            if (m_pMemFile == MAP_FAILED) {
                close(m_nMapFd);
                DeletionPolicy::DeleteFile(m_sFileName);
                throw MemMapFileException("Failed memory-mapping file: ",
                     m_sFileName.c_str());
            }
            return m_pMemFile;
        }
        // Sync the data
        void Sync() throw (MemMapFileException)
        {
            if(!MemSyncPolicy::Sync(&m_pMemFile, m_nFileSize))
            {
                close(m_nMapFd);
                DeletionPolicy::DeleteFile(m_sFileName);
                throw MemMapFileException("Failed to syncronize data to file : [%s], size[%d]",
                                           m_sFileName.c_str(),m_nFileSize);
            }
                
        }
        // trucate the file
        void TruncateFile(const unsigned nSize) throw (MemMapFileException)
        {
            // set the file's size
            if (!CreationPolicy::TruncateFile(m_nMapFd, m_nFileSize, &m_pMemFile)) {
                close(m_nMapFd);
                DeletionPolicy::DeleteFile(m_sFileName);
                throw MemMapFileException("Failed to truncate the file : [%s], size[%d]",
                                     m_sFileName.c_str(),m_nFileSize);
            }
            m_nFileSize = nSize;
        }

        // Delete the file based on policy
        void DeleteFile() throw()
            //throw (std::exception)
        {
            Unmap();
            DeletionPolicy::DeleteFile(m_sFileName);
            m_sFileName = "";
        }

        // unmap the file
        void Unmap() throw()
        {
            if (m_pMemFile != MAP_FAILED) {
                close(m_nMapFd);
                munmap((char *)m_pMemFile, m_nFileSize);
                m_pMemFile = MAP_FAILED;
            }

        }


    };       

//////////////////////////////////////////////////////////////////////////////
// MemMapFilePtr: It is a memory map wrapper class which provides the memory
// mapping functionality based on below defined policies.
// 1. CreationPolicy: Default value: CreateReadWrite
// 2. DeletionPolicy: Default value: DeleteFile
// 3. MappingPolicy:  Default Value: SharedMap
// 4. MemSyncPolicy:  Defauly value: MemSync
//////////////////////////////////////////////////////////////////////////////
    template<typename T, typename CreationPolicy=CreateReadWrite,
             typename DeletionPolicy=DoNotDelete, 
             typename MappingPolicy=SharedMapReadWrite,
             typename MemSyncPolicy=MemSync
             >
    class MemMapFilePtr
    {
        typedef MemMapFile<CreationPolicy,DeletionPolicy,MappingPolicy,MemSync> MemMapFileDef;
        MemMapFileDef * m_pFile;
        T* m_pObj;

        // private functions not implemented
        MemMapFilePtr();
        MemMapFilePtr(const MemMapFilePtr &);
        MemMapFilePtr& operator=(const MemMapFilePtr&);

    public:

        // constructor
        explicit MemMapFilePtr(const std::string &sFileName, unsigned nSize=sizeof(T)):m_pFile(0)
        {
            m_pFile = new MemMapFileDef(nSize, sFileName);
            m_pFile->OpenFile();
            m_pFile->TruncateFile(sizeof(T));
            m_pObj = reinterpret_cast<T*>(m_pFile->MapFile());

        }
        // syncronize the data
        void Sync()
        {
            m_pFile->Sync();
        }
        // destructor
        virtual ~MemMapFilePtr()
        {
            m_pFile->DeleteFile();
            delete m_pFile;
        }
        // operator*
        T& operator*()
        {
            return *m_pObj;
        }
        // operator*
        T& operator*() const
        {
            return *m_pObj;
        }
        // operator->
        T* operator->()
        {
            return m_pObj;
        }
        // operator ->
        T* operator->() const
        {
            return m_pObj;
        }
    };

} // namespace
#endif // _MEMMAP_H_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
Rohit Joshi is a software engineer working for a telecom company in USA. He has development expirience using C, C++ ,C#, VoiceXML, ASR, IMAP, LDAP, HTTP, SIP, H323 on unix/linux and platforms.

Comments and Discussions