Shared_Memory_Pool.cpp

Go to the documentation of this file.
00001 // Shared_Memory_Pool.cpp,v 4.4 2005/10/28 16:14:55 ossama Exp
00002 
00003 // Shared_Memory_Pool.cpp
00004 #include "ace/Shared_Memory_Pool.h"
00005 #include "ace/OS_NS_sys_shm.h"
00006 #include "ace/Log_Msg.h"
00007 
00008 ACE_RCSID(ace, Shared_Memory_Pool, "Shared_Memory_Pool.cpp,v 4.4 2005/10/28 16:14:55 ossama Exp")
00009 
00010 #if !defined (ACE_LACKS_SYSV_SHMEM)
00011 
00012 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00013 
00014 ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_Pool)
00015 
00016 ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options (const char *base_addr,
00017                                                                 size_t max_segments,
00018                                                                 size_t file_perms,
00019                                                                 off_t minimum_bytes,
00020                                                                 size_t segment_size)
00021   : base_addr_ (base_addr),
00022     max_segments_ (max_segments),
00023     minimum_bytes_ (minimum_bytes),
00024     file_perms_ (file_perms),
00025     segment_size_ (segment_size)
00026 {
00027   ACE_TRACE ("ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options");
00028 }
00029 
00030 void
00031 ACE_Shared_Memory_Pool::dump (void) const
00032 {
00033 #if defined (ACE_HAS_DUMP)
00034   ACE_TRACE ("ACE_Shared_Memory_Pool::dump");
00035 #endif /* ACE_HAS_DUMP */
00036 }
00037 
00038 int
00039 ACE_Shared_Memory_Pool::in_use (off_t &offset,
00040                                 size_t &counter)
00041 {
00042   offset = 0;
00043   SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
00044   shmid_ds buf;
00045 
00046   for (counter = 0;
00047        counter < this->max_segments_ && st[counter].used_ == 1;
00048        counter++)
00049     {
00050       if (ACE_OS::shmctl (st[counter].shmid_, IPC_STAT, &buf) == -1)
00051         ACE_ERROR_RETURN ((LM_ERROR,
00052                            ACE_LIB_TEXT ("(%P|%t) %p\n"),
00053                            ACE_LIB_TEXT ("shmctl")),
00054                           -1);
00055       offset += buf.shm_segsz;
00056       // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) segment size = %d, offset = %d\n"), buf.shm_segsz, offset));
00057     }
00058 
00059   return 0;
00060 }
00061 
00062 int
00063 ACE_Shared_Memory_Pool::find_seg (const void* const searchPtr,
00064                                   off_t &offset,
00065                                   size_t &counter)
00066 {
00067   offset = 0;
00068   SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
00069   shmid_ds buf;
00070 
00071   for (counter = 0;
00072        counter < this->max_segments_
00073          && st[counter].used_ == 1;
00074        counter++)
00075     {
00076       if (ACE_OS::shmctl (st[counter].shmid_, IPC_STAT, &buf) == -1)
00077         ACE_ERROR_RETURN ((LM_ERROR,
00078                            ACE_LIB_TEXT ("(%P|%t) %p\n"),
00079                            ACE_LIB_TEXT ("shmctl")),
00080                           -1);
00081       offset += buf.shm_segsz;
00082 
00083       // If segment 'counter' starts at a location greater than the
00084       // place we are searching for. We then decrement the offset to
00085       // the start of counter-1. (flabar@vais.net)
00086       if (((ptrdiff_t) offset + (ptrdiff_t) (this->base_addr_)) > (ptrdiff_t) searchPtr)
00087         {
00088           --counter;
00089           offset -= buf.shm_segsz;
00090           return 0;
00091         }
00092       // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) segment size = %d, offset = %d\n"), buf.shm_segsz, offset));
00093     }
00094 
00095   return 0;
00096 }
00097 
00098 int
00099 ACE_Shared_Memory_Pool::commit_backing_store_name (size_t rounded_bytes,
00100                                                    off_t &offset)
00101 {
00102   ACE_TRACE ("ACE_Shared_Memory_Pool::commit_backing_store_name");
00103 
00104   size_t counter;
00105   SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
00106 
00107   if (this->in_use (offset, counter) == -1)
00108     return -1;
00109 
00110   if (counter == this->max_segments_)
00111     ACE_ERROR_RETURN ((LM_ERROR,
00112                       "exceeded max number of segments = %d, base = %u, offset = %u\n",
00113                        counter,
00114                        this->base_addr_,
00115                        offset),
00116                       -1);
00117   else
00118     {
00119       int shmid = ACE_OS::shmget (st[counter].key_,
00120                                   rounded_bytes,
00121                                   this->file_perms_ | IPC_CREAT | IPC_EXCL);
00122       if (shmid == -1)
00123         ACE_ERROR_RETURN ((LM_ERROR,
00124                            ACE_LIB_TEXT ("(%P|%t) %p\n"),
00125                            ACE_LIB_TEXT ("shmget")),
00126                           -1);
00127       st[counter].shmid_ = shmid;
00128       st[counter].used_ = 1;
00129 
00130       void *address = (void *) (((char *) this->base_addr_) + offset);
00131       void *shmem = ACE_OS::shmat (st[counter].shmid_,
00132                                    (char *) address,
00133                                    0);
00134 
00135       if (shmem != address)
00136         ACE_ERROR_RETURN ((LM_ERROR,
00137                            "(%P|%t) %p, shmem = %u, address = %u\n",
00138                            "shmat",
00139                            shmem,
00140                            address),
00141                           -1);
00142     }
00143   return 0;
00144 }
00145 
00146 // Handle SIGSEGV and SIGBUS signals to remap shared memory properly.
00147 
00148 int
00149 ACE_Shared_Memory_Pool::handle_signal (int , siginfo_t *siginfo, ucontext_t *)
00150 {
00151   ACE_TRACE ("ACE_Shared_Memory_Pool::handle_signal");
00152   // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("signal %S occurred\n"), signum));
00153 
00154   // While FreeBSD 5.X has a siginfo_t struct with a si_addr field,
00155   // it does not define SEGV_MAPERR.
00156 #if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR) && \
00157         (defined (SEGV_MAPERR) || defined (SEGV_MEMERR))
00158   off_t offset;
00159   // Make sure that the pointer causing the problem is within the
00160   // range of the backing store.
00161 
00162   if (siginfo != 0)
00163     {
00164       // 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));
00165       size_t counter;
00166       if (this->in_use (offset, counter) == -1)
00167         ACE_ERROR ((LM_ERROR,
00168                     ACE_LIB_TEXT ("(%P|%t) %p\n"),
00169                     ACE_LIB_TEXT ("in_use")));
00170 #if !defined(_UNICOS)
00171       else if (!(siginfo->si_code == SEGV_MAPERR
00172            && siginfo->si_addr < (((char *) this->base_addr_) + offset)
00173            && siginfo->si_addr >= ((char *) this->base_addr_)))
00174         ACE_ERROR_RETURN ((LM_ERROR,
00175                            "(%P|%t) address %u out of range\n",
00176                            siginfo->si_addr),
00177                           -1);
00178 #else /* ! _UNICOS */
00179       else if (!(siginfo->si_code == SEGV_MEMERR
00180            && siginfo->si_addr < (((unsigned long) this->base_addr_) + offset)
00181            && siginfo->si_addr >= ((unsigned long) this->base_addr_)))
00182         ACE_ERROR_RETURN ((LM_ERROR,
00183                            "(%P|%t) address %u out of range\n",
00184                            siginfo->si_addr),
00185                           -1);
00186 #endif /* ! _UNICOS */
00187     }
00188 
00189   // The above if case will check to see that the address is in the
00190   // proper range.  Therefore there is a segment out there that the
00191   // pointer wants to point into.  Find the segment that someone else
00192   // has used and attach to it (flabar@vais.net)
00193 
00194   size_t counter; // ret value to get shmid from the st table.
00195 
00196 #if !defined(_UNICOS)
00197   if (this->find_seg (siginfo->si_addr, offset, counter) == -1)
00198 #else /* ! _UNICOS */
00199   if (this->find_seg ((const void *)siginfo->si_addr, offset, counter) == -1)
00200 #endif /* ! _UNICOS */
00201       ACE_ERROR_RETURN ((LM_ERROR,
00202                          ACE_LIB_TEXT ("(%P|%t) %p\n"),
00203                          ACE_LIB_TEXT ("in_use")),
00204                         -1);
00205 
00206   void *address = (void *) (((char *) this->base_addr_) + offset);
00207   SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
00208 
00209   void *shmem = ACE_OS::shmat (st[counter].shmid_, (char *) address, 0);
00210 
00211   if (shmem != address)
00212       ACE_ERROR_RETURN ((LM_ERROR,
00213                          "(%P|%t) %p, shmem = %u, address = %u\n",
00214                          "shmat",
00215                          shmem,
00216                          address),
00217                         -1);
00218 
00219   // NOTE: this won't work if we dont have SIGINFO_T or SI_ADDR
00220 #else
00221   ACE_UNUSED_ARG (siginfo);
00222 #endif /* ACE_HAS_SIGINFO_T && !defined (ACE_LACKS_SI_ADDR) */
00223 
00224   return 0;
00225 }
00226 
00227 ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool (const ACE_TCHAR *backing_store_name,
00228                                                 const OPTIONS *options)
00229   : base_addr_ (0),
00230     file_perms_ (ACE_DEFAULT_FILE_PERMS),
00231     max_segments_ (ACE_DEFAULT_MAX_SEGMENTS),
00232     minimum_bytes_ (0),
00233     segment_size_ (ACE_DEFAULT_SEGMENT_SIZE)
00234 {
00235   ACE_TRACE ("ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool");
00236 
00237   // Only change the defaults if <options> != 0.
00238   if (options)
00239     {
00240       this->base_addr_ =
00241         reinterpret_cast<void *> (const_cast<char *> (options->base_addr_));
00242       this->max_segments_ = options->max_segments_;
00243       this->file_perms_ = options->file_perms_;
00244       this->minimum_bytes_ = options->minimum_bytes_;
00245       this->segment_size_ = options->segment_size_;
00246     }
00247 
00248   if (backing_store_name)
00249     {
00250       // Convert the string into a number that is used as the segment
00251       // key.
00252 
00253       int segment_key;
00254       int result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (backing_store_name),
00255                              "%d",
00256                              &segment_key);
00257 
00258       if (result == 0 || result == EOF)
00259         // The conversion to a number failed so hash with crc32
00260         // ACE::crc32 is also used in <SV_Semaphore_Simple>.
00261         this->base_shm_key_ =
00262           (key_t) ACE::crc32 (ACE_TEXT_ALWAYS_CHAR (backing_store_name));
00263       else
00264         this->base_shm_key_ = segment_key;
00265 
00266       if (this->base_shm_key_ == IPC_PRIVATE)
00267         // Make sure that the segment can be shared between unrelated
00268         // processes.
00269         this->base_shm_key_ = ACE_DEFAULT_SHM_KEY;
00270     }
00271   else
00272     this->base_shm_key_ = ACE_DEFAULT_SHM_KEY;
00273 
00274   if (this->signal_handler_.register_handler (SIGSEGV, this) == -1)
00275     ACE_ERROR ((LM_ERROR,
00276                 ACE_LIB_TEXT ("%p\n"),
00277                 ACE_LIB_TEXT ("ACE_Sig_Handler::register_handler")));
00278 }
00279 
00280 ACE_Shared_Memory_Pool::~ACE_Shared_Memory_Pool (void)
00281 {
00282 }
00283 
00284 // Ask system for more shared memory.
00285 
00286 void *
00287 ACE_Shared_Memory_Pool::acquire (size_t nbytes,
00288                                  size_t &rounded_bytes)
00289 {
00290   ACE_TRACE ("ACE_Shared_Memory_Pool::acquire");
00291 
00292   rounded_bytes = this->round_up (nbytes);
00293 
00294   // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) acquiring more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes));
00295 
00296   off_t offset;
00297 
00298   if (this->commit_backing_store_name (rounded_bytes, offset) == -1)
00299     return 0;
00300 
00301   // ACE_DEBUG ((LM_DEBUG,  ACE_LIB_TEXT ("(%P|%t) acquired more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes));
00302   return ((char *) this->base_addr_) + offset;
00303 }
00304 
00305 // Ask system for initial chunk of shared memory.
00306 
00307 void *
00308 ACE_Shared_Memory_Pool::init_acquire (size_t nbytes,
00309                                       size_t &rounded_bytes,
00310                                       int &first_time)
00311 {
00312   ACE_TRACE ("ACE_Shared_Memory_Pool::init_acquire");
00313 
00314   off_t shm_table_offset = ACE::round_to_pagesize (sizeof (SHM_TABLE));
00315   rounded_bytes = this->round_up (nbytes > (size_t) this->minimum_bytes_
00316                                   ? nbytes
00317                                   : (size_t) this->minimum_bytes_);
00318 
00319   // Acquire the semaphore to serialize initialization and prevent
00320   // race conditions.
00321 
00322   int shmid = ACE_OS::shmget (this->base_shm_key_,
00323                               rounded_bytes + shm_table_offset,
00324                               this->file_perms_ | IPC_CREAT | IPC_EXCL);
00325   if (shmid == -1)
00326     {
00327       if (errno != EEXIST)
00328         ACE_ERROR_RETURN ((LM_ERROR,
00329                            ACE_LIB_TEXT ("(%P|%t) %p\n"),
00330                            ACE_LIB_TEXT ("shmget")),
00331                           0);
00332       first_time = 0;
00333 
00334       shmid = ACE_OS::shmget (this->base_shm_key_, 0, 0);
00335 
00336       if (shmid == -1)
00337         ACE_ERROR_RETURN ((LM_ERROR,
00338                            ACE_LIB_TEXT ("(%P|%t) %p\n"),
00339                            ACE_LIB_TEXT ("shmget")),
00340                           0);
00341 
00342       // This implementation doesn't care if we don't get the key we
00343       // want...
00344       this->base_addr_ =
00345         ACE_OS::shmat (shmid,
00346                        reinterpret_cast<char *> (this->base_addr_),
00347                        0);
00348       if (this->base_addr_ == reinterpret_cast<void *> (-1))
00349         ACE_ERROR_RETURN ((LM_ERROR,
00350                            "(%P|%t) %p, base_addr = %u\n",
00351                            "shmat",
00352                            this->base_addr_),
00353                           0);
00354     }
00355   else
00356     {
00357       first_time = 1;
00358 
00359       // This implementation doesn't care if we don't get the key we
00360       // want...
00361       this->base_addr_ =
00362         ACE_OS::shmat (shmid,
00363                        reinterpret_cast<char *> (this->base_addr_),
00364                        0);
00365       if (this->base_addr_ == reinterpret_cast<char *> (-1))
00366         ACE_ERROR_RETURN ((LM_ERROR,
00367                            "(%P|%t) %p, base_addr = %u\n",
00368                            "shmat",
00369                            this->base_addr_), 0);
00370 
00371       SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
00372       st[0].key_ = this->base_shm_key_;
00373       st[0].shmid_ = shmid;
00374 
00375       st[0].used_ = 1;
00376 
00377       for (size_t counter = 1; // Skip over the first entry...
00378            counter < this->max_segments_;
00379            counter++)
00380         {
00381           st[counter].key_ = this->base_shm_key_ + counter;
00382           st[counter].shmid_ = 0;
00383           st[counter].used_ = 0;
00384         }
00385     }
00386 
00387   return (void *) (((char *) this->base_addr_) + shm_table_offset);
00388 }
00389 
00390 // Instruct the memory pool to release all of its resources.
00391 
00392 int
00393 ACE_Shared_Memory_Pool::release (int)
00394 {
00395   ACE_TRACE ("ACE_Shared_Memory_Pool::release");
00396 
00397   int result = 0;
00398   SHM_TABLE *st = reinterpret_cast<SHM_TABLE *> (this->base_addr_);
00399 
00400   for (size_t counter = 0;
00401        counter < this->max_segments_ && st[counter].used_ == 1;
00402        counter++)
00403     if (ACE_OS::shmctl (st[counter].shmid_, IPC_RMID, 0) == -1)
00404       result = -1;
00405 
00406   return result;
00407 }
00408 
00409 int
00410 ACE_Shared_Memory_Pool::sync (ssize_t, int)
00411 {
00412   ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
00413   return 0;
00414 }
00415 
00416 int
00417 ACE_Shared_Memory_Pool::sync (void *, size_t, int)
00418 {
00419   ACE_TRACE ("ACE_Shared_Memory_Pool::sync");
00420   return 0;
00421 }
00422 
00423 int
00424 ACE_Shared_Memory_Pool::protect (ssize_t, int)
00425 {
00426   ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
00427   return 0;
00428 }
00429 
00430 int
00431 ACE_Shared_Memory_Pool::protect (void *, size_t, int)
00432 {
00433   ACE_TRACE ("ACE_Shared_Memory_Pool::protect");
00434   return 0;
00435 }
00436 
00437 void *
00438 ACE_Shared_Memory_Pool::base_addr (void) const
00439 {
00440   ACE_TRACE ("ACE_Shared_Memory_Pool::base_addr");
00441   return this->base_addr_;
00442 }
00443 
00444 // Implement the algorithm for rounding up the request to an
00445 // appropriate chunksize.
00446 
00447 size_t
00448 ACE_Shared_Memory_Pool::round_up (size_t nbytes)
00449 {
00450   ACE_TRACE ("ACE_Shared_Memory_Pool::round_up");
00451   if (nbytes < this->segment_size_)
00452     nbytes = this->segment_size_;
00453 
00454   return ACE::round_to_pagesize (nbytes);
00455 }
00456 
00457 ACE_END_VERSIONED_NAMESPACE_DECL
00458 
00459 #endif /* !ACE_LACKS_SYSV_SHMEM */

Generated on Thu Nov 9 09:42:03 2006 for ACE by doxygen 1.3.6