diff options
Diffstat (limited to 'ACE/ace/MMAP_Memory_Pool.cpp')
-rw-r--r-- | ACE/ace/MMAP_Memory_Pool.cpp | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/ACE/ace/MMAP_Memory_Pool.cpp b/ACE/ace/MMAP_Memory_Pool.cpp new file mode 100644 index 00000000000..6405e8cbcd2 --- /dev/null +++ b/ACE/ace/MMAP_Memory_Pool.cpp @@ -0,0 +1,589 @@ +// $Id$ + +// MMAP_Memory_Pool.cpp +#include "ace/MMAP_Memory_Pool.h" +#include "ace/OS_NS_sys_mman.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/Log_Msg.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_INLINE__) +#include "ace/MMAP_Memory_Pool.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_MMAP_Memory_Pool) + +void +ACE_MMAP_Memory_Pool::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_MMAP_Memory_Pool::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_MMAP_Memory_Pool::release (int destroy) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::release"); + +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) + ACE_BASED_POINTER_REPOSITORY::instance ()->unbind (this->mmap_.addr ()); +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + + if (destroy) + this->mmap_.remove (); + else + this->mmap_.close (); + return 0; +} + +int +ACE_MMAP_Memory_Pool::sync (size_t len, int flags) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::sync"); + + return this->mmap_.sync (len, flags); +} + +int +ACE_MMAP_Memory_Pool::sync (int flags) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::sync"); + + size_t const len = ACE_Utils::truncate_cast<size_t> ( + ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END)); + + return this->mmap_.sync (len, flags); +} + +/// Sync @a len bytes of the memory region to the backing store starting +/// at <addr_>. +int +ACE_MMAP_Memory_Pool::sync (void *addr, size_t len, int flags) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::sync"); + return ACE_OS::msync (addr, len, flags); +} + +// Change the protection of the pages of the mapped region to <prot> +// starting at <this->base_addr_> up to <len> bytes. +// Change protection of all pages in the mapped region. + +int +ACE_MMAP_Memory_Pool::protect (size_t len, int prot) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::protect"); + + return this->mmap_.protect (len, prot); +} + +int +ACE_MMAP_Memory_Pool::protect (int prot) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::protect"); + + size_t const len = ACE_Utils::truncate_cast<size_t> ( + ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END)); + + return this->mmap_.protect (len, prot); +} + + +// Change the protection of the pages of the mapped region to <prot> +// starting at <addr> up to <len> bytes. + +int +ACE_MMAP_Memory_Pool::protect (void *addr, size_t len, int prot) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::protect"); + return ACE_OS::mprotect (addr, len, prot); +} + +ACE_MMAP_Memory_Pool::ACE_MMAP_Memory_Pool ( + const ACE_TCHAR *backing_store_name, + const OPTIONS *options) + : base_addr_ (0), + use_fixed_addr_(0), + flags_ (MAP_SHARED), + write_each_page_ (false), + minimum_bytes_ (0), + sa_ (0), + file_mode_ (ACE_DEFAULT_FILE_PERMS), + install_signal_handler_ (true) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::ACE_MMAP_Memory_Pool"); + +#if (defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)) || defined (ACE_WIN32) + // For plaforms that give the faulting address. + guess_on_fault_ = false; +#else + // For plaforms that do NOT give the faulting address, let the + // options decide whether to guess or not. + if (options) + guess_on_fault_ = options->guess_on_fault_; + else + // If no options are specified, default to true. + guess_on_fault_ = true; +#endif /* (defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)) || defined (ACE_WIN32) */ + + // Only change the defaults if <options> != 0. + if (options) + { + if (options->flags_ != 0) + this->flags_ = options->flags_; + use_fixed_addr_ = options->use_fixed_addr_; + + if (use_fixed_addr_ == ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED) + { + this->base_addr_ = const_cast<void *> (options->base_addr_); + ACE_SET_BITS (flags_, MAP_FIXED); + } + this->write_each_page_ = options->write_each_page_; + this->minimum_bytes_ = options->minimum_bytes_; + if (options->sa_ != 0) + this->sa_ = options->sa_; + this->file_mode_ = options->file_mode_; + this->install_signal_handler_ = options->install_signal_handler_; + } + + if (backing_store_name == 0) + { + // Only create a new unique filename for the backing store file + // if the user didn't supply one... +#if defined (ACE_DEFAULT_BACKING_STORE) + // Create a temporary file. + ACE_OS::strcpy (this->backing_store_name_, + ACE_DEFAULT_BACKING_STORE); +#else /* ACE_DEFAULT_BACKING_STORE */ + if (ACE::get_temp_dir (this->backing_store_name_, + MAXPATHLEN - 17) == -1) + // -17 for ace-malloc-XXXXXX + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Temporary path too long, ") + ACE_TEXT ("defaulting to current directory\n"))); + this->backing_store_name_[0] = 0; + } + + // Add the filename to the end + ACE_OS::strcat (this->backing_store_name_, + ACE_TEXT ("ace-malloc-XXXXXX")); + + // If requested an unique filename, use mktemp to get a random file. + if (options && options->unique_) + ACE_OS::mktemp(this->backing_store_name_); +#endif /* ACE_DEFAULT_BACKING_STORE */ + } + else + ACE_OS::strsncpy (this->backing_store_name_, + backing_store_name, + (sizeof this->backing_store_name_ / sizeof (ACE_TCHAR))); + +#if !defined (ACE_WIN32) + if (this->install_signal_handler_) + { + if (this->signal_handler_.register_handler (SIGSEGV, this) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT("%p\n"), this->backing_store_name_)); + } +#endif /* ACE_WIN32 */ +} + +ACE_MMAP_Memory_Pool::~ACE_MMAP_Memory_Pool (void) +{ +} + +// Compute the new map_size of the backing store and commit the +// memory. +int +ACE_MMAP_Memory_Pool::commit_backing_store_name (size_t rounded_bytes, + size_t & map_size) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::commit_backing_store_name"); + +#if defined (__Lynx__) + map_size = rounded_bytes; +#else + size_t seek_len; + + if (this->write_each_page_) + // Write to the end of every block to ensure that we have enough + // space in the backing store. + seek_len = this->round_up (1); // round_up(1) is one page. + else + // We're willing to risk it all in the name of efficiency... + seek_len = rounded_bytes; + + // The following loop will execute multiple times (if + // this->write_each_page == 1) or just once (if + // this->write_each_page == 0). + + for (size_t cur_block = 0; + cur_block < rounded_bytes; + cur_block += seek_len) + { + map_size = + ACE_Utils::truncate_cast<size_t> ( + ACE_OS::lseek (this->mmap_.handle (), + static_cast<ACE_OFF_T> (seek_len - 1), + SEEK_END)); + + if (map_size == static_cast<size_t> (-1) + || ACE_OS::write (this->mmap_.handle (), + "", + 1) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + this->backing_store_name_), + -1); + } + +#if defined (ACE_OPENVMS) + ::fsync(this->mmap_.handle()); +#endif + + // Increment by one to put us at the beginning of the next chunk... + ++map_size; +#endif /* __Lynx__ */ + return 0; +} + +// Memory map the file up to <map_size> bytes. + +int +ACE_MMAP_Memory_Pool::map_file (size_t map_size) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::map_file"); +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) + void* obase_addr = this->base_addr_; +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + + // Unmap the existing mapping. + this->mmap_.unmap (); + +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) + if (use_fixed_addr_ == ACE_MMAP_Memory_Pool_Options::NEVER_FIXED) + this->base_addr_ = 0; +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + + // Remap the file; try to stay at the same location as a previous mapping + // but do not force it with MAP_FIXED. Doing so will give the OS permission + // to map locations currently holding other things (such as the heap, or + // the C library) into the map file, producing very unexpected results. + if (this->mmap_.map (map_size, + PROT_RDWR, + this->flags_, + this->base_addr_, + 0, + this->sa_) == -1 + || (this->base_addr_ != 0 +#ifdef ACE_HAS_WINCE + && this->mmap_.addr () == 0)) // WinCE does not allow users to specify alloc addr. +#else + && this->mmap_.addr () != this->base_addr_)) +#endif // ACE_HAS_WINCE + { +#if 0 + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) addr = %@, base_addr = %@, map_size = %B, %p\n"), + this->mmap_.addr (), + this->base_addr_, + map_size, + this->backing_store_name_)); +#endif /* 0 */ + return -1; + } + else + { +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) + this->base_addr_ = this->mmap_.addr (); + + if (obase_addr && this->base_addr_ != obase_addr) + { + ACE_BASED_POINTER_REPOSITORY::instance ()->unbind (obase_addr); + } + + ACE_BASED_POINTER_REPOSITORY::instance ()->bind (this->base_addr_, + map_size); +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + return 0; + } +} + +// Ask operating system for more shared memory, increasing the mapping +// accordingly. Note that this routine assumes that the appropriate +// locks are held when it is called. + +void * +ACE_MMAP_Memory_Pool::acquire (size_t nbytes, + size_t &rounded_bytes) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::acquire"); + rounded_bytes = this->round_up (nbytes); + + // ACE_DEBUG ((LM_DEBUG, "(%P|%t) acquiring more chunks, nbytes = + // %B, rounded_bytes = %B\n", nbytes, rounded_bytes)); + + size_t map_size; + + if (this->commit_backing_store_name (rounded_bytes, + map_size) == -1) + return 0; + else if (this->map_file (map_size) == -1) + return 0; + + // ACE_DEBUG ((LM_DEBUG, "(%P|%t) acquired more chunks, nbytes = %B, + // rounded_bytes = %B, map_size = %B\n", nbytes, rounded_bytes, + // map_size)); + + return (void *) ((char *) this->mmap_.addr () + (this->mmap_.size () - rounded_bytes)); +} + +// Ask system for initial chunk of shared memory. + +void * +ACE_MMAP_Memory_Pool::init_acquire (size_t nbytes, + size_t &rounded_bytes, + int &first_time) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::init_acquire"); + + first_time = 0; + + if (nbytes < static_cast <size_t> (this->minimum_bytes_)) + nbytes = static_cast <size_t> (this->minimum_bytes_); + + if (this->mmap_.open (this->backing_store_name_, + O_RDWR | O_CREAT | O_TRUNC | O_EXCL, + this->file_mode_, this->sa_) != -1) + { + // First time in, so need to acquire memory. + first_time = 1; + + void *result = this->acquire (nbytes, rounded_bytes); + // After the first time, reset the flag so that subsequent calls + // will use MAP_FIXED + if (this->use_fixed_addr_ == ACE_MMAP_Memory_Pool_Options::FIRSTCALL_FIXED) + { + ACE_SET_BITS (flags_, MAP_FIXED); + } + return result; + } + else if (errno == EEXIST) + { + errno = 0; + // Reopen file *without* using O_EXCL... + if (this->mmap_.map (this->backing_store_name_, + static_cast<size_t> (-1), + O_RDWR, + this->file_mode_, + PROT_RDWR, + this->flags_, + this->base_addr_, + 0, + this->sa_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("MMAP_Memory_Pool::init_acquire, EEXIST")), + 0); + // After the first time, reset the flag so that subsequent calls + // will use MAP_FIXED + if (use_fixed_addr_ == ACE_MMAP_Memory_Pool_Options::FIRSTCALL_FIXED) + { + ACE_SET_BITS (flags_, MAP_FIXED); + } +#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1) + // Update the mapped segment information + ACE_BASED_POINTER_REPOSITORY::instance ()->bind (this->mmap_.addr(), + this->mmap_.size()); +#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */ + + return this->mmap_.addr (); + } + else + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("MMAP_Memory_Pool::init_acquire")), + 0); +} + +#if defined (ACE_WIN32) +int +ACE_MMAP_Memory_Pool::seh_selector (void *ep) +{ + DWORD const 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; +} +#endif /* ACE_WIN32 */ + +int +ACE_MMAP_Memory_Pool::remap (void *addr) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::remap"); + // ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Remapping with fault address at: %@\n"), addr)); + size_t const current_map_size = + ACE_Utils::truncate_cast<size_t> (ACE_OS::filesize (this->mmap_.handle ())); + // ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END); + + if (!(addr < (void *) ((char *) this->mmap_.addr () + current_map_size) + && addr >= this->mmap_.addr ())) + return -1; + + // Extend the mapping to cover the size of the backing store. + return this->map_file (current_map_size); +} + +ACE_MMAP_Memory_Pool_Options::ACE_MMAP_Memory_Pool_Options ( + const void *base_addr, + int use_fixed_addr, + bool write_each_page, + size_t minimum_bytes, + u_int flags, + bool guess_on_fault, + LPSECURITY_ATTRIBUTES sa, + mode_t file_mode, + bool unique, + bool install_signal_handler) + : base_addr_ (base_addr), + use_fixed_addr_ (use_fixed_addr), + write_each_page_ (write_each_page), + minimum_bytes_ (minimum_bytes), + flags_ (flags), + guess_on_fault_ (guess_on_fault), + sa_ (sa), + file_mode_ (file_mode), + unique_ (unique), + install_signal_handler_ (install_signal_handler) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool_Options::ACE_MMAP_Memory_Pool_Options"); + // for backwards compatability + if (base_addr_ == 0 && use_fixed_addr_ == ALWAYS_FIXED) + use_fixed_addr_ = FIRSTCALL_FIXED; +} + +#if !defined (ACE_WIN32) +int +ACE_MMAP_Memory_Pool::handle_signal (int signum, siginfo_t *siginfo, ucontext_t *) +{ + if (signum != SIGSEGV) + return -1; +#if 0 + else + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) received %S\n"), signum)); +#endif + // ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) new mapping address = %@\n"), (char *) this->base_addr_ + current_map_size)); + +#if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR) + // Make sure that the pointer causing the problem is within the + // range of the backing store. + + if (siginfo != 0) + { + // ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) si_signo = %d, si_code = %d, addr = %@\n"), siginfo->si_signo, siginfo->si_code, siginfo->si_addr)); + if (this->remap ((void *) siginfo->si_addr) == -1) + return -1; + // ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) address %@ out of range\n", + // siginfo->si_addr), -1); + return 0; + } +#else + ACE_UNUSED_ARG(siginfo); +#endif /* ACE_HAS_SIGINFO_T && !defined ACE_LACKS_SI_ADDR */ + // If guess_on_fault_ is true, then we want to try to remap without + // knowing the faulting address. guess_on_fault_ can only be true + // on platforms that do not provide the faulting address through + // signals or exceptions. We check to see if the mapping is up to + // date. If it is, then this fault isn't due to this mapping and we + // pass it on. + if (guess_on_fault_) + { + // Check if the current mapping is up to date. + size_t const current_map_size = + ACE_Utils::truncate_cast<size_t> (ACE_OS::filesize (this->mmap_.handle ())); + + if (static_cast<size_t> (current_map_size) == this->mmap_.size ()) + { + // The mapping is up to date so this really is a bad + // address. Thus, remove current signal handler so process + // will fail with default action and core file will be + // written. + this->signal_handler_.remove_handler (SIGSEGV); + return 0; + } + + // Extend the mapping to cover the size of the backing store. + return this->map_file (current_map_size); + } + else + return -1; +} +#endif + +void * +ACE_MMAP_Memory_Pool::base_addr (void) const +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::base_addr"); + return this->base_addr_; +} + +size_t +ACE_MMAP_Memory_Pool::round_up (size_t nbytes) +{ + ACE_TRACE ("ACE_MMAP_Memory_Pool::round_up"); + return ACE::round_to_pagesize (nbytes); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Lite_MMAP_Memory_Pool) + +ACE_Lite_MMAP_Memory_Pool::ACE_Lite_MMAP_Memory_Pool (const ACE_TCHAR *backing_store_name, + const OPTIONS *options) + : ACE_MMAP_Memory_Pool (backing_store_name, options) +{ + ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::ACE_Lite_MMAP_Memory_Pool"); +} + +ACE_Lite_MMAP_Memory_Pool::~ACE_Lite_MMAP_Memory_Pool (void) +{ +} + +int +ACE_Lite_MMAP_Memory_Pool::sync (size_t, int) +{ + ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync"); + return 0; +} + +int +ACE_Lite_MMAP_Memory_Pool::sync (int) +{ + ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync"); + return 0; +} + +int +ACE_Lite_MMAP_Memory_Pool::sync (void *, size_t, int) +{ + ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync"); + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL |