2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-22 03:42:07 +00:00

Implementations for win32 + POSIX. Win32 tested.

[SVN r14427]
This commit is contained in:
John D. Moore
2002-07-12 19:30:30 +00:00
parent 00038f78e5
commit 1029d0d2bb

262
src/shared_memory.cpp Normal file
View File

@@ -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 <boost/thread/shared_memory.hpp>
#if defined(BOOST_HAS_WINTHREADS)
#include <windows.h>
// Next line should really be BOOST_HAS_POSIX_xxx
#elif defined(BOOST_HAS_PTHREADS)
#include <sys/shm.h>
#include <sys/mman.h>
// Need to busy-wait on POSIX
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#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<void,void *,size_t> &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<HANDLE>(m_mem_obj));
}
if(m_h_event)
{
CloseHandle(reinterpret_cast<HANDLE>(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<int>(h_map);
m_h_event = reinterpret_cast<void *>(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<int>(h_map);
event_obj = NULL; //reinterpret_cast<void *>(h_event);
#endif
}
} // namespace boost