From 1029d0d2bb8563bdafc092d552d41a8b2529b052 Mon Sep 17 00:00:00 2001 From: "John D. Moore" Date: Fri, 12 Jul 2002 19:30:30 +0000 Subject: [PATCH] Implementations for win32 + POSIX. Win32 tested. [SVN r14427] --- src/shared_memory.cpp | 262 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 src/shared_memory.cpp diff --git a/src/shared_memory.cpp b/src/shared_memory.cpp new file mode 100644 index 00000000..c5c30fc9 --- /dev/null +++ b/src/shared_memory.cpp @@ -0,0 +1,262 @@ +// Copyright (C) 2002 +// William E. Kempf, David Moore +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. + +#include + +#if defined(BOOST_HAS_WINTHREADS) +#include + +// Next line should really be BOOST_HAS_POSIX_xxx +#elif defined(BOOST_HAS_PTHREADS) + +#include +#include + +// Need to busy-wait on POSIX +#include +#include + +#endif + + +namespace +{ + +const int HEADER_ALIGN=16; + +struct hdr +{ + size_t len; + unsigned int count; +}; + + + +void fillzero(void *ptr, size_t len) +{ + memset(ptr,0,len); +} + +void noinit(void *,size_t) +{ + +} + +}; + + +namespace boost +{ + +shared_memory:: +shared_memory(const char *name,size_t len) : m_ptr(NULL),m_mem_obj(0),m_h_event(NULL), + m_len(len),m_initfunc(&noinit) +{ + create(name,len); +} + +// Obtain a shared memory block and initialize it with initfunc +shared_memory:: +shared_memory(const char *name,size_t len,const boost::function2 &initfunc) : + m_ptr(NULL),m_mem_obj(0),m_h_event(NULL),m_len(len),m_initfunc(initfunc) +{ + create(name,len); +} + + + +shared_memory:: +~shared_memory() +{ + + if(m_ptr) + { + m_ptr = ((char *) m_ptr - HEADER_ALIGN); + hdr *p_hdr = (hdr *)m_ptr; + + if(p_hdr) + { + p_hdr->count--; + } +#if defined(BOOST_HAS_WINTHREADS) + + UnmapViewOfFile(m_ptr); + + if(m_mem_obj) + { + CloseHandle(reinterpret_cast(m_mem_obj)); + } + if(m_h_event) + { + CloseHandle(reinterpret_cast(m_h_event)); + } +#elif defined (BOOST_HAS_PTHREADS) + if(p_hdr->count == 0) + { + shm_unlink(m_name); + } + munmap(m_ptr,m_len); +#endif + + } +} + + + + +void +shared_memory:: +create(const char *name,size_t len) +{ +#if defined(BOOST_HAS_WINTHREADS) + HANDLE h_map = NULL; + HANDLE h_event = NULL; + + DWORD ret; + bool b_creator = false; + + std::string obj_name = "_EVT_"; + obj_name += name; + h_event = CreateEvent(NULL,TRUE,FALSE,obj_name.c_str()); + + if(h_event == NULL) + { + throw boost::thread_resource_error(); + } + b_creator = (GetLastError() != ERROR_ALREADY_EXISTS); + + h_map = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,len+HEADER_ALIGN,name); + + if(h_map) + { + m_ptr = (char *)MapViewOfFile(h_map,FILE_MAP_WRITE,0,0,0); + if(m_ptr) + { + // Get a pointer to our header, and move our real ptr past this. + hdr *p_hdr = (hdr *)m_ptr; + m_ptr = ((char *)m_ptr + HEADER_ALIGN); + + if(b_creator) + { + // Call the initialization function for the user area. + m_initfunc(m_ptr,len); + p_hdr->len = len; + p_hdr->count = 1; + SetEvent(h_event); + } + else + { + ret = WaitForSingleObject(h_event,INFINITE); + if(ret != WAIT_OBJECT_0) + { + CloseHandle(h_event); + CloseHandle(h_map); + throw boost::thread_resource_error(); + } + + // We've got a previously constructed object. + (p_hdr->count)++; + } + } + else + { + CloseHandle(h_event); + throw boost::thread_resource_error(); + } + } + + m_mem_obj = reinterpret_cast(h_map); + m_h_event = reinterpret_cast(h_event); + +#elif defined (BOOST_HAS_PTHREADS) + int fd_smo; // descriptor to shared memory object + bool b_creator = true; + + fd_smo = shm_open(name,O_RDWR|O_CREAT|O_EXCL,SHM_MODE); + + if(fd_smo == -1) + { + if(errno == EEXIST) + { + // We lost the race. We should just re-open with shared access + // below. + fd_smo = shm_open(name,O_RDWR,SHM_MODE); + + b_creator = false + } + else + { + throw boost::thread_resource_error(); + } + } + else + { + // We're the creator. Use ftrunctate to set the size. + b_creator = true; + // + // Add error check on ftruncate. + ftruncate(fd_smo,len+HEADER_ALIGN); + } + + m_ptr = (char *)mmap(NULL,len + HEADER_ALIGN, + PROT_READ|PROT_WRITE, + MAP_SHARED, + fd_smo, + 0); + + + if(m_ptr) + { + // Get a pointer to our header, and move our real ptr past this. + hdr *p_hdr = (hdr *)ptr; + m_ptr = ((char *)m_ptr + HEADER_ALIGN); + + if(b_creator) + { + // Call the initialization function for the user area. + //flock(fd_smo); + + initfunc(ptr,len); + p_hdr->len = len; + p_hdr->count = 1; + + //funlock(fd_sm0); + } + else + { + // Need an event here. For now, busy wait. + while(p_hdr->len == 0) + { + //flock(fd_smo); + //funlock(fd_smo); + + boost::xtime xt; + boost::xtime_get(&xt,boost::TIME_UTC); + xt.sec++; + + boost::thread::sleep(xt); + } + + // We've got a previously constructed object. + (p_hdr->count)++; + } + } + close(fd_smo); + mem_obj = NULL; //reinterpret_cast(h_map); + event_obj = NULL; //reinterpret_cast(h_event); +#endif + + +} + + + +} // namespace boost