summaryrefslogtreecommitdiff
path: root/ace/Pagefile_Memory_Pool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ace/Pagefile_Memory_Pool.cpp')
-rw-r--r--ace/Pagefile_Memory_Pool.cpp362
1 files changed, 362 insertions, 0 deletions
diff --git a/ace/Pagefile_Memory_Pool.cpp b/ace/Pagefile_Memory_Pool.cpp
new file mode 100644
index 00000000000..99a80760893
--- /dev/null
+++ b/ace/Pagefile_Memory_Pool.cpp
@@ -0,0 +1,362 @@
+// $Id$
+
+// 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_Msg.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"
+
+#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 */
+
+ACE_RCSID(ace, Pagefile_Memory_Pool, "$Id$")
+
+#if defined (ACE_WIN32)
+#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 /* !defined (ACE_HAS_WINCE) */
+
+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;
+ }
+
+ 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)));
+}
+
+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_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0))
+ // 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 /* (defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) */
+
+ // 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 = this->local_cb_.sh_.max_size_;
+#endif
+
+ object_handle_ =
+ ACE_TEXT_CreateFileMapping (INVALID_HANDLE_VALUE,
+#if (defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0))
+ &sa,
+#else
+ 0,
+#endif /* (defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) */
+ 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;
+}
+
+#endif /* ACE_WIN32 */
+