MMAP_Memory_Pool.cpp

Go to the documentation of this file.
00001 // MMAP_Memory_Pool.cpp,v 4.13 2006/06/09 14:03:06 jwillemsen Exp
00002 
00003 // MMAP_Memory_Pool.cpp
00004 #include "ace/MMAP_Memory_Pool.h"
00005 #include "ace/OS_NS_sys_mman.h"
00006 #include "ace/OS_NS_unistd.h"
00007 #include "ace/OS_NS_string.h"
00008 #include "ace/OS_NS_sys_stat.h"
00009 #include "ace/Log_Msg.h"
00010 
00011 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
00012 #include "ace/Based_Pointer_T.h"
00013 #include "ace/Based_Pointer_Repository.h"
00014 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1  */
00015 
00016 #if !defined (__ACE_INLINE__)
00017 #include "ace/MMAP_Memory_Pool.inl"
00018 #endif /* __ACE_INLINE__ */
00019 
00020 ACE_RCSID(ace,
00021           MMAP_Memory_Pool,
00022           "MMAP_Memory_Pool.cpp,v 4.13 2006/06/09 14:03:06 jwillemsen Exp")
00023 
00024 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00025 
00026 ACE_ALLOC_HOOK_DEFINE(ACE_MMAP_Memory_Pool)
00027 
00028 void
00029 ACE_MMAP_Memory_Pool::dump (void) const
00030 {
00031 #if defined (ACE_HAS_DUMP)
00032   ACE_TRACE ("ACE_MMAP_Memory_Pool::dump");
00033 #endif /* ACE_HAS_DUMP */
00034 }
00035 
00036 int
00037 ACE_MMAP_Memory_Pool::release (int destroy)
00038 {
00039   ACE_TRACE ("ACE_MMAP_Memory_Pool::release");
00040 
00041 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
00042   ACE_BASED_POINTER_REPOSITORY::instance ()->unbind (this->mmap_.addr ());
00043 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
00044 
00045   if (destroy)
00046   this->mmap_.remove ();
00047   else
00048     this->mmap_.close ();
00049   return 0;
00050 }
00051 
00052 int
00053 ACE_MMAP_Memory_Pool::sync (ssize_t len, int flags)
00054 {
00055   ACE_TRACE ("ACE_MMAP_Memory_Pool::sync");
00056 
00057   if (len < 0)
00058     len = ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END);
00059 
00060   return this->mmap_.sync (len, flags);
00061 }
00062 
00063 // Sync <len> bytes of the memory region to the backing store starting
00064 // at <addr_>.
00065 
00066 int
00067 ACE_MMAP_Memory_Pool::sync (void *addr, size_t len, int flags)
00068 {
00069   ACE_TRACE ("ACE_MMAP_Memory_Pool::sync");
00070   return ACE_OS::msync (addr, len, flags);
00071 }
00072 
00073 // Change the protection of the pages of the mapped region to <prot>
00074 // starting at <this->base_addr_> up to <len> bytes.  If <len> == -1
00075 // then change protection of all pages in the mapped region.
00076 
00077 int
00078 ACE_MMAP_Memory_Pool::protect (ssize_t len, int prot)
00079 {
00080   ACE_TRACE ("ACE_MMAP_Memory_Pool::protect");
00081 
00082   if (len < 0)
00083     len = ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END);
00084 
00085   return this->mmap_.protect (len, prot);
00086 }
00087 
00088 // Change the protection of the pages of the mapped region to <prot>
00089 // starting at <addr> up to <len> bytes.
00090 
00091 int
00092 ACE_MMAP_Memory_Pool::protect (void *addr, size_t len, int prot)
00093 {
00094   ACE_TRACE ("ACE_MMAP_Memory_Pool::protect");
00095   return ACE_OS::mprotect (addr, len, prot);
00096 }
00097 
00098 ACE_MMAP_Memory_Pool::ACE_MMAP_Memory_Pool (const ACE_TCHAR *backing_store_name,
00099                                             const OPTIONS *options)
00100   : base_addr_ (0),
00101     use_fixed_addr_(0),
00102     flags_ (MAP_SHARED),
00103     write_each_page_ (0),
00104     minimum_bytes_ (0),
00105     sa_ (0),
00106     file_mode_ (ACE_DEFAULT_FILE_PERMS)
00107 {
00108   ACE_TRACE ("ACE_MMAP_Memory_Pool::ACE_MMAP_Memory_Pool");
00109 
00110 #if (defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)) || defined (ACE_WIN32)
00111       // For plaforms that give the faulting address.
00112       guess_on_fault_ = false;
00113 #else
00114       // For plaforms that do NOT give the faulting address, let the
00115       // options decide whether to guess or not.
00116       if (options)
00117         guess_on_fault_ = options->guess_on_fault_;
00118       else
00119         // If no options are specified, default to true.
00120         guess_on_fault_ = true;
00121 #endif /* (defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)) || defined (ACE_WIN32) */
00122 
00123   // Only change the defaults if <options> != 0.
00124   if (options)
00125     {
00126       if (options->flags_ != 0)
00127         this->flags_ = options->flags_;
00128       use_fixed_addr_ = options->use_fixed_addr_;
00129 
00130       if (use_fixed_addr_ == ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED)
00131         {
00132           this->base_addr_ = const_cast<void *> (options->base_addr_);
00133           ACE_SET_BITS (flags_, MAP_FIXED);
00134         }
00135       this->write_each_page_ = options->write_each_page_;
00136       this->minimum_bytes_ = options->minimum_bytes_;
00137       if (options->sa_ != 0)
00138         this->sa_ = options->sa_;
00139       this->file_mode_ = options->file_mode_;
00140     }
00141 
00142   if (backing_store_name == 0)
00143     {
00144       // Only create a new unique filename for the backing store file
00145       // if the user didn't supply one...
00146 #if defined (ACE_DEFAULT_BACKING_STORE)
00147       // Create a temporary file.
00148       ACE_OS::strcpy (this->backing_store_name_,
00149                       ACE_DEFAULT_BACKING_STORE);
00150 #else /* ACE_DEFAULT_BACKING_STORE */
00151       if (ACE::get_temp_dir (this->backing_store_name_,
00152                              MAXPATHLEN - 17) == -1)
00153         // -17 for ace-malloc-XXXXXX
00154         {
00155           ACE_ERROR ((LM_ERROR,
00156                       ACE_LIB_TEXT ("Temporary path too long, ")
00157                       ACE_LIB_TEXT ("defaulting to current directory\n")));
00158           this->backing_store_name_[0] = 0;
00159         }
00160 
00161       // Add the filename to the end
00162       ACE_OS::strcat (this->backing_store_name_,
00163                       ACE_LIB_TEXT ("ace-malloc-XXXXXX"));
00164 
00165       // If requested an unique filename, use mktemp to get a random file.
00166       if (options->unique_)
00167         ACE_OS::mktemp(this->backing_store_name_);
00168 #endif /* ACE_DEFAULT_BACKING_STORE */
00169     }
00170   else
00171     ACE_OS::strsncpy (this->backing_store_name_,
00172                       backing_store_name,
00173                       (sizeof this->backing_store_name_ / sizeof (ACE_TCHAR)));
00174 
00175 #if !defined (ACE_WIN32)
00176   if (this->signal_handler_.register_handler (SIGSEGV, this) == -1)
00177     ACE_ERROR ((LM_ERROR,
00178                 "%p\n", this->backing_store_name_));
00179 #endif /* ACE_WIN32 */
00180 }
00181 
00182 ACE_MMAP_Memory_Pool::~ACE_MMAP_Memory_Pool (void)
00183 {
00184 }
00185 
00186 // Compute the new map_size of the backing store and commit the
00187 // memory.
00188 int
00189 ACE_MMAP_Memory_Pool::commit_backing_store_name (size_t rounded_bytes,
00190                                                  ACE_LOFF_T &map_size)
00191 {
00192   ACE_TRACE ("ACE_MMAP_Memory_Pool::commit_backing_store_name");
00193 
00194   size_t seek_len;
00195 
00196   if (this->write_each_page_)
00197     // Write to the end of every block to ensure that we have enough
00198     // space in the backing store.
00199     seek_len = this->round_up (1); // round_up(1) is one page.
00200   else
00201     // We're willing to risk it all in the name of efficiency...
00202     seek_len = rounded_bytes;
00203 
00204   // The following loop will execute multiple times (if
00205   // this->write_each_page == 1) or just once (if
00206   // this->write_each_page == 0).
00207 
00208   for (size_t cur_block = 0;
00209        cur_block < rounded_bytes;
00210        cur_block += seek_len)
00211     {
00212       map_size = ACE_OS::lseek (this->mmap_.handle (),
00213                                 static_cast<off_t> (seek_len - 1),
00214                                 SEEK_END);
00215 
00216       if (map_size == -1
00217           || ACE_OS::write (this->mmap_.handle (),
00218                             "",
00219                             1) == -1)
00220         ACE_ERROR_RETURN ((LM_ERROR,
00221                            ACE_LIB_TEXT ("(%P|%t) %p\n"),
00222                            this->backing_store_name_),
00223                           -1);
00224     }
00225 
00226 #if defined (ACE_OPENVMS)
00227   ::fsync(this->mmap_.handle());
00228 #endif
00229 
00230   // Increment by one to put us at the beginning of the next chunk...
00231   ++map_size;
00232 
00233   return 0;
00234 }
00235 
00236 // Memory map the file up to <map_size> bytes.
00237 
00238 int
00239 ACE_MMAP_Memory_Pool::map_file (ACE_LOFF_T map_size)
00240 {
00241   ACE_TRACE ("ACE_MMAP_Memory_Pool::map_file");
00242 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
00243     void* obase_addr = this->base_addr_;
00244 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
00245 
00246   // Unmap the existing mapping.
00247   this->mmap_.unmap ();
00248 
00249 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
00250   if(use_fixed_addr_ == ACE_MMAP_Memory_Pool_Options::NEVER_FIXED)
00251     this->base_addr_ = 0;
00252 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
00253 
00254   // Remap the file.
00255   if (this->mmap_.map (map_size,
00256                        PROT_RDWR,
00257                        this->flags_,
00258                        this->base_addr_,
00259                        0,
00260                        this->sa_) == -1
00261       || this->base_addr_ != 0
00262 #ifdef ACE_HAS_WINCE
00263       && this->mmap_.addr () == 0)  // WinCE does not allow users to specify alloc addr.
00264 #else
00265       && this->mmap_.addr () != this->base_addr_)
00266 #endif  // ACE_HAS_WINCE
00267     {
00268 #if 0
00269       ACE_ERROR ((LM_ERROR,
00270                   ACE_LIB_TEXT ("(%P|%t) addr = %u, base_addr = %u, map_size = %u, %p\n"),
00271                   this->mmap_.addr (),
00272                   this->base_addr_,
00273                   map_size,
00274                   this->backing_store_name_));
00275 #endif /* 0 */
00276       return -1;
00277     }
00278   else
00279     {
00280 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
00281       this->base_addr_ = this->mmap_.addr ();
00282       if(obase_addr && this->base_addr_ != obase_addr)
00283          ACE_BASED_POINTER_REPOSITORY::instance ()->unbind (obase_addr);
00284       ACE_BASED_POINTER_REPOSITORY::instance ()->bind (this->base_addr_,
00285                                                        map_size);
00286 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
00287       return 0;
00288     }
00289 }
00290 
00291 // Ask operating system for more shared memory, increasing the mapping
00292 // accordingly.  Note that this routine assumes that the appropriate
00293 // locks are held when it is called.
00294 
00295 void *
00296 ACE_MMAP_Memory_Pool::acquire (size_t nbytes,
00297                                size_t &rounded_bytes)
00298 {
00299   ACE_TRACE ("ACE_MMAP_Memory_Pool::acquire");
00300   rounded_bytes = this->round_up (nbytes);
00301 
00302   // ACE_DEBUG ((LM_DEBUG, "(%P|%t) acquiring more chunks, nbytes =
00303   // %d, rounded_bytes = %d\n", nbytes, rounded_bytes));
00304 
00305   ACE_LOFF_T map_size;
00306 
00307   if (this->commit_backing_store_name (rounded_bytes,
00308                                        map_size) == -1)
00309     return 0;
00310   else if (this->map_file (map_size) == -1)
00311     return 0;
00312 
00313   // ACE_DEBUG ((LM_DEBUG, "(%P|%t) acquired more chunks, nbytes = %d,
00314   // rounded_bytes = %d, map_size = %d\n", nbytes, rounded_bytes,
00315   // map_size));
00316 
00317   return (void *) ((char *) this->mmap_.addr () + (this->mmap_.size () - rounded_bytes));
00318 }
00319 
00320 // Ask system for initial chunk of shared memory.
00321 
00322 void *
00323 ACE_MMAP_Memory_Pool::init_acquire (size_t nbytes,
00324                                     size_t &rounded_bytes,
00325                                     int &first_time)
00326 {
00327   ACE_TRACE ("ACE_MMAP_Memory_Pool::init_acquire");
00328 
00329   first_time = 0;
00330 
00331   if (nbytes < static_cast <size_t> (this->minimum_bytes_))
00332     nbytes = static_cast <size_t> (this->minimum_bytes_);
00333 
00334   if (this->mmap_.open (this->backing_store_name_,
00335                         O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
00336                         this->file_mode_, this->sa_) != -1)
00337     {
00338       // First time in, so need to acquire memory.
00339       first_time = 1;
00340       return this->acquire (nbytes, rounded_bytes);
00341     }
00342   else if (errno == EEXIST)
00343     {
00344       errno = 0;
00345       // Reopen file *without* using O_EXCL...
00346       if (this->mmap_.map (this->backing_store_name_,
00347                            -1,
00348                            O_RDWR,
00349                            this->file_mode_,
00350                            PROT_RDWR,
00351                            this->flags_,
00352                            this->base_addr_,
00353                            0,
00354                            this->sa_) == -1)
00355         ACE_ERROR_RETURN ((LM_ERROR,
00356                            ACE_LIB_TEXT ("%p\n"),
00357                            ACE_LIB_TEXT ("MMAP_Memory_Pool::init_acquire, EEXIST")),
00358                           0);
00359 
00360 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
00361       // Update the mapped segment information
00362       ACE_BASED_POINTER_REPOSITORY::instance ()->bind (this->mmap_.addr(),
00363                                                        this->mmap_.size());
00364 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
00365 
00366       return this->mmap_.addr ();
00367     }
00368   else
00369     ACE_ERROR_RETURN ((LM_ERROR,
00370                        ACE_LIB_TEXT ("%p\n"),
00371                        ACE_LIB_TEXT ("MMAP_Memory_Pool::init_acquire")),
00372                       0);
00373 }
00374 
00375 #if defined (ACE_WIN32)
00376 int
00377 ACE_MMAP_Memory_Pool::seh_selector (void *ep)
00378 {
00379   DWORD const ecode = ((EXCEPTION_POINTERS *) ep)->ExceptionRecord->ExceptionCode;
00380 
00381   if (ecode == EXCEPTION_ACCESS_VIOLATION)
00382     {
00383       void * fault_addr = (void *)
00384         ((EXCEPTION_POINTERS *) ep)->ExceptionRecord->ExceptionInformation[1];
00385 
00386       if (this->remap (fault_addr) == 0)
00387         return 1;
00388     }
00389 
00390   return 0;
00391 }
00392 #endif /* ACE_WIN32 */
00393 
00394 int
00395 ACE_MMAP_Memory_Pool::remap (void *addr)
00396 {
00397   ACE_TRACE ("ACE_MMAP_Memory_Pool::remap");
00398   //  ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("Remapping with fault address at: %X\n"), addr));
00399   off_t const current_map_size = ACE_OS::filesize (this->mmap_.handle ());
00400   // ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END);
00401 
00402   if (!(addr < (void *) ((char *) this->mmap_.addr () + current_map_size)
00403         && addr >= this->mmap_.addr ()))
00404     return -1;
00405 
00406   // Extend the mapping to cover the size of the backing store.
00407   return this->map_file (current_map_size);
00408 }
00409 
00410 ACE_MMAP_Memory_Pool_Options::ACE_MMAP_Memory_Pool_Options (const void *base_addr,
00411                                                             int use_fixed_addr,
00412                                                             int write_each_page,
00413                                                             ACE_LOFF_T minimum_bytes,
00414                                                             u_int flags,
00415                                                             int guess_on_fault,
00416                                                             LPSECURITY_ATTRIBUTES sa,
00417                                                             mode_t file_mode,
00418                                                             bool unique)
00419   : base_addr_ (base_addr),
00420     use_fixed_addr_ (use_fixed_addr),
00421     write_each_page_ (write_each_page),
00422     minimum_bytes_ (minimum_bytes),
00423     flags_ (flags),
00424     guess_on_fault_ (guess_on_fault),
00425     sa_ (sa),
00426     file_mode_ (file_mode),
00427     unique_ (unique)
00428 {
00429   ACE_TRACE ("ACE_MMAP_Memory_Pool_Options::ACE_MMAP_Memory_Pool_Options");
00430   // for backwards compatability
00431   if (base_addr_ == 0 && use_fixed_addr_ == ALWAYS_FIXED)
00432     use_fixed_addr_ = FIRSTCALL_FIXED;
00433 }
00434 
00435 // Handle SIGSEGV and SIGBUS signals to remap memory properly.  When a
00436 // process reads or writes to non-mapped memory a signal (SIGBUS or
00437 // SIGSEGV) will be triggered.  At that point, the ACE_Sig_Handler
00438 // (which is part of the ACE_Reactor) will catch the signal and
00439 // dispatch the handle_signal() method defined here.  If the SIGSEGV
00440 // signal occurred due to the fact that the mapping wasn't uptodate
00441 // with respect to the backing store, the handler method below will
00442 // update the mapping accordingly.  When the signal handler returns,
00443 // the instruction should be restarted and the operation should work.
00444 
00445 int
00446 ACE_MMAP_Memory_Pool::handle_signal (int signum, siginfo_t *siginfo, ucontext_t *)
00447 {
00448   if (signum != SIGSEGV)
00449     return -1;
00450   else
00451     ; // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) received %S\n"), signum));
00452 
00453   // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) new mapping address = %u\n"), (char *) this->base_addr_ + current_map_size));
00454 
00455 #if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)
00456   // Make sure that the pointer causing the problem is within the
00457   // range of the backing store.
00458 
00459   if (siginfo != 0)
00460     {
00461       // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) si_signo = %d, si_code = %d, addr = %u\n"), siginfo->si_signo, siginfo->si_code, siginfo->si_addr));
00462       if (this->remap ((void *) siginfo->si_addr) == -1)
00463         return -1;
00464       // ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) address %u out of range\n",
00465       // siginfo->si_addr), -1);
00466       return 0;
00467     }
00468 #else
00469   ACE_UNUSED_ARG(siginfo);
00470 #endif /* ACE_HAS_SIGINFO_T && !defined ACE_LACKS_SI_ADDR */
00471   // If guess_on_fault_ is true, then we want to try to remap without
00472   // knowing the faulting address.  guess_on_fault_ can only be true
00473   // on platforms that do not provide the faulting address through
00474   // signals or exceptions.  We check to see if the mapping is up to
00475   // date. If it is, then this fault isn't due to this mapping and we
00476   // pass it on.
00477   if (guess_on_fault_)
00478     {
00479       // Check if the current mapping is up to date.
00480       ACE_LOFF_T const current_map_size = ACE_OS::filesize (this->mmap_.handle ());
00481 
00482       if (static_cast<size_t> (current_map_size) == this->mmap_.size ())
00483         {
00484           // The mapping is up to date so this really is a bad
00485           // address.  Thus, remove current signal handler so process
00486           // will fail with default action and core file will be
00487           // written.
00488           this->signal_handler_.remove_handler (SIGSEGV);
00489           return 0;
00490         }
00491 
00492       // Extend the mapping to cover the size of the backing store.
00493       return this->map_file (current_map_size);
00494     }
00495   else
00496     return -1;
00497 }
00498 
00499 void *
00500 ACE_MMAP_Memory_Pool::base_addr (void) const
00501 {
00502   ACE_TRACE ("ACE_MMAP_Memory_Pool::base_addr");
00503   return this->base_addr_;
00504 }
00505 
00506 size_t
00507 ACE_MMAP_Memory_Pool::round_up (size_t nbytes)
00508 {
00509   ACE_TRACE ("ACE_MMAP_Memory_Pool::round_up");
00510   return ACE::round_to_pagesize (static_cast<off_t> (nbytes));
00511 }
00512 
00513 ACE_ALLOC_HOOK_DEFINE(ACE_Lite_MMAP_Memory_Pool)
00514 
00515 ACE_Lite_MMAP_Memory_Pool::ACE_Lite_MMAP_Memory_Pool (const ACE_TCHAR *backing_store_name,
00516                                                       const OPTIONS *options)
00517   : ACE_MMAP_Memory_Pool (backing_store_name, options)
00518 {
00519   ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::ACE_Lite_MMAP_Memory_Pool");
00520 }
00521 
00522 ACE_Lite_MMAP_Memory_Pool::~ACE_Lite_MMAP_Memory_Pool (void)
00523 {
00524 }
00525 
00526 int
00527 ACE_Lite_MMAP_Memory_Pool::sync (ssize_t, int)
00528 {
00529   ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync");
00530   return 0;
00531 }
00532 
00533 int
00534 ACE_Lite_MMAP_Memory_Pool::sync (void *, size_t, int)
00535 {
00536   ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync");
00537   return 0;
00538 }
00539 
00540 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:41:56 2006 for ACE by doxygen 1.3.6