shm.cpp

00001
00002 /***************************************************************************
00003  *  shm.cpp - shared memory segment
00004  *
00005  *  Created: Thu Jan 12 14:10:43 2006
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <utils/ipc/shm.h>
00025 #include <utils/ipc/shm_exceptions.h>
00026 #include <utils/ipc/shm_lister.h>
00027 #include <utils/ipc/semset.h>
00028
00029 #include <sys/ipc.h>
00030 #include <sys/shm.h>
00031 #include <errno.h>
00032 #include <cstring>
00033 #include <limits.h>
00034 #include <cstdlib>
00035
00036 namespace fawkes {
00037 
00038 /** @class SharedMemoryHeader <utils/ipc/shm.h>
00039  * Interface for shared memory header.
00040  * This class has to be implemented to be able to use shared memory segments.
00041  * It defines a set of properties for the shared memory segment that can be
00042  * searched for and printed out by an appropriate lister.
00043  *
00044  * @see SharedMemory
00045  * @see SharedMemoryLister
00046  * @ingroup IPC
00047  * @author Tim Niemueller
00048  *
00049  *
00050  * @fn SharedMemoryHeader::~SharedMemoryHeader()
00051  * Virtual destructor
00052  *
00053  * @fn bool SharedMemoryHeader::matches(void *memptr)
00054  * Method to check if the given memptr matches this header.
00055  * This method is called when searching for a shared memory segment to
00056  * open, list or erase it.
00057  * Implement this to distuinguish several shared memory segments that share
00058  * the same magic token.
00059  * @param memptr The memory chunk in the shared memory segment where to start
00060  * checking.
00061  * @return true, if the given data in the memory chunk matches this header, false
00062  * otherwise.
00063  *
00064  * @fn unsigned int SharedMemoryHeader::size()
00065  * Size of the header.
00066  * The size that is needed in the shared memory memptr to accomodate the
00067  * header data. This size has to fit all the data that will be stored in the
00068  * header. It must return the same size every time.
00069  *
00070  * @fn void SharedMemoryHeader::initialize(void *memptr)
00071  * Initialize the header.
00072  * This should initialize the header data in the given memptr from the
00073  * data of this SharedMemoryHeader derivate instance. It has to write out
00074  * all state information that is needed to identify the shared memory
00075  * segment later on.
00076  * @param memptr the memptr where the header data shall be written to.
00077  *
00078  * @fn void SharedMemoryHeader::set(void *memptr)
00079  * Set information from memptr.
00080  * Set the information stored in this SharedMemoryHeader derivate instance
00081  * from the data stored in the given memptr.
00082  * @param memptr The memptr where to copy data from.
00083  *
00084  * @fn void SharedMemoryHeader::reset()
00085  * Reset information previously set with set().
00086  * This shall restore the state the header had before set() was called. This is
00087  * used for instance in the SharedMemoryLister after info about one segment
00088  * has been printed.
00089  *
00090  * @fn size_t SharedMemoryHeader::data_size()
00091  * Return the size of the data.
00092  * The size of the data that will be stored in the shared memory segment.
00093  * This method has to return the same value everytime and may only depend
00094  * on the other data set in the header and written to the shared memory
00095  * segment.
00096  * @return the size of the data segment
00097  *
00098  * @fn SharedMemoryHeader *  SharedMemoryHeader::clone() const
00099  * Clone this shared memory header.
00100  * This method shall return a copied instance of this SharedMemoryHeader derivate.
00101  * It should act the same way as the current instance.
00102  * @return Clone instance. Remember to delete the instance.
00103  *
00104  * @fn bool SharedMemoryHeader::operator==(const SharedMemoryHeader &s) const
00105  * Check for equality if headers.
00106  * This shall be implemented that it compares the current and the given instances for
00107  * equality. You probably want to use dynamic_cast to cast the given instance to
00108  * a compatible type.
00109  * @param s shared memory header to compare to
00110  * @return true if the two instances identify the very same shared memory segments,
00111  * false otherwise
00112  */
00113
00114 
00115 /** @class SharedMemory <utils/ipc/shm.h>
00116  * Shared memory segment.
00117  * This class gives access to shared memory segment to store arbitrary data.
00118  * With shared memory data can be shared between several applications. Special
00119  * means like semaphores have to be used to control access to the storage
00120  * to prevent data corruption.
00121  *
00122  * The shared memory segment is divided into three parts.
00123  * 1. General shared memory header
00124  * 2. Data-specific header
00125  * 3. Data
00126  *
00127  * The general header consists of a magic token of MagicTokenSize that is used
00128  * to find the basically compatible shared memory segments out of all existing
00129  * shared memory segments. This is done for convenience. Although in general
00130  * shared memory is accessed via keys or IDs it is easier from the maintenance
00131  * side to just scan the segments to find the correct one, especially if there
00132  * may be more than just one segment for the same application.
00133  * The header also includes a semaphore ID which is unused at the moment.
00134  *
00135  * The data-specific header is generated from a given SharedMemoryHeader
00136  * implementation. It can be used to store any information that is needed to
00137  * identify a specific shared memory segment and to store management data for
00138  * the data segment. It should always contain enough information to derive
00139  * the data segment size or if needed an explicit information about the memory
00140  * size.
00141  *
00142  * The data segment can be filled with any data you like.
00143  *
00144  * Shared memory segments are protected with a read-write lock implemented with
00145  * two IPC semaphores. The writer takes preference in locking. Only a limited
00146  * number of concurrent readers can be allowed. The constant
00147  * MaxNumberConcurrentReaders defines how many these are.
00148  * If a shared memory segment already has a semaphore assigned at the time it
00149  * is opened this semaphore is automatically opened. In any case add_semaphore()
00150  * can be used to create (or open if it already exists) a semaphore for the
00151  * shared memory segment. Information about the semaphore is stored in the
00152  * shared memory general header.
00153  *
00154  * This class provides utilities to list, erase and check existence of given
00155  * shared memory segments. For this often a SharedMemoryLister is used that
00156  * takes care of formatting the output of the specific information about the
00157  * shared memory segment.
00158  *
00159  * @see SharedMemoryHeader
00160  * @see SharedMemorySegment
00161  * @see qa_shmem.cpp
00162  * @ingroup IPC
00163  *
00164  * @author Tim Niemueller
00165  */
00166 
00167 /** @var SharedMemory::_memptr
00168  * Pointer to the data segment.
00169  */
00170 /** @var SharedMemory::_mem_size
00171  * Total size of the segment, including headers
00172  */
00173 /** @fn SharedMemory::_data_size
00174  * Size of the data segment only
00175  */
00176 /** @var SharedMemory::_header
00177  * Data-specific header
00178  */
00179 /** @var SharedMemory::_is_read_only
00180  * Read-only.
00181  * if true before attach() open segment read-only
00182  */
00183 /** @var SharedMemory::_destroy_on_delete
00184  * destroy on delete.
00185  * If true before free() segment is destroyed.
00186  */
00187 /** @var SharedMemory::_should_create
00188  * Create shared memory segment.
00189  * If true before attach shared memory segment is created if it does
00190  * not exist.
00191  */
00192 /** @var SharedMemory::_magic_token
00193  * Magic token
00194  */
00195 /** @var SharedMemory::_shm_magic_token
00196  * Magic token as stored in the shared memory segment
00197  */
00198 /** @var SharedMemory::_shm_header
00199  * general header as stored in the shared memory segment
00200  */
00201 /** @var SharedMemory::_shm_upper_bound
00202  * Upper bound of memory. Used by ptr to determine if the given address is valid.
00203  */
00204 /** @var SharedMemory::_shm_offset
00205  * Offset to the master's base addr.
00206  */
00207 
00208 /** The magic token size.
00209  * Your magic token identifier may have an arbitrary size. It is truncated
00210  * at MagicTokenSize bytes or filled with zeros up to a length of
00211  * MagicTokenSize bytes.
00212  */
00213 const unsigned int SharedMemory::MagicTokenSize = 16;
00214 
00215 /** Maximum number of concurrent readers.
00216  * This constant defines how many readers may concurrently read from
00217  * shared memory segments.
00218  */
00219 const short SharedMemory::MaxNumConcurrentReaders = 8;
00220
00221 #define WRITE_MUTEX_SEM 0
00222 #define READ_SEM        1
00223 
00224 
00225 /** Constructor for derivates.
00226  * This constructor may only be used by derivatives. It can be used to delay
00227  * the call to attach() to do other preparations like creating a
00228  * SharedMemoryHeader object.
00229  * @param magic_token magic token of the shared memory segment
00230  * @param is_read_only if true the shared memory segment is opened in
00231  *                     read-only mode
00232  * @param create       if true the shared memory segment is created if
00233  *                     no one matching the headers was found
00234  * @param destroy_on_delete if true the shared memory segment is destroyed
00235  *                          when this SharedMemory instance is deleted.
00236  */
00237 SharedMemory::SharedMemory(const char *magic_token,
00238                            bool is_read_only,
00239                            bool create,
00240                            bool destroy_on_delete)
00241 {
00242   _magic_token = new char[MagicTokenSize];
00243   memset(_magic_token, 0, MagicTokenSize);
00244   strncpy(_magic_token, magic_token, MagicTokenSize);
00245
00246   _is_read_only      = is_read_only;
00247   _destroy_on_delete = destroy_on_delete;
00248   _should_create     = create;
00249
00250   _memptr          = NULL;
00251   _shm_magic_token = NULL;
00252   _shm_header      = NULL;
00253   _header          = NULL;
00254   _data_size       = 0;
00255
00256   __semset         = NULL;
00257   __created        = false;
00258   __shared_mem     = NULL;
00259   __shared_mem_id  = 0;
00260   __shared_mem_upper_bound = NULL;
00261
00262   __write_lock_aquired     = false;
00263 }
00264
00265 
00266 /** Copy constructor.
00267  * If the given SharedMemory was attached this instance will also attach.
00268  * @param s SharedMemory instance to copy.
00269  */
00270 SharedMemory::SharedMemory(const SharedMemory &s)
00271 {
00272   _magic_token = new char[MagicTokenSize];
00273   memset(_magic_token, 0, MagicTokenSize);
00274   strncpy(_magic_token, s._magic_token, MagicTokenSize);
00275
00276   _is_read_only      = s._is_read_only;
00277   _destroy_on_delete = s._destroy_on_delete;
00278   _should_create     = s._should_create;
00279
00280   _memptr          = NULL;
00281   _shm_magic_token = NULL;
00282   _shm_header      = NULL;
00283   _header          = s._header->clone();
00284   _data_size       = 0;
00285
00286   __semset         = NULL;
00287   __created        = false;
00288   __shared_mem     = NULL;
00289   __shared_mem_id  = 0;
00290   __shared_mem_upper_bound = NULL;
00291
00292   __write_lock_aquired     = false;
00293
00294   try {
00295     attach();
00296   } catch (Exception &e) {
00297     e.append("SharedMemory public copy constructor");
00298     throw;
00299   }
00300
00301   if (_memptr == NULL) {
00302     throw ShmCouldNotAttachException("Could not attach to created shared memory segment");
00303   }
00304 }
00305
00306 
00307 /** Create a new shared memory segment.
00308  * This will open a shared memory segment that exactly fits the given
00309  * SharedMemoryHeader. It the segment does not exist and create is assured
00310  * the segment is created from the given data, otherwise the SharedMemory
00311  * instance remains in an invalid state and an exception is thrown.
00312  * The segment can be destroyed automatically if the instance is destroyed.
00313  * Shared memory segments can be opened read-only.
00314  * @param magic_token This is the magic token discussed above that is used
00315  *                    to identify the shared memory segment. The magic_token
00316  *                    can be of arbitrary size but at most MagicTokenSize
00317  *                    bytes are used.
00318  * @param header      The data-sepcific header used for this shared memory
00319  *                    segment
00320  * @param is_read_only if true the shared memory segment is opened in
00321  *                     read-only mode
00322  * @param create       if true the shared memory segment is created if
00323  *                     no one matching the headers was found
00324  * @param destroy_on_delete if true the shared memory segment is destroyed
00325  *                          when this SharedMemory instance is deleted.
00326  * @exception ShmNoHeaderException No header has been set
00327  * @exception ShmInconsistentSegmentSizeException The memory size is not the
00328  *                                                expected memory size
00329  * @exception ShmCouldNotAttachException Could not attach to shared
00330  *                                       memory segment
00331  */
00332 SharedMemory::SharedMemory(const char *magic_token,
00333                            SharedMemoryHeader *header,
00334                            bool is_read_only, bool create, bool destroy_on_delete)
00335 {
00336   _magic_token = new char[MagicTokenSize];
00337   memset(_magic_token, 0, MagicTokenSize);
00338   strncpy(_magic_token, magic_token, MagicTokenSize);
00339
00340   _header            = header;
00341   _is_read_only      = is_read_only;
00342   _destroy_on_delete = destroy_on_delete;
00343   _should_create     = create;
00344
00345   _memptr          = NULL;
00346   _shm_magic_token = NULL;
00347   _shm_header      = NULL;
00348   _data_size       = 0;
00349
00350   __created         = false;
00351   __semset          = NULL;
00352   __shared_mem     = NULL;
00353   __shared_mem_id  = 0;
00354   __shared_mem_upper_bound = NULL;
00355
00356   __write_lock_aquired     = false;
00357
00358   try {
00359     attach();
00360   } catch (Exception &e) {
00361     e.append("SharedMemory public constructor");
00362     throw;
00363   }
00364
00365   if (_memptr == NULL) {
00366     throw ShmCouldNotAttachException("Could not attach to created shared memory segment");
00367   }
00368 }
00369
00370 
00371 /** Destructor */
00372 SharedMemory::~SharedMemory()
00373 {
00374   if ( __semset != NULL ) {
00375     // if we destroy the shared memory region we can as well delete the semaphore,
00376     // it is not necessary anymore.
00377     __semset->set_destroy_on_delete( _destroy_on_delete );
00378     if ( _destroy_on_delete && ! _is_read_only ) {
00379       _shm_header->semaphore = 0;
00380     }
00381     delete __semset;
00382   }
00383   delete[] _magic_token;
00384   free();
00385 }
00386
00387 
00388 /** Detach from and maybe destroy the shared memory segment.
00389  * This will detach from the shared memory segment. If destroy_on_delete is
00390  * true this will destroy the shared memory segment before detaching.
00391  */
00392 void
00393 SharedMemory::free()
00394 {
00395   _memptr = NULL;
00396   _shm_header = NULL;
00397   _shm_magic_token = NULL;
00398
00399   if ((__shared_mem_id != -1) && !_is_read_only && _destroy_on_delete ) {
00400     shmctl(__shared_mem_id, IPC_RMID, NULL);
00401     __shared_mem_id = -1;
00402   }
00403   if (__shared_mem != NULL) {
00404     shmdt(__shared_mem);
00405     __shared_mem = NULL;
00406   }
00407 }
00408
00409 
00410 /** Attach to the shared memory segment.
00411  * This method will try to open and/or create the shared memory segment.
00412  * @exception ShmNoHeaderException No header has been set
00413  * @exception ShmInconsistentSegmentSizeException The memory size is not the
00414  *                                                expected memory size
00415  * @exception ShmCouldNotAttachException Could not attach to shared
00416  *                                       memory segment
00417  */
00418 void
00419 SharedMemory::attach()
00420 {
00421
00422   if (_header == NULL) {
00423     // No shared memory header, needed!
00424     throw ShmNoHeaderException();
00425   }
00426
00427   if ((_memptr != NULL) && (__shared_mem_id != -1)) {
00428     // a memptr has already been attached
00429     return;
00430   }
00431
00432   // based on code by ipcs and Philipp Vorst from allemaniACs3D
00433   int              max_id;
00434   int              shm_id;
00435   struct shmid_ds  shm_segment;
00436   void            *shm_buf;
00437   void            *shm_ptr;
00438
00439   // Find out maximal number of existing SHM segments
00440   struct shmid_ds shm_info;
00441   max_id = shmctl( 0, SHM_INFO, &shm_info );
00442
00443   if (max_id >= 0) {
00444     for ( int i = 0; (_memptr == NULL) && (i <= max_id); ++i ) {
00445
00446       shm_id = shmctl( i, SHM_STAT, &shm_segment );
00447       if ( shm_id < 0 )  continue;
00448       // Could be done to forbid attaching to destroyed segments
00449       // if ( shm_segment.shm_perm.mode & SHM_DEST )  continue;
00450
00451       shm_buf = shmat(shm_id, NULL, _is_read_only ? SHM_RDONLY : 0);
00452       if (shm_buf != (void *)-1) {
00453         // Attached
00454
00455         _shm_magic_token = (char *)shm_buf;
00456         _shm_header = (SharedMemory_header_t *)((char *)shm_buf + MagicTokenSize);
00457
00458         if ( strncmp(_shm_magic_token, _magic_token, MagicTokenSize) == 0 ) {
00459
00460           shm_ptr = (char *)shm_buf + MagicTokenSize
00461                                     + sizeof(SharedMemory_header_t);
00462
00463           if ( _header->matches( shm_ptr ) ) {
00464             // matching memory segment found
00465
00466             _header->set( shm_ptr );
00467             _data_size = _header->data_size();
00468             _mem_size  = sizeof(SharedMemory_header_t) + MagicTokenSize
00469                                                        + _header->size() + _data_size;
00470
00471             if (_mem_size != (unsigned int) shm_segment.shm_segsz) {
00472               throw ShmInconsistentSegmentSizeException(_mem_size,
00473                                                         (unsigned int) shm_segment.shm_segsz);
00474             }
00475
00476             __shared_mem_id   = shm_id;
00477             __shared_mem      = shm_buf;
00478             __shared_mem_upper_bound = (void *)((size_t)__shared_mem + _mem_size);
00479             _shm_upper_bound   = (void *)((size_t)_shm_header->shm_addr + _mem_size);
00480             _memptr            = (char *)shm_ptr + _header->size();
00481             _shm_offset        = (size_t)__shared_mem - (size_t)_shm_header->shm_addr;
00482
00483             if ( _shm_header->semaphore != 0 ) {
00484               // Houston, we've got a semaphore, open it!
00485               add_semaphore();
00486             }
00487
00488           } else {
00489             // not the wanted memory segment
00490             shmdt(shm_buf);
00491           }
00492         } else {
00493           // not our region of memory
00494           shmdt(shm_buf);
00495         }
00496       } // else could not attach, ignore
00497     }
00498   }
00499
00500   if ((_memptr == NULL) && ! _is_read_only && _should_create) {
00501     // try to create a new shared memory segment
00502     __created = true;
00503     key_t key = 1;
00504
00505     _data_size = _header->data_size();
00506     _mem_size  = sizeof(SharedMemory_header_t) + MagicTokenSize + _header->size() + _data_size;
00507     while ((_memptr == NULL) && (key < INT_MAX)) {
00508     // no shm segment found, create one
00509       __shared_mem_id = shmget(key, _mem_size, IPC_CREAT | IPC_EXCL | 0666);
00510       if (__shared_mem_id != -1) {
00511         __shared_mem = shmat(__shared_mem_id, NULL, 0);
00512         if (__shared_mem != (void *)-1) {
00513           memset(__shared_mem, 0, _mem_size);
00514
00515           _shm_magic_token = (char *)__shared_mem;
00516           _shm_header = (SharedMemory_header_t *)((char *)__shared_mem + MagicTokenSize);
00517           _shm_header->shm_addr = __shared_mem;
00518
00519           _memptr     = (char *)__shared_mem + MagicTokenSize
00520                                              + sizeof(SharedMemory_header_t)
00521                                              + _header->size();
00522           _shm_upper_bound = (void *)((size_t)__shared_mem + _mem_size);
00523           _shm_offset      = 0;
00524           __shared_mem_upper_bound = _shm_upper_bound;
00525
00526           strncpy(_shm_magic_token, _magic_token, MagicTokenSize);
00527
00528           _header->initialize( (char *)__shared_mem + MagicTokenSize
00529                                                     + sizeof(SharedMemory_header_t));
00530         } else {
00531           // It didn't work out, destroy shared mem and try again
00532           shmctl(__shared_mem_id, IPC_RMID, NULL);
00533           throw ShmCouldNotAttachException("Could not create shared memory segment");
00534         }
00535       } else {
00536         if (errno == EEXIST) {
00537           // non-free key number, try next one
00538           // note: we don't care about existing shared memory regions as we scanned
00539           // them before already!
00540           ++key;
00541         } else if (errno == EINVAL) {
00542           throw ShmCouldNotAttachException("Could not attach, segment too small or too big");
00543         } else {
00544           throw ShmCouldNotAttachException("Could not attach, shmget failed");
00545         }
00546       }
00547     }
00548   }
00549
00550   if (_memptr == NULL) {
00551     throw ShmCouldNotAttachException("Could not attach to shared memory segment");
00552   }
00553 }
00554
00555 
00556 /** Get the real pointer to the data based on an address.
00557  * If there is address-dependent data in the shared memory segment (like pointers
00558  * to the next element in a linked list) these are only valid for the process
00559  * that created the shared memory segment, they are not necessarily valid for
00560  * other processes.
00561  *
00562  * The function takes an address that has been stored in the
00563  * shared memory segment and transforms it into a valid local pointer.
00564  * Not that this does only work with pointers inside the shared memory segment.
00565  * You can only tranform addresses that point to somewhere inside the shared
00566  * memory segment!
00567  *
00568  * We could also have added local offsets, starting with 0 at the beginning
00569  * of the shared memory segment. We decided against this since our major our
00570  * main concern is that this works fast for the master, because this will be the
00571  * Fawkes main application, and for attached processes it may work slower and
00572  * we don't care.
00573  *
00574  * @param addr memory address read from the shared memory segment
00575  * @return pointer inside the shared memory segment
00576  * @exception ShmAddrOutOfBoundsException This exception is thrown if addr is not NULL,
00577  * smaller than the base addr and greater or equal to the base addr plus the memory size.
00578  * @see addr()
00579  */
00580 void *
00581 SharedMemory::ptr(void *addr)
00582 {
00583   if ( _shm_offset == 0 )  return addr;
00584   if ( addr == NULL) return NULL;
00585   if ( (addr < _shm_header->shm_addr) ||
00586        (addr >= _shm_upper_bound) ) {
00587     throw ShmAddrOutOfBoundsException();
00588   }
00589   return (void *)((size_t)addr + _shm_offset);
00590 }
00591
00592 
00593 /** Get an address from a real pointer.
00594  * If there is address-dependent data in the shared memory segment (like pointers
00595  * to the next element in a linked list) these are only valid for the process
00596  * that created the shared memory segment, they are not necessarily valid for
00597  * other processes.
00598  *
00599  * This method takes a pointer that points to data in the shared memory segment
00600  * that is valid in the local process and transform it to a pointer that is valid
00601  * inside the shared memory segment with respect to the base address used by the
00602  * creating process.
00603  *
00604  * @param ptr pointer to data inside the shared memory segment
00605  * @return  memory address valid for the creator of the shared memory segment
00606  * @exception ShmPtrOutOfBoundsException This exception is thrown if ptr is not NULL,
00607  * smaller than the local base ptr and greater or equal to the local base ptr plus
00608  * the memory size.
00609  * @see ptr()
00610  */
00611 void *
00612 SharedMemory::addr(void *ptr)
00613 {
00614   if ( _shm_offset == 0 )  return ptr;
00615   if ( ptr == NULL) return NULL;
00616   if ( (ptr < __shared_mem) ||
00617        (ptr >= __shared_mem_upper_bound) ) {
00618     throw ShmPtrOutOfBoundsException();
00619   }
00620   return (void *)((size_t)ptr - _shm_offset);
00621 }
00622
00623 
00624 /** Check for read-only mode
00625  * @return true, if the segment is opened in read-only mode, false otherwise
00626  */
00627 bool
00628 SharedMemory::is_read_only()
00629 {
00630   return _is_read_only;
00631 }
00632
00633 
00634 /** Determine if the shared memory segment has been created by this instance.
00635  * In some situations you want to know if the current instance has created the shared
00636  * memory segment or if it attached to an existing shared memory segment. This is
00637  * handy for example in master-slave constellations where one process is the master
00638  * over a given shared memory segment and other slaves may read but need special
00639  * means to alter the data.
00640  * This is a somewhat softer variant of exclusive access.
00641  * @return true, if this instance of SharedMemory created the segment, false
00642  * otherwise
00643  */
00644 bool
00645 SharedMemory::is_creator()
00646 {
00647   return __created;
00648 }
00649 
00650 /** Get a pointer to the shared memory
00651  * This method returns a pointer to the data-segment of the shared memory
00652  * segment. It has the size stated as dataSize() from the header.
00653  * @return pointer to the data-segment
00654  * @see getDataSize()
00655  */
00656 void *
00657 SharedMemory::memptr()
00658 {
00659   return _memptr;
00660 }
00661
00662 
00663 /** Get the size of the data-segment.
00664  * Use this method to get the size of the data segment. Calls dataSize() of
00665  * the data-specific header internally.
00666  * @return size of the data-segment in bytes
00667  */
00668 size_t
00669 SharedMemory::data_size()
00670 {
00671   return _data_size;
00672 }
00673
00674 
00675 /** Copies data from the memptr to shared memory.
00676  * Use this method to copy data from the given external memptr to the
00677  * data segment of the shared memory.
00678  * @param memptr the memptr to copy from
00679  */
00680 void
00681 SharedMemory::set(void *memptr)
00682 {
00683   memcpy(_memptr, memptr, _data_size);
00684 }
00685
00686 
00687 /** Check if segment has been destroyed
00688  * This can be used if the segment has been destroyed. This means that no
00689  * other process can connect to the shared memory segment. As long as some
00690  * process is attached to the shared memory segment the segment will still
00691  * show up in the list
00692  * @return true, if this shared memory segment has been destroyed, false
00693  *         otherwise
00694  */
00695 bool
00696 SharedMemory::is_destroyed()
00697 {
00698   return is_destroyed(__shared_mem_id);
00699 }
00700
00701 
00702 /** Check if memory can be swapped out.
00703  * This method can be used to check if the memory can be swapped.
00704  * @return true, if the memory can be swapped, false otherwise
00705  */
00706 bool
00707 SharedMemory::is_swapable()
00708 {
00709   return is_swapable(__shared_mem_id);
00710 }
00711
00712 
00713 /** Check validity of shared memory segment.
00714  * Use this to check if the shared memory segmentis valid. That means that
00715  * this instance is attached to the shared memory and data can be read from
00716  * or written to the memptr.
00717  * @return true, if the shared memory segment is valid and can be utilized,
00718  *         false otherwise
00719  */
00720 bool
00721 SharedMemory::is_valid()
00722 {
00723   return (_memptr != NULL);
00724 }
00725
00726 
00727 /** Check if memory segment is protected.
00728  * This method can be used to determine if a semaphore has been associated to
00729  * this shared memory segment. Locking is not guaranteed, it depends on the
00730  * application. Use lock(), tryLock() and unlock() appropriately. You can do
00731  * this always, also if you start with unprotected memory. The operations are
00732  * just noops in that case. Protection can be enabled by calling add_semaphore().
00733  * If a memory segment was protected when it was opened it is automatically
00734  * opened in protected mode.
00735  * @return true, if semaphore is associated to memory, false otherwise
00736  */
00737 bool
00738 SharedMemory::is_protected()
00739 {
00740   return (__semset != NULL);
00741 }
00742
00743 
00744 /** Set deletion behaviour.
00745  * This has the same effect as the destroy_on_delete parameter given to the
00746  * constructor.
00747  * @param destroy set to true to destroy the shared memory segment on
00748  *        deletion
00749  */
00750 void
00751 SharedMemory::set_destroy_on_delete(bool destroy)
00752 {
00753   _destroy_on_delete = destroy;
00754 }
00755
00756 
00757 /** Add semaphore to shared memory segment.
00758  * This adds a semaphore to the system and puts its key in the shared memory
00759  * segment header. The semaphore can then be protected via the semaphore by
00760  * appropriate locking. If a semaphore has been assigned to the shared memory
00761  * segment already but after the segment was opened the semaphore is opened
00762  * and no new semaphore is created.
00763  */
00764 void
00765 SharedMemory::add_semaphore()
00766 {
00767   if (__semset != NULL)  return;
00768   if (_memptr == NULL) throw Exception("Cannot add semaphore if not attached");
00769
00770   if ( _shm_header->semaphore != 0 ) {
00771     // a semaphore has been created but not been opened
00772     __semset = new SemaphoreSet( _shm_header->semaphore,
00773                                  /* num sems    */ 2,
00774                                  /* create      */ false,
00775                                  /* dest on del */ false );
00776   } else {
00777     // no semaphore exist, create one, but only if shmem is not
00778     // opened read-only!
00779     if ( ! _is_read_only) {
00780       __semset = new SemaphoreSet( /* num sems    */ 2,
00781                                    /* dest on del */ true );
00782       // one and only one (writer) may lock the memory
00783       __semset->unlock(WRITE_MUTEX_SEM);
00784       // up to MaxNumConcurrentReaders readers can lock the memory
00785       __semset->set_value(READ_SEM, MaxNumConcurrentReaders);
00786       _shm_header->semaphore = __semset->key();
00787     } else {
00788       throw Exception("Cannot create semaphore for read-only shmem segment");
00789     }
00790   }
00791 }
00792
00793 
00794 /** Set shared memory swapable.
00795  * Setting memory unswapable (in terms of Linux memory management: lock all
00796  * pages related to this memory segment) will only succeed for very small
00797  * portions of memory. A resource limit is implied (see getrlimit(2)). In
00798  * most cases the maximum amout of locked memory is about 32 KB.
00799  * @param swapable set to true, if memory should be allowed to be swaped out.
00800  */
00801 void
00802 SharedMemory::set_swapable(bool swapable)
00803 {
00804   if (swapable) {
00805     shmctl(__shared_mem_id, SHM_UNLOCK, NULL);
00806   } else {
00807     shmctl(__shared_mem_id, SHM_LOCK, NULL);
00808   }
00809 }
00810
00811 
00812 /** Lock shared memory segment for reading.
00813  * If the shared memory segment is protected by an associated semaphore it can be
00814  * locked with this semaphore by calling this method.
00815  * @see isProtected()
00816  * @see unlock()
00817  * @see try_lock_for_read()
00818  */
00819 void
00820 SharedMemory::lock_for_read()
00821 {
00822   if ( __semset == NULL ) {
00823     return;
00824   }
00825
00826   __semset->lock(READ_SEM);
00827   __lock_aquired = true;
00828 }
00829
00830 
00831 /** Try to aquire lock on shared memory segment for reading.
00832  * If the shared memory segment is protected by an associated semaphore it can be
00833  * locked. With tryLock() you can try to aquire the lock, but the method will not
00834  * block if it cannot get the lock but simply return false. This can be used to detect
00835  * if memory is locked:
00836  * @code
00837  * if (mem->tryLock()) {
00838  *   // was not locked
00839  *   mem->unlock();
00840  * } else {
00841  *   // is locked
00842  * }
00843  * @endcode
00844  * @see isProtected()
00845  * @see unlock()
00846  * @see lock()
00847  */
00848 bool
00849 SharedMemory::try_lock_for_read()
00850 {
00851   if ( __semset == NULL )  return false;
00852
00853   if ( __semset->try_lock(READ_SEM) ) {
00854     __lock_aquired = true;
00855     return true;
00856   } else {
00857     return false;
00858   }
00859 }
00860
00861 
00862 /** Lock shared memory segment for writing.
00863  * If the shared memory segment is protected by an associated semaphore it can be
00864  * locked with this semaphore by calling this method.
00865  * @see is_protected()
00866  * @see unlock()
00867  * @see try_lock_for_read()
00868  */
00869 void
00870 SharedMemory::lock_for_write()
00871 {
00872   if ( __semset == NULL ) {
00873     return;
00874   }
00875
00876   __semset->lock(WRITE_MUTEX_SEM);
00877   for ( short i = 0; i < MaxNumConcurrentReaders; ++i) {
00878     __semset->lock(READ_SEM);
00879   }
00880   __write_lock_aquired = true;
00881   __lock_aquired = true;
00882   __semset->unlock(WRITE_MUTEX_SEM);
00883 }
00884
00885 
00886 /** Try to aquire lock on shared memory segment for writing.
00887  * If the shared memory segment is protected by an associated semaphore it can be
00888  * locked. With tryLock() you can try to aquire the lock, but the method will not
00889  * block if it cannot get the lock but simply return false. This can be used to detect
00890  * if memory is locked:
00891  * @code
00892  * if (mem->tryLock()) {
00893  *   // was not locked
00894  *   mem->unlock();
00895  * } else {
00896  *   // is locked
00897  * }
00898  * @endcode
00899  * @see isProtected()
00900  * @see unlock()
00901  * @see lock()
00902  */
00903 bool
00904 SharedMemory::try_lock_for_write()
00905 {
00906   if ( __semset == NULL )  return false;
00907
00908   if ( __semset->try_lock(WRITE_MUTEX_SEM) ) {
00909     for ( short i = 0; i < MaxNumConcurrentReaders; ++i) {
00910       if ( ! __semset->try_lock(READ_SEM) ) {
00911         // we up to now locked i-1 readers, unlock 'em and fail
00912         for (short j = 0; j < i - 1; ++j) {
00913           __semset->unlock(READ_SEM);
00914         }
00915         __semset->unlock(WRITE_MUTEX_SEM);
00916         return false;
00917       }
00918     }
00919     __lock_aquired = true;
00920     __write_lock_aquired = true;
00921     __semset->unlock(WRITE_MUTEX_SEM);
00922     return true;
00923   } else {
00924     return false;
00925   }
00926 }
00927
00928 
00929 /** Unlock memory.
00930  * If the shared memory segment is protected by an associated semaphore it can be
00931  * locked. With unlock() you lift the lock on the memory. Be aware that unlocking
00932  * a not-locked piece of memory will result in havoc and insanity! Have only exactly
00933  * guaranteed pairs of lock/successful tryLock() and unlock()!
00934  */
00935 void
00936 SharedMemory::unlock()
00937 {
00938   if ( __semset == NULL || ! __lock_aquired )  return;
00939
00940   if ( __write_lock_aquired ) {
00941     for ( short i = 0; i < MaxNumConcurrentReaders; ++i) {
00942       __semset->unlock(READ_SEM);
00943     }
00944     __write_lock_aquired = false;
00945   } else {
00946     __semset->unlock(READ_SEM);
00947   }
00948 }
00949
00950
00951 /* ==================================================================
00952  * STATICs
00953  */
00954 
00955 /** Check if a segment has been destroyed.
00956  * Check for a shared memory segment of the given ID.
00957  * @param shm_id ID of the shared memory segment.
00958  * @return true, if the shared memory segment is marked as destroyed or
00959  * does not exist at all, false otherwise.
00960  */
00961 bool
00962 SharedMemory::is_destroyed(int shm_id)
00963 {
00964   struct shmid_ds  shm_segment;
00965
00966   if (shmctl(shm_id, IPC_STAT, &shm_segment ) == -1) {
00967     return true;
00968   } else {
00969 #ifdef __USEMISC
00970     struct ipc_perm *perm = &shm_segment.shm_perm;
00971     return (perm->mode & SHM_DEST);
00972 #else
00973     return false;
00974 #endif
00975   }
00976 }
00977
00978 
00979 /** Check if memory can be swapped out.
00980  * This method can be used to check if the memory can be swapped.
00981  * @param shm_id ID of the shared memory segment.
00982  * @return true, if the memory can be swapped, false otherwise
00983  */
00984 bool
00985 SharedMemory::is_swapable(int shm_id)
00986 {
00987 #ifdef __USE_MISC
00988   struct shmid_ds  shm_segment;
00989   struct ipc_perm *perm = &shm_segment.shm_perm;
00990
00991   if (shmctl(shm_id, IPC_STAT, &shm_segment ) < 0) {
00992     return true;
00993   } else {
00994     return ! (perm->mode & SHM_LOCKED);
00995   }
00996 #else
00997   return true;
00998 #endif
00999 }
01000
01001 
01002 /** Get number of attached processes.
01003  * @param shm_id ID of the shared memory segment.
01004  * @return number of attached processes
01005  */
01006 unsigned int
01007 SharedMemory::num_attached(int shm_id)
01008 {
01009   struct shmid_ds  shm_segment;
01010
01011   if (shmctl(shm_id, IPC_STAT, &shm_segment ) < 0) {
01012     return 0;
01013   } else {
01014     return shm_segment.shm_nattch;
01015   }
01016 }
01017
01018 
01019 /** List shared memory segments of a given type.
01020  * This method lists all shared memory segments that match the given magic
01021  * token (first MagicTokenSize bytes, filled with zero) and the given
01022  * header. The lister is called to format the output.
01023  * @param magic_token Token to look for
01024  * @param header      header to identify interesting segments with matching
01025  *                    magic_token
01026  * @param lister      Lister used to format output
01027  */
01028 void
01029 SharedMemory::list(const char *magic_token,
01030                    SharedMemoryHeader *header, SharedMemoryLister *lister)
01031 {
01032
01033   lister->print_header();
01034   SharedMemoryIterator i = find(magic_token, header);
01035   SharedMemoryIterator endi = end();
01036
01037   if ( i == endi ) {
01038     lister->print_no_segments();
01039   }
01040
01041   while ( i != endi ) {
01042     lister->print_info(*i, i.shmid(), i.semaphore(), i.segmsize(),
01043                       i.databuf());
01044     ++i;
01045   }
01046
01047   lister->print_footer();
01048 }
01049
01050 
01051 /** Erase shared memory segments of a given type.
01052  * This method erases (destroys) all shared memory segments that match the
01053  * given magic token (first MagicTokenSize bytes, filled with zero) and the
01054  * given header. The lister is called to format the output. If a semaphore
01055  * has been assigned to this shared memory segment it is destroyed as well.
01056  * @param magic_token Token to look for
01057  * @param header      header to identify interesting segments with matching
01058  *                    magic_token
01059  * @param lister      Lister used to format output, maybe NULL (default)
01060  */
01061 void
01062 SharedMemory::erase(const char *magic_token,
01063                     SharedMemoryHeader *header, SharedMemoryLister *lister)
01064 {
01065
01066   if (lister != NULL) lister->print_header();
01067
01068   SharedMemoryIterator i = find(magic_token, header);
01069   SharedMemoryIterator endi = end();
01070
01071   if ( (i == endi) && (lister != NULL)) {
01072     lister->print_no_segments();
01073   }
01074
01075   while ( i != endi ) {
01076     if ( i.semaphore() != 0 ) {
01077       // a semaphore has been assigned, destroy!
01078       SemaphoreSet::destroy(i.semaphore());
01079     }
01080
01081     // Mark shared memory segment as destroyed
01082     shmctl(i.shmid(), IPC_RMID, NULL);
01083
01084     if ( lister != NULL) {
01085       lister->print_info(*i, i.shmid(), i.semaphore(), i.segmsize(),
01086                          i.databuf());
01087     }
01088
01089     ++i;
01090   }
01091
01092   if (lister != NULL) lister->print_footer();
01093 }
01094
01095 
01096 /** Erase orphaned (attach count = 0) shared memory segments of a given type.
01097  * This method erases (destroys) all shared memory segments that match the
01098  * given magic token (first MagicTokenSize bytes, filled with zero) and the
01099  * given header and where no process is attached to. If a semaphore has been
01100  * assigned to this shared memory segment it is destroyed as well.
01101  * The lister is called to format the output.
01102  * @param magic_token Token to look for
01103  * @param header      header to identify interesting segments with matching
01104  *                    magic_token
01105  * @param lister      Lister used to format output, maybe NULL (default)
01106  */
01107 void
01108 SharedMemory::erase_orphaned(const char *magic_token,
01109                              SharedMemoryHeader *header, SharedMemoryLister *lister)
01110 {
01111
01112   if (lister != NULL) lister->print_header();
01113
01114   SharedMemoryIterator i = find(magic_token, header);
01115   SharedMemoryIterator endi = end();
01116
01117   if ( (i == endi) && (lister != NULL)) {
01118     lister->print_no_segments();
01119   }
01120
01121   unsigned int num_segments = 0;
01122
01123   while ( i != endi ) {
01124
01125     if ( i.segmnattch() == 1 ) {
01126       // only iterator attached
01127       if ( i.semaphore() != 0 ) {
01128         // a semaphore has been assigned, destroy!
01129         SemaphoreSet::destroy(i.semaphore());
01130       }
01131
01132       // Mark shared memory segment as destroyed
01133       shmctl(i.shmid(), IPC_RMID, NULL);
01134
01135       if ( lister != NULL) {
01136         lister->print_info(*i, i.shmid(), i.semaphore(), i.segmsize(),
01137                            i.databuf());
01138       }
01139
01140       ++num_segments;
01141     }
01142     ++i;
01143   }
01144
01145   if ( (num_segments == 0) && (lister != NULL) ) {
01146     lister->print_no_orphaned_segments();
01147   }
01148
01149   if (lister != NULL) lister->print_footer();
01150 }
01151
01152 
01153 /** Check if a specific shared memory segment exists.
01154  * This method will search for a memory chunk that matches the given magic
01155  * token and header.
01156  * @param magic_token Token to look for
01157  * @param header      header to identify interesting segments with matching
01158  *                    magic_token
01159  * @return true, if a matching shared memory segment was found, else
01160  * otherwise
01161  */
01162 bool
01163 SharedMemory::exists(const char *magic_token,
01164                      SharedMemoryHeader *header)
01165 {
01166   return (find(magic_token, header) != end());
01167 }
01168
01169 
01170 /** Find SharedMemory segments.
01171  * Find SharedMemory segments identified by the supplied magic_token and header.
01172  * @param magic_token magic token
01173  * @param header shared memory header
01174  * @return iterator pointing to the first found element (or end() if none found)
01175  */
01176 SharedMemory::SharedMemoryIterator
01177 SharedMemory::find(const char *magic_token, SharedMemoryHeader *header)
01178 {
01179   return SharedMemoryIterator(magic_token, header);
01180 }
01181
01182 
01183 /** Get invalid iterator.
01184  * Returns an iterator to a non-existing element.
01185  * @return Non-existing element
01186  */
01187 SharedMemory::SharedMemoryIterator
01188 SharedMemory::end()
01189 {
01190   return SharedMemoryIterator();
01191 }
01192
01193 
01194 /** @class SharedMemory::SharedMemoryIterator <utils/ipc/shm.h>
01195  * Shared Memory iterator.
01196  * This iterator is used to iterate over shared memory segments which satisfy some
01197  * criterion. Use SharedMemory::find() and SharedMemory::list() to get the iterator.
01198  * @author Tim Niemueller
01199  */
01200 
01201 /** Constructor.
01202  * Constructs invalid iterator.
01203  */
01204 SharedMemory::SharedMemoryIterator::SharedMemoryIterator()
01205 {
01206   __magic_token = NULL;
01207   __cur_shmid   = -1;
01208   __cur_id      = -1;
01209   __header      = NULL;
01210   __shm_buf     = NULL;
01211   __segmsize    = 0;
01212   __segmnattch  = 0;
01213
01214   struct shmid_ds shm_info;
01215   __max_id = shmctl( 0, SHM_INFO, &shm_info );
01216 }
01217
01218 
01219 /** Copy constructor.
01220  * @param shmit shared memory iterator to copy
01221  */
01222 SharedMemory::SharedMemoryIterator::SharedMemoryIterator(const SharedMemoryIterator &shmit)
01223 {
01224   __max_id = shmit.__max_id;
01225   __header = shmit.__header->clone();
01226   __cur_id = shmit.__cur_id;
01227   __cur_shmid = shmit.__cur_shmid;
01228   __shm_buf = NULL;
01229   __segmsize    = 0;
01230   __segmnattch  = 0;
01231
01232   if ( shmit.__magic_token == NULL ) {
01233     __magic_token = NULL;
01234   } else {
01235     __magic_token = strdup(shmit.__magic_token);
01236   }
01237
01238   if ( shmit.__shm_buf != (void *)-1 ) {
01239     // other iterator is attach, attach as well
01240     try {
01241       attach();
01242     } catch (Exception &e) {
01243       // ignore
01244     }
01245   }
01246 }
01247
01248 
01249 /** Constructor.
01250  * @param magic_token magic token
01251  * @param header shared memory header
01252  */
01253 SharedMemory::SharedMemoryIterator::SharedMemoryIterator(const char *magic_token,
01254                                                          SharedMemoryHeader *header)
01255 {
01256   __magic_token = strdup(magic_token);
01257   __header = header->clone();
01258   __cur_id = -1;
01259   __cur_shmid = -1;
01260   __shm_buf = (void *)-1;
01261   __segmsize    = 0;
01262   __segmnattch  = 0;
01263
01264   struct shmid_ds shm_info;
01265   __max_id = shmctl( 0, SHM_INFO, &shm_info );
01266
01267   // Find first shm segment
01268   ++(*this);
01269 }
01270
01271 
01272 /** Destructor. */
01273 SharedMemory::SharedMemoryIterator::~SharedMemoryIterator()
01274 {
01275   delete __header;
01276   if ( __shm_buf != (void *)-1 ) {
01277     shmdt(__shm_buf);
01278     __shm_buf = (void *)-1;
01279   }
01280   if ( __magic_token ) ::free(__magic_token);
01281 }
01282
01283 
01284 /** Attach. */
01285 void
01286 SharedMemory::SharedMemoryIterator::attach()
01287 {
01288   struct shmid_ds  shm_segment;
01289
01290   // Check if segment exists and get info
01291   __cur_shmid = shmctl( __cur_id, SHM_STAT, &shm_segment );
01292   if ( __cur_shmid < 0 ) {
01293     throw ShmCouldNotAttachException("SharedMemoryIterator could not stat");
01294   }
01295
01296   /* Could be done, since we probably want to list destroyed segments we don't do it here
01297   // check if segment has not been destroyed
01298   if ( shm_segment.shm_perm.mode & SHM_DEST ) {
01299     throw ShmCouldNotAttachException("SharedMemoryIterator: Segment already destroyed");
01300   }
01301   */
01302
01303   // actually attach
01304   __shm_buf = shmat(__cur_shmid, NULL, SHM_RDONLY);
01305   if (__shm_buf == (void *)-1) {
01306     throw ShmCouldNotAttachException("SharedMemoryIterator could not attach");
01307   }
01308
01309   // do STAT again to get up2date values
01310   __cur_shmid = shmctl( __cur_id, SHM_STAT, &shm_segment );
01311   if ( __cur_shmid < 0 ) {
01312     shmdt(__shm_buf);
01313     throw ShmCouldNotAttachException("SharedMemoryIterator could not stat (2)");
01314   }
01315
01316   __segmsize   = shm_segment.shm_segsz;
01317   __segmnattch = shm_segment.shm_nattch;
01318 }
01319
01320 
01321 /** Reset. */
01322 void
01323 SharedMemory::SharedMemoryIterator::reset()
01324 {
01325   if ( __header) __header->reset();
01326   if ( __shm_buf != (void *)-1) {
01327     shmdt(__shm_buf);
01328     __shm_buf = (void *)-1;
01329   }
01330   __data_buf   = NULL;
01331   __semaphore  = -1;
01332   __cur_shmid  = -1;
01333   __segmsize   = 0;
01334   __segmnattch = 0;
01335 }
01336
01337 
01338 /** Prefix increment.
01339  * @return reference to this instance
01340  */
01341 SharedMemory::SharedMemoryIterator &
01342 SharedMemory::SharedMemoryIterator::operator++()
01343 {
01344   reset();
01345   if (__max_id >= 0) {
01346     for (++__cur_id ;__cur_id <= __max_id; ++__cur_id ) {
01347       try {
01348         attach();
01349
01350         const char            *shm_magic_token = (char *)__shm_buf;
01351         SharedMemory_header_t *shm_header = (SharedMemory_header_t *)((char *)__shm_buf + MagicTokenSize);
01352
01353         if ( (strncmp(shm_magic_token, __magic_token, MagicTokenSize) == 0) &&
01354              ( !__header || __header->matches( (char *)__shm_buf + MagicTokenSize
01355                                                + sizeof(SharedMemory_header_t)) ) ) {
01356           // Found one!
01357           __semaphore = shm_header->semaphore;
01358           __data_buf = (char *)__shm_buf + MagicTokenSize
01359                                          + sizeof(SharedMemory_header_t)
01360                                          + (__header ? __header->size() : 0);
01361
01362           if ( __header ) {
01363             __header->set((char *)__shm_buf + MagicTokenSize
01364                           + sizeof(SharedMemory_header_t));
01365           }
01366
01367           break;
01368         } else {
01369           reset();
01370         }
01371       } catch (ShmCouldNotAttachException &e) {
01372         // ignore
01373       }
01374     }
01375     if ( __cur_id > __max_id ) {
01376       // did not find anything
01377       reset();
01378     }
01379   }
01380
01381   return *this;
01382 }
01383
01384 
01385 /** Postfix increment operator.
01386  * @param inc ignored
01387  * @return instance before advancing to the next shared memory segment
01388  */
01389 SharedMemory::SharedMemoryIterator
01390 SharedMemory::SharedMemoryIterator::operator++(int inc)
01391 {
01392   SharedMemoryIterator rv(*this);
01393   ++(*this);
01394   return rv;
01395 }
01396
01397 
01398 /** Advance by i steps.
01399  * @param i number of (matching) segments to advance.
01400  * @return reference to this after advancing
01401  */
01402 SharedMemory::SharedMemoryIterator &
01403 SharedMemory::SharedMemoryIterator::operator+(unsigned int i)
01404 {
01405   for (unsigned int j = 0; j < i; ++j) {
01406     ++(*this);
01407   }
01408   return *this;
01409 }
01410
01411 
01412 /** Advance by i steps.
01413  * @param i number of (matching) segments to advance.
01414  * @return reference to this after advancing
01415  */
01416 SharedMemory::SharedMemoryIterator &
01417 SharedMemory::SharedMemoryIterator::operator+=(unsigned int i)
01418 {
01419   for (unsigned int j = 0; j < i; ++j) {
01420     ++(*this);
01421   }
01422   return *this;
01423 }
01424
01425 
01426 /** Check iterators for equality.
01427  * @param s iterator to compare to
01428  * @return true if iterators point to the same shared memory segment, false otherwise
01429  */
01430 bool
01431 SharedMemory::SharedMemoryIterator::operator==(const SharedMemoryIterator & s) const
01432 {
01433   return (__cur_shmid == s.__cur_shmid);
01434 }
01435
01436 
01437 /** Check iterators for inequality.
01438  * @param s iterator to compare to
01439  * @return true if iteraters point to the same shared memory segment, false otherwise
01440  */
01441 bool
01442 SharedMemory::SharedMemoryIterator::operator!=(const SharedMemoryIterator & s) const
01443 {
01444   return ! (*this == s);
01445 }
01446
01447 
01448 /** Get SharedMemoryHeader.
01449  * @return shared memory header
01450  */
01451 const SharedMemoryHeader *
01452 SharedMemory::SharedMemoryIterator::operator*() const
01453 {
01454   return __header;
01455 }
01456
01457 
01458 /** Make this instance point to the same segment as shmit.
01459  * @param shmit shared memory iterator
01460  * @return reference to this instance
01461  */
01462 SharedMemory::SharedMemoryIterator &
01463 SharedMemory::SharedMemoryIterator::operator=(const SharedMemoryIterator & shmit)
01464 {
01465   if ( __shm_buf != (void *)-1 ) {
01466     shmdt(__shm_buf);
01467     __shm_buf = (void *)-1;
01468   }
01469   delete __header;
01470
01471   __max_id = shmit.__max_id;
01472   __header = shmit.__header->clone();
01473   __cur_id = shmit.__cur_id;
01474   __cur_shmid = shmit.__cur_shmid;
01475   __shm_buf = NULL;
01476
01477   if ( shmit.__magic_token == NULL ) {
01478     __magic_token = NULL;
01479   } else {
01480     __magic_token = strdup(shmit.__magic_token);
01481   }
01482
01483   if ( shmit.__shm_buf != (void *)-1 ) {
01484     // other iterator is attach, attach as well
01485     attach();
01486   }
01487
01488   return *this;
01489 }
01490
01491 
01492 /** Get magic token.
01493  * @return magic token.
01494  */
01495 const char *
01496 SharedMemory::SharedMemoryIterator::magic_token() const
01497 {
01498   return __magic_token;
01499 }
01500
01501 
01502 /** Get shared memory ID.
01503  * @return shared memory ID
01504  */
01505 int
01506 SharedMemory::SharedMemoryIterator::shmid() const
01507 {
01508   return __cur_shmid;
01509 }
01510
01511 
01512 /** Get semaphore.
01513  * @return semaphore
01514  */
01515 int
01516 SharedMemory::SharedMemoryIterator::semaphore() const
01517 {
01518   return __semaphore;
01519 }
01520
01521 
01522 /** Get segment size.
01523  * @return segment size
01524  */
01525 size_t
01526 SharedMemory::SharedMemoryIterator::segmsize() const
01527 {
01528   return __segmsize;
01529 }
01530
01531 
01532 /** Get number of attached parties.
01533  * @return number of attached parties
01534  */
01535 size_t
01536 SharedMemory::SharedMemoryIterator::segmnattch() const
01537 {
01538   return __segmnattch;
01539 }
01540
01541 
01542 /** Get pointer to data buffer.
01543  * @return data buffer
01544  */
01545 void *
01546 SharedMemory::SharedMemoryIterator::databuf() const
01547 {
01548   return __data_buf;
01549 }
01550
01551 } // end namespace fawkes