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

Generated on Tue Feb 22 13:32:28 2011 for Fawkes API by  doxygen 1.4.7