Shared_Memory_Pool.cpp

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

Generated on Tue Feb 2 17:18:42 2010 for ACE by  doxygen 1.4.7