server/dep/acelite/ace/Shared_Memory_Pool.cpp
Salja f4be15a7af Some missing from merge.
Signed-off-by: Salja <salja2012@hotmail.de>
2020-02-16 02:50:23 +00:00

448 lines
14 KiB
C++

// $Id: Shared_Memory_Pool.cpp 97185 2013-05-30 18:51:35Z johnnyw $
// Shared_Memory_Pool.cpp
#include "ace/Shared_Memory_Pool.h"
#include "ace/OS_NS_sys_shm.h"
#include "ace/Log_Category.h"
#if !defined (ACE_LACKS_SYSV_SHMEM)
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_Pool)
ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options (
const char *base_addr,
size_t max_segments,
size_t file_perms,
ACE_OFF_T minimum_bytes,
size_t segment_size)
: base_addr_ (base_addr),
max_segments_ (max_segments),
minimum_bytes_ (minimum_bytes),
file_perms_ (file_perms),
segment_size_ (segment_size)
{
ACE_TRACE ("ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options");
}
void
ACE_Shared_Memory_Pool::dump (void) const
{
#if defined (ACE_HAS_DUMP)
ACE_TRACE ("ACE_Shared_Memory_Pool::dump");
#endif /* ACE_HAS_DUMP */
}
int
ACE_Shared_Memory_Pool::in_use (ACE_OFF_T &offset,
size_t &counter)
{
offset = 0;
SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
shmid_ds buf;
for (counter = 0;
counter < this->max_segments_ && st[counter].used_ == 1;
counter++)
{
if (ACE_OS::shmctl (st[counter].shmid_, IPC_STAT, &buf) == -1)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("shmctl")),
-1);
offset += buf.shm_segsz;
// ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) segment size = %d, offset = %d\n"), buf.shm_segsz, offset));
}
return 0;
}
int
ACE_Shared_Memory_Pool::find_seg (const void* const searchPtr,
ACE_OFF_T &offset,
size_t &counter)
{
offset = 0;
SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
shmid_ds buf;
for (counter = 0;
counter < this->max_segments_
&& st[counter].used_ == 1;
counter++)
{
if (ACE_OS::shmctl (st[counter].shmid_, IPC_STAT, &buf) == -1)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("shmctl")),
-1);
offset += buf.shm_segsz;
// If segment 'counter' starts at a location greater than the
// place we are searching for. We then decrement the offset to
// the start of counter-1. (flabar@vais.net)
if (((ptrdiff_t) offset + (ptrdiff_t) (this->base_addr_)) > (ptrdiff_t) searchPtr)
{
--counter;
offset -= buf.shm_segsz;
return 0;
}
// ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) segment size = %d, offset = %d\n"), buf.shm_segsz, offset));
}
return 0;
}
int
ACE_Shared_Memory_Pool::commit_backing_store_name (size_t rounded_bytes,
ACE_OFF_T &offset)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::commit_backing_store_name");
size_t counter;
SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
if (this->in_use (offset, counter) == -1)
return -1;
if (counter == this->max_segments_)
ACELIB_ERROR_RETURN ((LM_ERROR,
"exceeded max number of segments = %d, base = %u, offset = %u\n",
counter,
this->base_addr_,
offset),
-1);
else
{
int shmid = ACE_OS::shmget (st[counter].key_,
rounded_bytes,
this->file_perms_ | IPC_CREAT | IPC_EXCL);
if (shmid == -1)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("shmget")),
-1);
st[counter].shmid_ = shmid;
st[counter].used_ = 1;
void *address = (void *) (((char *) this->base_addr_) + offset);
void *shmem = ACE_OS::shmat (st[counter].shmid_,
(char *) address,
0);
if (shmem != address)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT("(%P|%t) %p, shmem = %u, address = %u\n"),
ACE_TEXT("shmat"),
shmem,
address),
-1);
}
return 0;
}
/// Handle SIGSEGV and SIGBUS signals to remap shared memory properly.
int
ACE_Shared_Memory_Pool::handle_signal (int, siginfo_t *siginfo, ucontext_t *)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::handle_signal");
// While FreeBSD 5.X has a siginfo_t struct with a si_addr field,
// it does not define SEGV_MAPERR.
#if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR) && \
(defined (SEGV_MAPERR) || defined (SEGV_MEMERR))
if (siginfo == 0)
return -1;
ACE_OFF_T offset;
// Make sure that the pointer causing the problem is within the
// range of the backing store.
// ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) si_signo = %d, si_code = %d, addr = %u\n"), siginfo->si_signo, siginfo->si_code, siginfo->si_addr));
size_t counter = 0;
if (this->in_use (offset, counter) == -1)
{
ACELIB_ERROR ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("in_use")));
}
else if (!(siginfo->si_code == SEGV_MAPERR
&& siginfo->si_addr < (((char *) this->base_addr_) + offset)
&& siginfo->si_addr >= ((char *) this->base_addr_)))
{
ACELIB_ERROR_RETURN ((LM_ERROR,
"(%P|%t) address %u out of range\n",
siginfo->si_addr),
-1);
}
// The above if case will check to see that the address is in the
// proper range. Therefore there is a segment out there that the
// pointer wants to point into. Find the segment that someone else
// has used and attach to it (flabar@vais.net)
counter = 0; // ret value to get shmid from the st table.
if (this->find_seg (siginfo->si_addr, offset, counter) == -1)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("in_use")),
-1);
void *address = (void *) (((char *) this->base_addr_) + offset);
SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
void *shmem = ACE_OS::shmat (st[counter].shmid_, (char *) address, 0);
if (shmem != address)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT("(%P|%t) %p, shmem = %u, address = %u\n"),
ACE_TEXT("shmat"),
shmem,
address),
-1);
// NOTE: this won't work if we dont have SIGINFO_T or SI_ADDR
#else
ACE_UNUSED_ARG (siginfo);
#endif /* ACE_HAS_SIGINFO_T && !defined (ACE_LACKS_SI_ADDR) */
return 0;
}
ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool (
const ACE_TCHAR *backing_store_name,
const OPTIONS *options)
: base_addr_ (0),
file_perms_ (ACE_DEFAULT_FILE_PERMS),
max_segments_ (ACE_DEFAULT_MAX_SEGMENTS),
minimum_bytes_ (0),
segment_size_ (ACE_DEFAULT_SEGMENT_SIZE)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool");
// Only change the defaults if <options> != 0.
if (options)
{
this->base_addr_ =
reinterpret_cast<void *> (const_cast<char *> (options->base_addr_));
this->max_segments_ = options->max_segments_;
this->file_perms_ = options->file_perms_;
this->minimum_bytes_ = options->minimum_bytes_;
this->segment_size_ = options->segment_size_;
}
if (backing_store_name)
{
// Convert the string into a number that is used as the segment
// key.
int segment_key;
int result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (backing_store_name),
"%d",
&segment_key);
if (result == 0 || result == EOF)
// The conversion to a number failed so hash with crc32
// ACE::crc32 is also used in <SV_Semaphore_Simple>.
this->base_shm_key_ =
(key_t) ACE::crc32 (ACE_TEXT_ALWAYS_CHAR (backing_store_name));
else
this->base_shm_key_ = segment_key;
if (this->base_shm_key_ == IPC_PRIVATE)
// Make sure that the segment can be shared between unrelated
// processes.
this->base_shm_key_ = ACE_DEFAULT_SHM_KEY;
}
else
this->base_shm_key_ = ACE_DEFAULT_SHM_KEY;
if (this->signal_handler_.register_handler (SIGSEGV, this) == -1)
ACELIB_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("ACE_Sig_Handler::register_handler")));
}
ACE_Shared_Memory_Pool::~ACE_Shared_Memory_Pool (void)
{
}
// Ask system for more shared memory.
void *
ACE_Shared_Memory_Pool::acquire (size_t nbytes,
size_t &rounded_bytes)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::acquire");
rounded_bytes = this->round_up (nbytes);
// ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) acquiring more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes));
ACE_OFF_T offset;
if (this->commit_backing_store_name (rounded_bytes, offset) == -1)
return 0;
// ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) acquired more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes));
return ((char *) this->base_addr_) + offset;
}
// Ask system for initial chunk of shared memory.
void *
ACE_Shared_Memory_Pool::init_acquire (size_t nbytes,
size_t &rounded_bytes,
int &first_time)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::init_acquire");
ACE_OFF_T shm_table_offset = ACE::round_to_pagesize (sizeof (SHM_TABLE));
rounded_bytes = this->round_up (nbytes > (size_t) this->minimum_bytes_
? nbytes
: (size_t) this->minimum_bytes_);
// Acquire the semaphore to serialize initialization and prevent
// race conditions.
int shmid = ACE_OS::shmget (this->base_shm_key_,
rounded_bytes + shm_table_offset,
this->file_perms_ | IPC_CREAT | IPC_EXCL);
if (shmid == -1)
{
if (errno != EEXIST)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("shmget")),
0);
first_time = 0;
shmid = ACE_OS::shmget (this->base_shm_key_, 0, 0);
if (shmid == -1)
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT ("(%P|%t) %p\n"),
ACE_TEXT ("shmget")),
0);
// This implementation doesn't care if we don't get the key we
// want...
this->base_addr_ =
ACE_OS::shmat (shmid,
reinterpret_cast<char *> (this->base_addr_),
0);
if (this->base_addr_ == reinterpret_cast<void *> (-1))
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT("(%P|%t) %p, base_addr = %u\n"),
ACE_TEXT("shmat"),
this->base_addr_),
0);
}
else
{
first_time = 1;
// This implementation doesn't care if we don't get the key we
// want...
this->base_addr_ =
ACE_OS::shmat (shmid,
reinterpret_cast<char *> (this->base_addr_),
0);
if (this->base_addr_ == reinterpret_cast<char *> (-1))
ACELIB_ERROR_RETURN ((LM_ERROR,
ACE_TEXT("(%P|%t) %p, base_addr = %u\n"),
ACE_TEXT("shmat"),
this->base_addr_), 0);
SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
st[0].key_ = this->base_shm_key_;
st[0].shmid_ = shmid;
st[0].used_ = 1;
for (size_t counter = 1; // Skip over the first entry...
counter < this->max_segments_;
counter++)
{
st[counter].key_ = this->base_shm_key_ + counter;
st[counter].shmid_ = 0;
st[counter].used_ = 0;
}
}
return (void *) (((char *) this->base_addr_) + shm_table_offset);
}
// Instruct the memory pool to release all of its resources.
int
ACE_Shared_Memory_Pool::release (int)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::release");
int result = 0;
SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
for (size_t counter = 0;
counter < this->max_segments_ && st[counter].used_ == 1;
counter++)
if (ACE_OS::shmctl (st[counter].shmid_, IPC_RMID, 0) == -1)
result = -1;
return result;
}
int
ACE_Shared_Memory_Pool::sync (ssize_t, int)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
return 0;
}
int
ACE_Shared_Memory_Pool::sync (void *, size_t, int)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
return 0;
}
int
ACE_Shared_Memory_Pool::protect (ssize_t, int)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
return 0;
}
int
ACE_Shared_Memory_Pool::protect (void *, size_t, int)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
return 0;
}
void *
ACE_Shared_Memory_Pool::base_addr (void) const
{
ACE_TRACE ("ACE_Shared_Memory_Pool::base_addr");
return this->base_addr_;
}
// Implement the algorithm for rounding up the request to an
// appropriate chunksize.
size_t
ACE_Shared_Memory_Pool::round_up (size_t nbytes)
{
ACE_TRACE ("ACE_Shared_Memory_Pool::round_up");
if (nbytes < this->segment_size_)
nbytes = this->segment_size_;
return ACE::round_to_pagesize (nbytes);
}
ACE_END_VERSIONED_NAMESPACE_DECL
#endif /* !ACE_LACKS_SYSV_SHMEM */