mirror of
https://github.com/mangosfour/server.git
synced 2025-12-11 16:37:03 +00:00
389 lines
12 KiB
C++
389 lines
12 KiB
C++
// $Id: Pagefile_Memory_Pool.cpp 96985 2013-04-11 15:50:32Z huangh $
|
|
|
|
// Pagefile_Memory_Pool.cpp
|
|
#include "ace/Pagefile_Memory_Pool.h"
|
|
|
|
#if !defined (__ACE_INLINE__)
|
|
#include "ace/Pagefile_Memory_Pool.inl"
|
|
#endif /* __ACE_INLINE__ */
|
|
|
|
#include "ace/Log_Category.h"
|
|
#include "ace/Auto_Ptr.h"
|
|
#include "ace/RW_Thread_Mutex.h"
|
|
#include "ace/OS_NS_sys_mman.h"
|
|
#include "ace/OS_NS_string.h"
|
|
#include "ace/OS_NS_sys_stat.h"
|
|
#include "ace/OS_NS_unistd.h"
|
|
#include "ace/Truncate.h"
|
|
|
|
#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
|
|
#include "ace/Based_Pointer_T.h"
|
|
#include "ace/Based_Pointer_Repository.h"
|
|
#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
|
|
|
|
|
|
|
|
#if defined (ACE_WIN32) && !defined (ACE_HAS_PHARLAP)
|
|
#if !defined (ACE_HAS_WINCE)
|
|
#define ACE_MAP_FILE(_hnd, _access, _offHigh, _offLow, _nBytes, _baseAdd)\
|
|
MapViewOfFileEx (_hnd, _access, _offHigh, _offLow, _nBytes, _baseAdd)
|
|
#else //if !defined (ACE_HAS_WINCE)
|
|
#define ACE_MAP_FILE(_hnd, _access, _offHigh, _offLow, _nBytes, _baseAdd)\
|
|
MapViewOfFile (_hnd, _access, _offHigh, _offLow, _nBytes)
|
|
#endif /* !ACE_HAS_WINCE */
|
|
|
|
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
|
|
|
|
ACE_Pagefile_Memory_Pool_Options::ACE_Pagefile_Memory_Pool_Options (
|
|
void *base_addr,
|
|
size_t max_size)
|
|
: base_addr_ (base_addr),
|
|
max_size_ (max_size)
|
|
{
|
|
}
|
|
|
|
int
|
|
ACE_Pagefile_Memory_Pool::release (int)
|
|
{
|
|
return this->unmap ();
|
|
}
|
|
|
|
ACE_Pagefile_Memory_Pool::ACE_Pagefile_Memory_Pool (const ACE_TCHAR *backing_store_name,
|
|
const OPTIONS *options)
|
|
: shared_cb_ (0),
|
|
object_handle_ (0),
|
|
page_size_ (ACE_Pagefile_Memory_Pool::round_to_page_size (1))
|
|
{
|
|
// Initialize local copy of pool statistics.
|
|
if (options != 0)
|
|
{
|
|
this->local_cb_.req_base_ = options->base_addr_;
|
|
this->local_cb_.mapped_base_ = 0;
|
|
this->local_cb_.sh_.max_size_ =
|
|
options->max_size_;
|
|
this->local_cb_.sh_.mapped_size_ = 0;
|
|
this->local_cb_.sh_.free_offset_ =
|
|
this->local_cb_.sh_.mapped_size_;
|
|
this->local_cb_.sh_.free_size_ = 0;
|
|
}
|
|
else
|
|
{
|
|
this->local_cb_.req_base_ = 0;
|
|
this->local_cb_.mapped_base_ = 0;
|
|
this->local_cb_.sh_.max_size_ =
|
|
this->round_to_chunk_size (page_size_) ;
|
|
this->local_cb_.sh_.mapped_size_ = 0;
|
|
this->local_cb_.sh_.free_offset_ =
|
|
this->local_cb_.sh_.mapped_size_;
|
|
this->local_cb_.sh_.free_size_ = 0;
|
|
}
|
|
|
|
int update_backing_store_name = backing_store_name == 0 ? 0 : 1;
|
|
|
|
if (backing_store_name == 0)
|
|
// Only create a new unique filename for the backing store file if
|
|
// the user didn't supply one...
|
|
backing_store_name = ACE_DEFAULT_PAGEFILE_POOL_NAME;
|
|
|
|
ACE_OS::strsncpy (this->backing_store_name_,
|
|
backing_store_name,
|
|
(sizeof this->backing_store_name_ / sizeof (ACE_TCHAR)));
|
|
|
|
if (update_backing_store_name
|
|
&& ACE_OS::strlen (this->backing_store_name_) < sizeof this->backing_store_name_)
|
|
ACE_OS::strcat (this->backing_store_name_,
|
|
ACE_TEXT ("_"));
|
|
}
|
|
|
|
ACE_Pagefile_Memory_Pool::~ACE_Pagefile_Memory_Pool (void)
|
|
{
|
|
}
|
|
|
|
void *
|
|
ACE_Pagefile_Memory_Pool::acquire (size_t nbytes,
|
|
size_t &rounded_bytes)
|
|
{
|
|
rounded_bytes = round_to_page_size (nbytes);
|
|
void *result = 0;
|
|
int first_time = 0;
|
|
|
|
// Check local_cb_ for consistency. Remap, if extra space is too
|
|
// small and/or we didn't map the whole shared memory section
|
|
if (this->shared_cb_->sh_.mapped_size_
|
|
> this->local_cb_.sh_.mapped_size_
|
|
|| this->shared_cb_->sh_.free_size_ < rounded_bytes)
|
|
{
|
|
size_t append = 0;
|
|
if (rounded_bytes > this->shared_cb_->sh_.free_size_)
|
|
append = rounded_bytes - this->shared_cb_->sh_.free_size_;
|
|
|
|
if (this->map (first_time, append) < 0)
|
|
return result;
|
|
}
|
|
|
|
// Get the block from extra space and update shared and local
|
|
// control block
|
|
if (this->shared_cb_->sh_.free_size_ < rounded_bytes)
|
|
return result;
|
|
|
|
result = (void *)((char *) this->local_cb_.mapped_base_
|
|
+ this->shared_cb_->sh_.free_offset_);
|
|
this->shared_cb_->sh_.free_offset_ += rounded_bytes;
|
|
this->shared_cb_->sh_.free_size_ -= rounded_bytes;
|
|
this->local_cb_.sh_ = this->shared_cb_->sh_;
|
|
|
|
return result;
|
|
}
|
|
|
|
void *
|
|
ACE_Pagefile_Memory_Pool::init_acquire (size_t nbytes,
|
|
size_t &rounded_bytes,
|
|
int &first_time)
|
|
{
|
|
// Map the shared memory and get information, if we created the
|
|
// shared memory.
|
|
if (this->map (first_time) < 0)
|
|
return 0;
|
|
|
|
if (first_time != 0)
|
|
// We created the shared memory. So we have to allocate the
|
|
// requested memory.
|
|
return this->acquire (nbytes, rounded_bytes);
|
|
else
|
|
// We just mapped the memory and return the base address
|
|
return (void *)((char *) this->local_cb_.mapped_base_
|
|
+ ACE_Pagefile_Memory_Pool::round_to_page_size
|
|
((int) sizeof (Control_Block)));
|
|
}
|
|
|
|
int
|
|
ACE_Pagefile_Memory_Pool::seh_selector (void *ep)
|
|
{
|
|
DWORD ecode = ((EXCEPTION_POINTERS *) ep)->ExceptionRecord->ExceptionCode;
|
|
|
|
if (ecode == EXCEPTION_ACCESS_VIOLATION)
|
|
{
|
|
void * fault_addr = (void *)
|
|
((EXCEPTION_POINTERS *) ep)->ExceptionRecord->ExceptionInformation[1];
|
|
|
|
if (this->remap (fault_addr) == 0)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ACE_Pagefile_Memory_Pool::remap (void *addr)
|
|
{
|
|
// If the shared memory is not mapped or the address, that caused
|
|
// the memory fault is outside of the commited range of chunks, we
|
|
// return.
|
|
if (this->shared_cb_ == 0
|
|
|| addr < this->local_cb_.mapped_base_
|
|
|| addr >= (void *)((char *) this->local_cb_.mapped_base_
|
|
+ this->shared_cb_->sh_.mapped_size_))
|
|
return -1;
|
|
|
|
// We can solve the problem by committing additional chunks.
|
|
int first_time = 0;
|
|
return this->map (first_time);
|
|
}
|
|
|
|
int
|
|
ACE_Pagefile_Memory_Pool::unmap (void)
|
|
{
|
|
#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
|
|
ACE_BASED_POINTER_REPOSITORY::instance ()->unbind
|
|
(this->local_cb_.mapped_base_);
|
|
#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
|
|
|
|
// Cleanup cached pool pointer.
|
|
this->shared_cb_ = 0;
|
|
|
|
if (this->local_cb_.sh_.mapped_size_ > 0)
|
|
::UnmapViewOfFile (this->local_cb_.mapped_base_);
|
|
|
|
// Reset local pool statistics.
|
|
this->local_cb_.req_base_ =
|
|
ACE_DEFAULT_PAGEFILE_POOL_BASE;
|
|
this->local_cb_.mapped_base_ = 0;
|
|
this->local_cb_.sh_.max_size_ =
|
|
ACE_DEFAULT_PAGEFILE_POOL_SIZE;
|
|
this->local_cb_.sh_.mapped_size_ = 0;
|
|
this->local_cb_.sh_.free_offset_ =
|
|
this->local_cb_.sh_.mapped_size_;
|
|
this->local_cb_.sh_.free_size_ = 0;
|
|
|
|
// Release the pool
|
|
if (this->object_handle_ != 0)
|
|
{
|
|
::CloseHandle (this->object_handle_);
|
|
this->object_handle_ = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ACE_Pagefile_Memory_Pool::map (int &first_time,
|
|
size_t append_bytes)
|
|
{
|
|
size_t map_size;
|
|
void *map_addr;
|
|
|
|
// Create file mapping, if not yet done
|
|
if (object_handle_ == 0)
|
|
{
|
|
#if !defined (ACE_LACKS_WIN32_SECURITY_DESCRIPTORS)
|
|
// Allow access by all users.
|
|
SECURITY_ATTRIBUTES sa;
|
|
SECURITY_DESCRIPTOR sd;
|
|
::InitializeSecurityDescriptor (&sd,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
::SetSecurityDescriptorDacl (&sd,
|
|
TRUE,
|
|
0,
|
|
FALSE);
|
|
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = &sd;
|
|
sa.bInheritHandle = FALSE;
|
|
#endif /* ACE_LACKS_WIN32_SECURITY_DESCRIPTORS */
|
|
|
|
// Get an object handle to the named reserved memory object.
|
|
DWORD size_high;
|
|
DWORD size_low;
|
|
#if defined (ACE_WIN64)
|
|
size_high = static_cast<DWORD> (this->local_cb_.sh_.max_size_ >> 32);
|
|
size_low = static_cast<DWORD> (this->local_cb_.sh_.max_size_ & 0xFFFFFFFF);
|
|
#else
|
|
size_high = 0;
|
|
size_low = ACE_Utils::truncate_cast<DWORD> (this->local_cb_.sh_.max_size_);
|
|
#endif
|
|
|
|
object_handle_ =
|
|
ACE_TEXT_CreateFileMapping (INVALID_HANDLE_VALUE,
|
|
#if !defined (ACE_LACKS_WIN32_SECURITY_DESCRIPTORS)
|
|
&sa,
|
|
#else
|
|
0,
|
|
#endif /* !ACE_LACKS_WIN32_SECURITY_DESCRIPTORS */
|
|
PAGE_READWRITE | SEC_RESERVE,
|
|
size_high,
|
|
size_low,
|
|
this->backing_store_name_);
|
|
if (object_handle_ == 0)
|
|
return -1;
|
|
first_time =
|
|
::GetLastError () == ERROR_ALREADY_EXISTS
|
|
? 0
|
|
: 1;
|
|
}
|
|
|
|
// Do the initial mapping.
|
|
if (this->shared_cb_ == 0)
|
|
{
|
|
// Map a view to the shared memory. Note: <MapViewOfFile[Ex]>
|
|
// does *not* commit the pages!
|
|
this->shared_cb_ = (ACE_Pagefile_Memory_Pool::Control_Block *)
|
|
ACE_MAP_FILE (this->object_handle_,
|
|
FILE_MAP_WRITE,
|
|
0,
|
|
0,
|
|
this->local_cb_.sh_.max_size_,
|
|
this->local_cb_.req_base_);
|
|
if (this->shared_cb_ == 0)
|
|
return -1;
|
|
|
|
// There was no previous mapping, so we map the first chunk and
|
|
// initialize the shared pool statistics.
|
|
if (first_time)
|
|
{
|
|
// 1st block is used to keep shared memory statistics.
|
|
map_size =
|
|
ACE_Pagefile_Memory_Pool::round_to_chunk_size
|
|
(ACE_Pagefile_Memory_Pool::round_to_page_size
|
|
((int) sizeof(Control_Block))
|
|
+ append_bytes);
|
|
|
|
if (::VirtualAlloc ((void *) this->shared_cb_,
|
|
map_size,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE) == 0)
|
|
return -1;
|
|
|
|
this->shared_cb_->req_base_ = 0;
|
|
this->shared_cb_->mapped_base_ = 0;
|
|
this->local_cb_.mapped_base_ = this->shared_cb_;
|
|
this->local_cb_.sh_.mapped_size_ = map_size;
|
|
this->local_cb_.sh_.free_offset_ =
|
|
round_to_page_size ((int) sizeof (Control_Block));
|
|
this->local_cb_.sh_.free_size_ =
|
|
this->local_cb_.sh_.mapped_size_ -
|
|
this->local_cb_.sh_.free_offset_;
|
|
this->shared_cb_->sh_ = this->local_cb_.sh_;
|
|
}
|
|
|
|
// The shared memory exists, so we map the first chunk to the
|
|
// base address of the pool to get the shared pool statistics.
|
|
else
|
|
{
|
|
// 1st block is used to keep shared memory statistics.
|
|
map_size =
|
|
ACE_Pagefile_Memory_Pool::round_to_chunk_size
|
|
((int) sizeof (Control_Block));
|
|
|
|
if (::VirtualAlloc ((void *) this->shared_cb_,
|
|
map_size,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE) == 0)
|
|
return -1;
|
|
this->local_cb_.mapped_base_ = this->shared_cb_;
|
|
this->local_cb_.sh_.mapped_size_ = map_size;
|
|
}
|
|
}
|
|
|
|
// If the shared memory is larger than the part we've already
|
|
// committed, we have to remap it.
|
|
if (this->shared_cb_->sh_.mapped_size_ >
|
|
this->local_cb_.sh_.mapped_size_
|
|
|| append_bytes > 0)
|
|
{
|
|
map_size =
|
|
(this->shared_cb_->sh_.mapped_size_ -
|
|
this->local_cb_.sh_.mapped_size_)
|
|
+ ACE_Pagefile_Memory_Pool::round_to_chunk_size
|
|
(append_bytes);
|
|
|
|
map_addr = (void *)((char *) this->shared_cb_ +
|
|
this->local_cb_.sh_.mapped_size_);
|
|
|
|
if (::VirtualAlloc (map_addr,
|
|
map_size,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE) == 0)
|
|
return -1;
|
|
else if (append_bytes > 0)
|
|
{
|
|
this->shared_cb_->sh_.mapped_size_ +=
|
|
round_to_chunk_size (append_bytes);
|
|
this->shared_cb_->sh_.free_size_ =
|
|
this->shared_cb_->sh_.mapped_size_ -
|
|
this->shared_cb_->sh_.free_offset_;
|
|
}
|
|
}
|
|
|
|
// Update local copy of the shared memory statistics.
|
|
this->local_cb_.sh_ =
|
|
this->shared_cb_->sh_;
|
|
#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
|
|
ACE_BASED_POINTER_REPOSITORY::instance ()->bind
|
|
(this->local_cb_.mapped_base_,
|
|
this->local_cb_.sh_.mapped_size_);
|
|
#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
|
|
|
|
return 0;
|
|
}
|
|
|
|
ACE_END_VERSIONED_NAMESPACE_DECL
|
|
|
|
#endif /* ACE_WIN32 && !ACE_HAS_PHARLAP */
|