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-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