Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Shared_Memory_Pool.cpp
blob10e3ba4c0670018fdcc49ffbea6fcefa7d514cdb
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,
13 size_t max_segments,
14 size_t file_perms,
15 ACE_OFF_T minimum_bytes,
16 size_t segment_size)
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");
26 void
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 */
34 int
35 ACE_Shared_Memory_Pool::in_use (ACE_OFF_T &offset,
36 size_t &counter)
38 #ifndef ACE_HAS_SYSV_IPC
39 ACE_UNUSED_ARG (offset);
40 ACE_UNUSED_ARG (counter);
41 ACE_NOTSUP_RETURN (-1);
42 #else
43 offset = 0;
44 SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->shm_addr_table_[0]);
45 shmid_ds buf;
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"),
52 ACE_TEXT ("shmctl")),
53 -1);
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));
57 return 0;
58 #endif
61 int
62 ACE_Shared_Memory_Pool::find_seg (const void* const searchPtr,
63 ACE_OFF_T &offset,
64 size_t &counter)
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);
71 #else
72 offset = 0;
73 SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->shm_addr_table_[0]);
74 shmid_ds buf;
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"),
81 ACE_TEXT ("shmctl")),
82 -1);
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)
90 --counter;
91 offset -= buf.shm_segsz;
92 return 0;
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));
97 return 0;
98 #endif
102 ACE_Shared_Memory_Pool::commit_backing_store_name (size_t rounded_bytes,
103 ACE_OFF_T &offset)
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"),
111 -1);
114 size_t counter;
115 SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->shm_addr_table_[0]);
117 if (this->in_use (offset, counter) == -1)
118 return -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",
124 counter,
125 this->shm_addr_table_[0],
126 static_cast<unsigned int>(offset)),
127 -1);
129 else
131 int const shmid = ACE_OS::shmget (st[counter].key_,
132 rounded_bytes,
133 this->file_perms_ | IPC_CREAT | IPC_EXCL);
134 if (shmid == -1)
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")),
138 -1);
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"),
148 ACE_TEXT("shmat"),
149 shmem,
150 address),
151 -1);
153 shm_addr_table_[counter] = shmem;
155 return 0;
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))
168 if (siginfo == 0)
169 return -1;
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));
174 ACE_OFF_T offset;
175 size_t counter = 0;
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",
188 siginfo->si_addr,
189 this->shm_addr_table_[0],
190 static_cast<unsigned int>(offset)),
191 -1);
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")),
203 -1);
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"),
213 ACE_TEXT("shmat"),
214 shmem,
215 address),
216 -1);
218 // NOTE: this won't work if we dont have SIGINFO_T or SI_ADDR
219 #else
220 ACE_UNUSED_ARG (siginfo);
221 #endif /* ACE_HAS_SIGINFO_T && !defined (ACE_LACKS_SI_ADDR) */
223 return 0;
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.
238 if (options)
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);
245 #else
246 if (backing_store_name)
248 // Convert the string into a number that is used as the segment
249 // key.
250 int segment_key = 0;
251 #if !defined (ACE_LACKS_SSCANF)
252 int const result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (backing_store_name),
253 "%d",
254 &segment_key);
255 #else
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));
264 else
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
272 // processes.
273 this->base_shm_key_ = ACE_DEFAULT_SHM_KEY;
276 else
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.
289 void *
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));
298 ACE_OFF_T offset;
300 if (this->commit_backing_store_name (rounded_bytes, offset) == -1)
301 return nullptr;
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.
308 void *
309 ACE_Shared_Memory_Pool::init_acquire (size_t nbytes,
310 size_t &rounded_bytes,
311 int &first_time)
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_
317 ? nbytes
318 : (size_t) this->minimum_bytes_);
320 // Acquire the semaphore to serialize initialization and prevent
321 // race conditions.
322 int shmid = ACE_OS::shmget (this->base_shm_key_,
323 rounded_bytes + shm_table_offset,
324 this->file_perms_ | IPC_CREAT | IPC_EXCL);
325 if (shmid == -1)
327 if (errno != EEXIST)
328 ACELIB_ERROR_RETURN ((LM_ERROR,
329 ACE_TEXT ("(%P|%t) ACE_Shared_Memory_Pool::init_acquire, %p\n"),
330 ACE_TEXT ("shmget")),
332 first_time = 0;
334 shmid = ACE_OS::shmget (this->base_shm_key_, 0, 0);
336 if (shmid == -1)
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"),
349 ACE_TEXT("shmat"),
350 this->shm_addr_table_[0]),
354 else
356 first_time = 1;
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"),
365 ACE_TEXT("shmat"),
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;
372 st[0].used_ = 1;
374 for (size_t counter = 1; // Skip over the first entry...
375 counter < this->max_segments_;
376 counter++)
378 #ifdef ACE_HAS_SYSV_IPC
379 st[counter].key_ = this->base_shm_key_ + counter;
380 #endif
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");
396 int result = 0;
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
406 // as last
407 size_t counter = this->max_segments_;
408 while (counter > 0)
410 --counter;
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)
422 result = -1;
424 this->shm_addr_table_[counter] = nullptr;
427 // When the segment is used and we are asked to destroy it we instruct the
428 // OS to release it
429 if (destroy == 1 && used == 1)
431 if (ACE_OS::shmctl (shmid, IPC_RMID, 0) == -1)
433 result = -1;
439 return result;
443 ACE_Shared_Memory_Pool::sync (ssize_t, int)
445 ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
446 return 0;
450 ACE_Shared_Memory_Pool::sync (void *, size_t, int)
452 ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
453 return 0;
457 ACE_Shared_Memory_Pool::protect (ssize_t, int)
459 ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
460 return 0;
464 ACE_Shared_Memory_Pool::protect (void *, size_t, int)
466 ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
467 return 0;
470 void *
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.
479 size_t
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 */