Fawkes API
Fawkes Development Version
|
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