1 // MMAP_Memory_Pool.cpp
2 #include "ace/MMAP_Memory_Pool.h"
3 #include "ace/OS_NS_sys_mman.h"
4 #include "ace/OS_NS_unistd.h"
5 #include "ace/OS_NS_string.h"
6 #include "ace/OS_NS_sys_stat.h"
7 #include "ace/Log_Category.h"
8 #include "ace/Truncate.h"
9 #include "ace/Lib_Find.h"
11 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
12 #include "ace/Based_Pointer_T.h"
13 #include "ace/Based_Pointer_Repository.h"
14 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
16 #if !defined (__ACE_INLINE__)
17 #include "ace/MMAP_Memory_Pool.inl"
18 #endif /* __ACE_INLINE__ */
20 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
22 ACE_ALLOC_HOOK_DEFINE(ACE_MMAP_Memory_Pool
)
25 ACE_MMAP_Memory_Pool::dump () const
27 #if defined (ACE_HAS_DUMP)
28 ACE_TRACE ("ACE_MMAP_Memory_Pool::dump");
29 #endif /* ACE_HAS_DUMP */
33 ACE_MMAP_Memory_Pool::release (int destroy
)
35 ACE_TRACE ("ACE_MMAP_Memory_Pool::release");
37 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
38 ACE_BASED_POINTER_REPOSITORY::instance ()->unbind (this->mmap_
.addr ());
39 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
42 this->mmap_
.remove ();
49 ACE_MMAP_Memory_Pool::sync (size_t len
, int flags
)
51 ACE_TRACE ("ACE_MMAP_Memory_Pool::sync");
53 return this->mmap_
.sync (len
, flags
);
57 ACE_MMAP_Memory_Pool::sync (int flags
)
59 ACE_TRACE ("ACE_MMAP_Memory_Pool::sync");
61 size_t const len
= ACE_Utils::truncate_cast
<size_t> (
62 ACE_OS::lseek (this->mmap_
.handle (), 0, SEEK_END
));
64 return this->mmap_
.sync (len
, flags
);
67 /// Sync @a len bytes of the memory region to the backing store starting
70 ACE_MMAP_Memory_Pool::sync (void *addr
, size_t len
, int flags
)
72 ACE_TRACE ("ACE_MMAP_Memory_Pool::sync");
73 return ACE_OS::msync (addr
, len
, flags
);
76 // Change the protection of the pages of the mapped region to <prot>
77 // starting at <this->base_addr_> up to <len> bytes.
78 // Change protection of all pages in the mapped region.
81 ACE_MMAP_Memory_Pool::protect (size_t len
, int prot
)
83 ACE_TRACE ("ACE_MMAP_Memory_Pool::protect");
85 return this->mmap_
.protect (len
, prot
);
89 ACE_MMAP_Memory_Pool::protect (int prot
)
91 ACE_TRACE ("ACE_MMAP_Memory_Pool::protect");
93 size_t const len
= ACE_Utils::truncate_cast
<size_t> (
94 ACE_OS::lseek (this->mmap_
.handle (), 0, SEEK_END
));
96 return this->mmap_
.protect (len
, prot
);
100 // Change the protection of the pages of the mapped region to <prot>
101 // starting at <addr> up to <len> bytes.
104 ACE_MMAP_Memory_Pool::protect (void *addr
, size_t len
, int prot
)
106 ACE_TRACE ("ACE_MMAP_Memory_Pool::protect");
107 return ACE_OS::mprotect (addr
, len
, prot
);
110 ACE_MMAP_Memory_Pool::ACE_MMAP_Memory_Pool (
111 const ACE_TCHAR
*backing_store_name
,
112 const OPTIONS
*options
)
116 write_each_page_ (false),
119 file_mode_ (ACE_DEFAULT_FILE_PERMS
),
120 install_signal_handler_ (true)
122 ACE_TRACE ("ACE_MMAP_Memory_Pool::ACE_MMAP_Memory_Pool");
124 #if (defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)) || defined (ACE_WIN32)
125 // For plaforms that give the faulting address.
126 guess_on_fault_
= false;
128 // For plaforms that do NOT give the faulting address, let the
129 // options decide whether to guess or not.
131 guess_on_fault_
= options
->guess_on_fault_
;
133 // If no options are specified, default to true.
134 guess_on_fault_
= true;
135 #endif /* (defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)) || defined (ACE_WIN32) */
137 // Only change the defaults if <options> != 0.
140 if (options
->flags_
!= 0)
141 this->flags_
= options
->flags_
;
142 use_fixed_addr_
= options
->use_fixed_addr_
;
144 if (use_fixed_addr_
== ACE_MMAP_Memory_Pool_Options::ALWAYS_FIXED
)
146 this->base_addr_
= const_cast<void *> (options
->base_addr_
);
147 ACE_SET_BITS (flags_
, MAP_FIXED
);
149 this->write_each_page_
= options
->write_each_page_
;
150 this->minimum_bytes_
= options
->minimum_bytes_
;
151 if (options
->sa_
!= 0)
152 this->sa_
= options
->sa_
;
153 this->file_mode_
= options
->file_mode_
;
154 this->install_signal_handler_
= options
->install_signal_handler_
;
157 if (backing_store_name
== 0)
159 // Only create a new unique filename for the backing store file
160 // if the user didn't supply one...
161 #if defined (ACE_DEFAULT_BACKING_STORE)
162 // Create a temporary file.
163 ACE_OS::strcpy (this->backing_store_name_
,
164 ACE_DEFAULT_BACKING_STORE
);
165 #else /* ACE_DEFAULT_BACKING_STORE */
166 if (ACE::get_temp_dir (this->backing_store_name_
,
167 MAXPATHLEN
- 17) == -1)
168 // -17 for ace-malloc-XXXXXX
170 ACELIB_ERROR ((LM_ERROR
,
171 ACE_TEXT ("Temporary path too long, ")
172 ACE_TEXT ("defaulting to current directory\n")));
173 this->backing_store_name_
[0] = 0;
176 // Add the filename to the end
177 ACE_OS::strcat (this->backing_store_name_
,
178 ACE_TEXT ("ace-malloc-XXXXXX"));
180 // If requested an unique filename, use mktemp to get a random file.
181 if (options
&& options
->unique_
)
182 # if defined (ACE_DISABLE_MKTEMP)
184 ACELIB_ERROR ((LM_ERROR
,
185 ACE_TEXT ("mktemp disabled; ")
186 ACE_TEXT ("can't generate unique name")));
187 this->backing_store_name_
[0] = 0;
190 ACE_OS::mktemp(this->backing_store_name_
);
191 # endif /* ACE_DISABLE_MKTEMP */
192 #endif /* ACE_DEFAULT_BACKING_STORE */
195 ACE_OS::strsncpy (this->backing_store_name_
,
197 (sizeof this->backing_store_name_
/ sizeof (ACE_TCHAR
)));
199 #if !defined (ACE_WIN32)
200 if (this->install_signal_handler_
)
202 if (this->signal_handler_
.register_handler (SIGSEGV
, this) == -1)
203 ACELIB_ERROR ((LM_ERROR
,
204 ACE_TEXT("%p\n"), this->backing_store_name_
));
206 #endif /* ACE_WIN32 */
209 ACE_MMAP_Memory_Pool::~ACE_MMAP_Memory_Pool ()
213 // Compute the new map_size of the backing store and commit the
216 ACE_MMAP_Memory_Pool::commit_backing_store_name (size_t rounded_bytes
,
219 ACE_TRACE ("ACE_MMAP_Memory_Pool::commit_backing_store_name");
221 #if defined (__Lynx__)
222 map_size
= rounded_bytes
;
226 if (this->write_each_page_
)
227 // Write to the end of every block to ensure that we have enough
228 // space in the backing store.
229 seek_len
= this->round_up (1); // round_up(1) is one page.
231 // We're willing to risk it all in the name of efficiency...
232 seek_len
= rounded_bytes
;
234 // The following loop will execute multiple times (if
235 // this->write_each_page == 1) or just once (if
236 // this->write_each_page == 0).
238 for (size_t cur_block
= 0;
239 cur_block
< rounded_bytes
;
240 cur_block
+= seek_len
)
243 ACE_Utils::truncate_cast
<size_t> (
244 ACE_OS::lseek (this->mmap_
.handle (),
245 static_cast<ACE_OFF_T
> (seek_len
- 1),
248 if (map_size
== static_cast<size_t> (-1)
249 || ACE_OS::write (this->mmap_
.handle (),
252 ACELIB_ERROR_RETURN ((LM_ERROR
,
253 ACE_TEXT ("(%P|%t) %p\n"),
254 this->backing_store_name_
),
258 // Increment by one to put us at the beginning of the next chunk...
260 #endif /* __Lynx__ */
264 // Memory map the file up to <map_size> bytes.
267 ACE_MMAP_Memory_Pool::map_file (size_t map_size
)
269 ACE_TRACE ("ACE_MMAP_Memory_Pool::map_file");
270 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
271 void* obase_addr
= this->base_addr_
;
272 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
274 // Unmap the existing mapping.
275 this->mmap_
.unmap ();
277 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
278 if (use_fixed_addr_
== ACE_MMAP_Memory_Pool_Options::NEVER_FIXED
)
279 this->base_addr_
= 0;
280 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
282 // Remap the file; try to stay at the same location as a previous mapping
283 // but do not force it with MAP_FIXED. Doing so will give the OS permission
284 // to map locations currently holding other things (such as the heap, or
285 // the C library) into the map file, producing very unexpected results.
286 if (this->mmap_
.map (map_size
,
292 || (this->base_addr_
!= 0
293 && this->mmap_
.addr () != this->base_addr_
))
296 ACELIB_ERROR ((LM_ERROR
,
297 ACE_TEXT ("(%P|%t) addr = %@, base_addr = %@, map_size = %B, %p\n"),
301 this->backing_store_name_
));
307 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
308 this->base_addr_
= this->mmap_
.addr ();
310 if (obase_addr
&& this->base_addr_
!= obase_addr
)
312 ACE_BASED_POINTER_REPOSITORY::instance ()->unbind (obase_addr
);
315 ACE_BASED_POINTER_REPOSITORY::instance ()->bind (this->base_addr_
,
317 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
322 // Ask operating system for more shared memory, increasing the mapping
323 // accordingly. Note that this routine assumes that the appropriate
324 // locks are held when it is called.
326 ACE_MMAP_Memory_Pool::acquire (size_t nbytes
,
327 size_t &rounded_bytes
)
329 ACE_TRACE ("ACE_MMAP_Memory_Pool::acquire");
330 rounded_bytes
= this->round_up (nbytes
);
332 // ACELIB_DEBUG ((LM_DEBUG, "(%P|%t) acquiring more chunks, nbytes =
333 // %B, rounded_bytes = %B\n", nbytes, rounded_bytes));
337 if (this->commit_backing_store_name (rounded_bytes
,
340 else if (this->map_file (map_size
) == -1)
343 // ACELIB_DEBUG ((LM_DEBUG, "(%P|%t) acquired more chunks, nbytes = %B,
344 // rounded_bytes = %B, map_size = %B\n", nbytes, rounded_bytes,
347 return (void *) ((char *) this->mmap_
.addr () + (this->mmap_
.size () - rounded_bytes
));
350 // Ask system for initial chunk of shared memory.
353 ACE_MMAP_Memory_Pool::init_acquire (size_t nbytes
,
354 size_t &rounded_bytes
,
357 ACE_TRACE ("ACE_MMAP_Memory_Pool::init_acquire");
361 if (nbytes
< static_cast <size_t> (this->minimum_bytes_
))
362 nbytes
= static_cast <size_t> (this->minimum_bytes_
);
364 if (this->mmap_
.open (this->backing_store_name_
,
365 O_RDWR
| O_CREAT
| O_TRUNC
| O_EXCL
,
366 this->file_mode_
, this->sa_
) != -1)
368 // First time in, so need to acquire memory.
371 void *result
= this->acquire (nbytes
, rounded_bytes
);
372 // After the first time, reset the flag so that subsequent calls
373 // will use MAP_FIXED
374 if (this->use_fixed_addr_
== ACE_MMAP_Memory_Pool_Options::FIRSTCALL_FIXED
)
376 ACE_SET_BITS (flags_
, MAP_FIXED
);
380 else if (errno
== EEXIST
)
383 // Reopen file *without* using O_EXCL...
384 if (this->mmap_
.map (this->backing_store_name_
,
385 static_cast<size_t> (-1),
393 ACELIB_ERROR_RETURN ((LM_ERROR
,
395 ACE_TEXT ("MMAP_Memory_Pool::init_acquire, EEXIST")),
397 // After the first time, reset the flag so that subsequent calls
398 // will use MAP_FIXED
399 if (use_fixed_addr_
== ACE_MMAP_Memory_Pool_Options::FIRSTCALL_FIXED
)
401 ACE_SET_BITS (flags_
, MAP_FIXED
);
403 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
404 // Update the mapped segment information
405 ACE_BASED_POINTER_REPOSITORY::instance ()->bind (this->mmap_
.addr(),
407 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
409 return this->mmap_
.addr ();
412 ACELIB_ERROR_RETURN ((LM_ERROR
,
414 ACE_TEXT ("MMAP_Memory_Pool::init_acquire")),
418 #if defined (ACE_WIN32)
420 ACE_MMAP_Memory_Pool::seh_selector (void *ep
)
422 DWORD
const ecode
= ((EXCEPTION_POINTERS
*) ep
)->ExceptionRecord
->ExceptionCode
;
424 if (ecode
== EXCEPTION_ACCESS_VIOLATION
)
426 void * fault_addr
= (void *)
427 ((EXCEPTION_POINTERS
*) ep
)->ExceptionRecord
->ExceptionInformation
[1];
429 if (this->remap (fault_addr
) == 0)
435 #endif /* ACE_WIN32 */
438 ACE_MMAP_Memory_Pool::remap (void *addr
)
440 ACE_TRACE ("ACE_MMAP_Memory_Pool::remap");
441 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("Remapping with fault address at: %@\n"), addr));
442 size_t const current_map_size
=
443 ACE_Utils::truncate_cast
<size_t> (ACE_OS::filesize (this->mmap_
.handle ()));
444 // ACE_OS::lseek (this->mmap_.handle (), 0, SEEK_END);
446 if (!(addr
< (void *) ((char *) this->mmap_
.addr () + current_map_size
)
447 && addr
>= this->mmap_
.addr ()))
450 // Extend the mapping to cover the size of the backing store.
451 return this->map_file (current_map_size
);
454 ACE_MMAP_Memory_Pool_Options::ACE_MMAP_Memory_Pool_Options (
455 const void *base_addr
,
457 bool write_each_page
,
458 size_t minimum_bytes
,
461 LPSECURITY_ATTRIBUTES sa
,
464 bool install_signal_handler
)
465 : base_addr_ (base_addr
),
466 use_fixed_addr_ (use_fixed_addr
),
467 write_each_page_ (write_each_page
),
468 minimum_bytes_ (minimum_bytes
),
470 guess_on_fault_ (guess_on_fault
),
472 file_mode_ (file_mode
),
474 install_signal_handler_ (install_signal_handler
)
476 ACE_TRACE ("ACE_MMAP_Memory_Pool_Options::ACE_MMAP_Memory_Pool_Options");
477 // for backwards compatibility
478 if (base_addr_
== 0 && use_fixed_addr_
== ALWAYS_FIXED
)
479 use_fixed_addr_
= FIRSTCALL_FIXED
;
482 #if !defined (ACE_WIN32)
484 ACE_MMAP_Memory_Pool::handle_signal (int signum
, siginfo_t
*siginfo
, ucontext_t
*)
486 if (signum
!= SIGSEGV
)
490 ACELIB_DEBUG ((LM_DEBUG
, ACE_TEXT ("(%P|%t) received %S\n"), signum
));
492 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) new mapping address = %@\n"), (char *) this->base_addr_ + current_map_size));
494 #if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR)
495 // Make sure that the pointer causing the problem is within the
496 // range of the backing store.
500 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) si_signo = %d, si_code = %d, addr = %@\n"), siginfo->si_signo, siginfo->si_code, siginfo->si_addr));
501 if (this->remap ((void *) siginfo
->si_addr
) == -1)
503 // ACELIB_ERROR_RETURN ((LM_ERROR, "(%P|%t) address %@ out of range\n",
504 // siginfo->si_addr), -1);
508 ACE_UNUSED_ARG(siginfo
);
509 #endif /* ACE_HAS_SIGINFO_T && !defined ACE_LACKS_SI_ADDR */
510 // If guess_on_fault_ is true, then we want to try to remap without
511 // knowing the faulting address. guess_on_fault_ can only be true
512 // on platforms that do not provide the faulting address through
513 // signals or exceptions. We check to see if the mapping is up to
514 // date. If it is, then this fault isn't due to this mapping and we
518 // Check if the current mapping is up to date.
519 size_t const current_map_size
=
520 ACE_Utils::truncate_cast
<size_t> (ACE_OS::filesize (this->mmap_
.handle ()));
522 if (static_cast<size_t> (current_map_size
) == this->mmap_
.size ())
524 // The mapping is up to date so this really is a bad
525 // address. Thus, remove current signal handler so process
526 // will fail with default action and core file will be
528 this->signal_handler_
.remove_handler (SIGSEGV
);
532 // Extend the mapping to cover the size of the backing store.
533 return this->map_file (current_map_size
);
541 ACE_MMAP_Memory_Pool::base_addr () const
543 ACE_TRACE ("ACE_MMAP_Memory_Pool::base_addr");
544 return this->base_addr_
;
548 ACE_MMAP_Memory_Pool::round_up (size_t nbytes
)
550 ACE_TRACE ("ACE_MMAP_Memory_Pool::round_up");
551 return ACE::round_to_pagesize (nbytes
);
554 ACE_ALLOC_HOOK_DEFINE(ACE_Lite_MMAP_Memory_Pool
)
556 ACE_Lite_MMAP_Memory_Pool::ACE_Lite_MMAP_Memory_Pool (const ACE_TCHAR
*backing_store_name
,
557 const OPTIONS
*options
)
558 : ACE_MMAP_Memory_Pool (backing_store_name
, options
)
560 ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::ACE_Lite_MMAP_Memory_Pool");
563 ACE_Lite_MMAP_Memory_Pool::~ACE_Lite_MMAP_Memory_Pool ()
568 ACE_Lite_MMAP_Memory_Pool::sync (size_t, int)
570 ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync");
575 ACE_Lite_MMAP_Memory_Pool::sync (int)
577 ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync");
582 ACE_Lite_MMAP_Memory_Pool::sync (void *, size_t, int)
584 ACE_TRACE ("ACE_Lite_MMAP_Memory_Pool::sync");
588 ACE_END_VERSIONED_NAMESPACE_DECL