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