// 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) #define ACE_MAP_FILE(_hnd, _access, _offHigh, _offLow, _nBytes, _baseAdd) \ MapViewOfFileEx (_hnd, _access, _offHigh, _offLow, _nBytes, _baseAdd) 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 const 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 ("_")); } 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 () { #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) { // 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; // Get an object handle to the named reserved memory object. DWORD size_high; DWORD size_low; #if defined (ACE_WIN64) size_high = static_cast (this->local_cb_.sh_.max_size_ >> 32); size_low = static_cast (this->local_cb_.sh_.max_size_ & 0xFFFFFFFF); #else size_high = 0; size_low = ACE_Utils::truncate_cast (this->local_cb_.sh_.max_size_); #endif object_handle_ = ACE_TEXT_CreateFileMapping (INVALID_HANDLE_VALUE, &sa, 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: // 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 */