summaryrefslogtreecommitdiff
path: root/ACE/ace/MMAP_Memory_Pool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/MMAP_Memory_Pool.cpp')
-rw-r--r--ACE/ace/MMAP_Memory_Pool.cpp589
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