1 #include "ace/Shared_Memory_Pool.h"
2 #include "ace/OS_NS_sys_shm.h"
3 #include "ace/Log_Category.h"
5 #if !defined (ACE_LACKS_SYSV_SHMEM)
7 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
9 ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_Pool
)
11 ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options (
12 const char *base_addr
,
15 ACE_OFF_T minimum_bytes
,
17 : base_addr_ (base_addr
),
18 max_segments_ (max_segments
),
19 minimum_bytes_ (minimum_bytes
),
20 file_perms_ (file_perms
),
21 segment_size_ (segment_size
)
23 ACE_TRACE ("ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options");
27 ACE_Shared_Memory_Pool::dump () const
29 #if defined (ACE_HAS_DUMP)
30 ACE_TRACE ("ACE_Shared_Memory_Pool::dump");
31 #endif /* ACE_HAS_DUMP */
35 ACE_Shared_Memory_Pool::in_use (ACE_OFF_T
&offset
,
38 #ifndef ACE_HAS_SYSV_IPC
39 ACE_UNUSED_ARG (offset
);
40 ACE_UNUSED_ARG (counter
);
41 ACE_NOTSUP_RETURN (-1);
44 SHM_TABLE
*st
= reinterpret_cast<SHM_TABLE
*> (this->shm_addr_table_
[0]);
47 for (counter
= 0; counter
< this->max_segments_
&& st
[counter
].used_
== 1; counter
++)
49 if (ACE_OS::shmctl (st
[counter
].shmid_
, IPC_STAT
, &buf
) == -1)
50 ACELIB_ERROR_RETURN ((LM_ERROR
,
51 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::in_use, %p\n"),
54 offset
+= buf
.shm_segsz
;
55 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::in_use, segment size = %d, offset = %d\n"), buf.shm_segsz, offset));
62 ACE_Shared_Memory_Pool::find_seg (const void* const searchPtr
,
66 #ifndef ACE_HAS_SYSV_IPC
67 ACE_UNUSED_ARG (searchPtr
);
68 ACE_UNUSED_ARG (offset
);
69 ACE_UNUSED_ARG (counter
);
70 ACE_NOTSUP_RETURN (-1);
73 SHM_TABLE
*st
= reinterpret_cast<SHM_TABLE
*> (this->shm_addr_table_
[0]);
76 for (counter
= 0; counter
< this->max_segments_
&& st
[counter
].used_
== 1; counter
++)
78 if (ACE_OS::shmctl (st
[counter
].shmid_
, IPC_STAT
, &buf
) == -1)
79 ACELIB_ERROR_RETURN ((LM_ERROR
,
80 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::find_seg, %p\n"),
83 offset
+= buf
.shm_segsz
;
85 // If segment 'counter' starts at a location greater than the
86 // place we are searching for. We then decrement the offset to
87 // the start of counter-1. (flabar@vais.net)
88 if (((ptrdiff_t) offset
+ (ptrdiff_t) (this->shm_addr_table_
[0])) > (ptrdiff_t) searchPtr
)
91 offset
-= buf
.shm_segsz
;
94 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::find_seg, segment size = %d, offset = %d\n"), buf.shm_segsz, offset));
102 ACE_Shared_Memory_Pool::commit_backing_store_name (size_t rounded_bytes
,
105 ACE_TRACE ("ACE_Shared_Memory_Pool::commit_backing_store_name");
107 if (this->shm_addr_table_
[0] == nullptr)
109 ACELIB_ERROR_RETURN ((LM_ERROR
,
110 "ACE_Shared_Memory_Pool::commit_backing_store_name, base address is zero\n"),
115 SHM_TABLE
*st
= reinterpret_cast<SHM_TABLE
*> (this->shm_addr_table_
[0]);
117 if (this->in_use (offset
, counter
) == -1)
120 if (counter
== this->max_segments_
)
122 ACELIB_ERROR_RETURN ((LM_ERROR
,
123 "ACE_Shared_Memory_Pool::commit_backing_store_name, exceeded max number of segments = %d, base = %u, offset = %u\n",
125 this->shm_addr_table_
[0],
126 static_cast<unsigned int>(offset
)),
131 int const shmid
= ACE_OS::shmget (st
[counter
].key_
,
133 this->file_perms_
| IPC_CREAT
| IPC_EXCL
);
135 ACELIB_ERROR_RETURN ((LM_ERROR
,
136 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::commit_backing_store_name, %p\n"),
137 ACE_TEXT ("shmget")),
139 st
[counter
].shmid_
= shmid
;
140 st
[counter
].used_
= 1;
142 void *address
= (void *) (((char *) this->shm_addr_table_
[0]) + offset
);
143 void *shmem
= ACE_OS::shmat (st
[counter
].shmid_
, (char *) address
, 0);
145 if (shmem
!= address
)
146 ACELIB_ERROR_RETURN ((LM_ERROR
,
147 ACE_TEXT("(%P|%t) ACE_Shared_Memory_Pool::commit_backing_store_name, %p, shmem = %u, address = %u\n"),
153 shm_addr_table_
[counter
] = shmem
;
158 /// Handle SIGSEGV and SIGBUS signals to remap shared memory properly.
160 ACE_Shared_Memory_Pool::handle_signal (int, siginfo_t
*siginfo
, ucontext_t
*)
162 ACE_TRACE ("ACE_Shared_Memory_Pool::handle_signal");
164 // While FreeBSD 5.X has a siginfo_t struct with a si_addr field,
165 // it does not define SEGV_MAPERR.
166 #if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR) && \
167 (defined (SEGV_MAPERR) || defined (SEGV_MEMERR))
171 // Make sure that the pointer causing the problem is within the
172 // range of the backing store.
173 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::handle_signal, si_signo = %d, si_code = %d, addr = %u\n"), siginfo->si_signo, siginfo->si_code, siginfo->si_addr));
176 if (this->in_use (offset
, counter
) == -1)
178 ACELIB_ERROR ((LM_ERROR
,
179 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::handle_signal, %p\n"),
180 ACE_TEXT ("in_use")));
182 else if (!(siginfo
->si_code
== SEGV_MAPERR
183 && siginfo
->si_addr
< (((char *) this->shm_addr_table_
[0]) + offset
)
184 && siginfo
->si_addr
>= ((char *) this->shm_addr_table_
[0])))
186 ACELIB_ERROR_RETURN ((LM_ERROR
,
187 "(%P|%t) ACE_Shared_Memory_Pool::handle_signal, address %u out of range, base = %u, offset = %u\n",
189 this->shm_addr_table_
[0],
190 static_cast<unsigned int>(offset
)),
194 // The above if case will check to see that the address is in the
195 // proper range. Therefore there is a segment out there that the
196 // pointer wants to point into. Find the segment that someone else
197 // has used and attach to it (flabar@vais.net)
198 counter
= 0; // ret value to get shmid from the st table.
199 if (this->find_seg (siginfo
->si_addr
, offset
, counter
) == -1)
200 ACELIB_ERROR_RETURN ((LM_ERROR
,
201 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::handle_signal, %p\n"),
202 ACE_TEXT ("in_use")),
205 void *address
= (void *) (((char *) this->shm_addr_table_
[0]) + offset
);
206 SHM_TABLE
*st
= reinterpret_cast<SHM_TABLE
*> (this->shm_addr_table_
[0]);
208 void *shmem
= ACE_OS::shmat (st
[counter
].shmid_
, (char *) address
, 0);
210 if (shmem
!= address
)
211 ACELIB_ERROR_RETURN ((LM_ERROR
,
212 ACE_TEXT("(%P|%t) ACE_Shared_Memory_Pool::handle_signal, %p, shmem = %u, address = %u\n"),
218 // NOTE: this won't work if we dont have SIGINFO_T or SI_ADDR
220 ACE_UNUSED_ARG (siginfo
);
221 #endif /* ACE_HAS_SIGINFO_T && !defined (ACE_LACKS_SI_ADDR) */
226 ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool (
227 const ACE_TCHAR
*backing_store_name
,
228 const OPTIONS
*options
)
229 : file_perms_ (options
? options
->file_perms_
: ACE_DEFAULT_FILE_PERMS
),
230 max_segments_ (options
? options
->max_segments_
: ACE_DEFAULT_MAX_SEGMENTS
),
231 minimum_bytes_ (options
? options
->minimum_bytes_
: 0),
232 segment_size_ (options
? options
->segment_size_
: ACE_DEFAULT_SEGMENT_SIZE
),
233 shm_addr_table_ (std::make_unique
<void *[]> (this->max_segments_
))
235 ACE_TRACE ("ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool");
237 // Only change the defaults if options != nullptr.
240 this->shm_addr_table_
[0] = reinterpret_cast<void *> (const_cast<char *> (options
->base_addr_
));
243 #ifndef ACE_HAS_SYSV_IPC
244 ACE_UNUSED_ARG (backing_store_name
);
246 if (backing_store_name
)
248 // Convert the string into a number that is used as the segment
251 #if !defined (ACE_LACKS_SSCANF)
252 int const result
= ::sscanf (ACE_TEXT_ALWAYS_CHAR (backing_store_name
),
256 int const result
= 0;
257 #endif /* ACE_LACKS_SSCANF */
258 if (result
== 0 || result
== EOF
)
260 // The conversion to a number failed so hash with crc32
261 // ACE::crc32 is also used in <SV_Semaphore_Simple>.
262 this->base_shm_key_
= (key_t
) ACE::crc32 (ACE_TEXT_ALWAYS_CHAR (backing_store_name
));
266 this->base_shm_key_
= segment_key
;
269 if (this->base_shm_key_
== IPC_PRIVATE
)
271 // Make sure that the segment can be shared between unrelated
273 this->base_shm_key_
= ACE_DEFAULT_SHM_KEY
;
277 this->base_shm_key_
= ACE_DEFAULT_SHM_KEY
;
278 #endif // ACE_HAS_SYSV_IPC
280 if (this->signal_handler_
.register_handler (SIGSEGV
, this) == -1)
282 ACELIB_ERROR ((LM_ERROR
,
283 ACE_TEXT ("ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool, %p\n"),
284 ACE_TEXT ("ACE_Sig_Handler::register_handler")));
288 /// Ask system for more shared memory.
290 ACE_Shared_Memory_Pool::acquire (size_t nbytes
, size_t &rounded_bytes
)
292 ACE_TRACE ("ACE_Shared_Memory_Pool::acquire");
294 rounded_bytes
= this->round_up (nbytes
);
296 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::acquire, acquiring more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes));
300 if (this->commit_backing_store_name (rounded_bytes
, offset
) == -1)
303 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::acquire, acquired more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes));
304 return ((char *) this->shm_addr_table_
[0]) + offset
;
307 /// Ask system for initial chunk of shared memory.
309 ACE_Shared_Memory_Pool::init_acquire (size_t nbytes
,
310 size_t &rounded_bytes
,
313 ACE_TRACE ("ACE_Shared_Memory_Pool::init_acquire");
315 ACE_OFF_T
const shm_table_offset
= ACE::round_to_pagesize (sizeof (SHM_TABLE
));
316 rounded_bytes
= this->round_up (nbytes
> (size_t) this->minimum_bytes_
318 : (size_t) this->minimum_bytes_
);
320 // Acquire the semaphore to serialize initialization and prevent
322 int shmid
= ACE_OS::shmget (this->base_shm_key_
,
323 rounded_bytes
+ shm_table_offset
,
324 this->file_perms_
| IPC_CREAT
| IPC_EXCL
);
328 ACELIB_ERROR_RETURN ((LM_ERROR
,
329 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::init_acquire, %p\n"),
330 ACE_TEXT ("shmget")),
334 shmid
= ACE_OS::shmget (this->base_shm_key_
, 0, 0);
337 ACELIB_ERROR_RETURN ((LM_ERROR
,
338 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::init_acquire, %p\n"),
339 ACE_TEXT ("shmget")),
342 // This implementation doesn't care if we don't get the key we want...
343 this->shm_addr_table_
[0] = ACE_OS::shmat (shmid
, reinterpret_cast<char *> (this->shm_addr_table_
[0]), 0);
345 if (this->shm_addr_table_
[0] == reinterpret_cast<void *> (-1))
347 ACELIB_ERROR_RETURN ((LM_ERROR
,
348 ACE_TEXT("(%P|%t) ACE_Shared_Memory_Pool::init_acquire, %p, base_addr = %u\n"),
350 this->shm_addr_table_
[0]),
358 // This implementation doesn't care if we don't get the key we want...
359 this->shm_addr_table_
[0] = ACE_OS::shmat (shmid
, reinterpret_cast<char *> (this->shm_addr_table_
[0]), 0);
361 if (this->shm_addr_table_
[0] == reinterpret_cast<char *> (-1))
363 ACELIB_ERROR_RETURN ((LM_ERROR
,
364 ACE_TEXT("(%P|%t) ACE_Shared_Memory_Pool::init_acquire, %p, base_addr = %u\n"),
366 this->shm_addr_table_
[0]), 0);
369 SHM_TABLE
*st
= reinterpret_cast<SHM_TABLE
*> (this->shm_addr_table_
[0]);
370 st
[0].key_
= this->base_shm_key_
;
371 st
[0].shmid_
= shmid
;
374 for (size_t counter
= 1; // Skip over the first entry...
375 counter
< this->max_segments_
;
378 #ifdef ACE_HAS_SYSV_IPC
379 st
[counter
].key_
= this->base_shm_key_
+ counter
;
381 st
[counter
].shmid_
= 0;
382 st
[counter
].used_
= 0;
383 shm_addr_table_
[counter
] = nullptr;
387 return (void *) (((char *) this->shm_addr_table_
[0]) + shm_table_offset
);
390 /// Instruct the memory pool to release all of its resources.
392 ACE_Shared_Memory_Pool::release (int destroy
)
394 ACE_TRACE ("ACE_Shared_Memory_Pool::release");
398 // At the moment we have attached any segments we have to release/destroy these
399 if (this->shm_addr_table_
[0])
401 // The shared memory table is store in segment[0]
402 SHM_TABLE
*st
= reinterpret_cast<SHM_TABLE
*> (this->shm_addr_table_
[0]);
404 // Detach the mapped shared memory segments in reverse order.
405 // We store the shared memory table in segment[0], so we have to destroy that
407 size_t counter
= this->max_segments_
;
412 // Get the shared memory id and used flag on the stack as we can't read the shared memory
413 // anymore after we detached it
414 int const shmid
= st
[counter
].shmid_
;
415 int const used
= st
[counter
].used_
;
417 // When we have an address attached for this segment we have to detach it
418 if (this->shm_addr_table_
[counter
])
420 if (ACE_OS::shmdt (this->shm_addr_table_
[counter
]) == -1)
424 this->shm_addr_table_
[counter
] = nullptr;
427 // When the segment is used and we are asked to destroy it we instruct the
429 if (destroy
== 1 && used
== 1)
431 if (ACE_OS::shmctl (shmid
, IPC_RMID
, 0) == -1)
443 ACE_Shared_Memory_Pool::sync (ssize_t
, int)
445 ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
450 ACE_Shared_Memory_Pool::sync (void *, size_t, int)
452 ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
457 ACE_Shared_Memory_Pool::protect (ssize_t
, int)
459 ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
464 ACE_Shared_Memory_Pool::protect (void *, size_t, int)
466 ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
471 ACE_Shared_Memory_Pool::base_addr () const
473 ACE_TRACE ("ACE_Shared_Memory_Pool::base_addr");
474 return this->shm_addr_table_
[0];
477 /// Implement the algorithm for rounding up the request to an
478 /// appropriate chunksize.
480 ACE_Shared_Memory_Pool::round_up (size_t nbytes
)
482 ACE_TRACE ("ACE_Shared_Memory_Pool::round_up");
483 if (nbytes
< this->segment_size_
)
484 nbytes
= this->segment_size_
;
486 return ACE::round_to_pagesize (nbytes
);
489 ACE_END_VERSIONED_NAMESPACE_DECL
491 #endif /* !ACE_LACKS_SYSV_SHMEM */