Fawkes API  Fawkes Development Version
shm.cpp
1 
2 /***************************************************************************
3  * shm.cpp - shared memory segment
4  *
5  * Created: Thu Jan 12 14:10:43 2006
6  * Copyright 2005-2011 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <sys/ipc.h>
25 #include <sys/shm.h>
26 #include <utils/ipc/semset.h>
27 #include <utils/ipc/shm.h>
28 #include <utils/ipc/shm_exceptions.h>
29 #include <utils/ipc/shm_lister.h>
30 #include <utils/ipc/shm_registry.h>
31 
32 #include <cstdio>
33 #include <cstdlib>
34 #include <cstring>
35 #include <errno.h>
36 #include <limits.h>
37 
38 namespace fawkes {
39 
40 /** @class SharedMemoryHeader <utils/ipc/shm.h>
41  * Interface for shared memory header.
42  * This class has to be implemented to be able to use shared memory segments.
43  * It defines a set of properties for the shared memory segment that can be
44  * searched for and printed out by an appropriate lister.
45  *
46  * @see SharedMemory
47  * @see SharedMemoryLister
48  * @ingroup IPC
49  * @author Tim Niemueller
50  *
51  *
52  * @fn SharedMemoryHeader::~SharedMemoryHeader()
53  * Virtual destructor
54  *
55  * @fn bool SharedMemoryHeader::matches(void *memptr)
56  * Method to check if the given memptr matches this header.
57  * This method is called when searching for a shared memory segment to
58  * open, list or erase it.
59  * Implement this to distuinguish several shared memory segments that share
60  * the same magic token.
61  * @param memptr The memory chunk in the shared memory segment where to start
62  * checking.
63  * @return true, if the given data in the memory chunk matches this header, false
64  * otherwise.
65  *
66  * @fn unsigned int SharedMemoryHeader::size()
67  * Size of the header.
68  * The size that is needed in the shared memory memptr to accomodate the
69  * header data. This size has to fit all the data that will be stored in the
70  * header. It must return the same size every time.
71  * @return size of header
72  *
73  * @fn void SharedMemoryHeader::initialize(void *memptr)
74  * Initialize the header.
75  * This should initialize the header data in the given memptr from the
76  * data of this SharedMemoryHeader derivate instance. It has to write out
77  * all state information that is needed to identify the shared memory
78  * segment later on.
79  * @param memptr the memptr where the header data shall be written to.
80  *
81  * @fn void SharedMemoryHeader::set(void *memptr)
82  * Set information from memptr.
83  * Set the information stored in this SharedMemoryHeader derivate instance
84  * from the data stored in the given memptr.
85  * @param memptr The memptr where to copy data from.
86  *
87  * @fn void SharedMemoryHeader::reset()
88  * Reset information previously set with set().
89  * This shall restore the state the header had before set() was called. This is
90  * used for instance in the SharedMemoryLister after info about one segment
91  * has been printed.
92  *
93  * @fn size_t SharedMemoryHeader::data_size()
94  * Return the size of the data.
95  * The size of the data that will be stored in the shared memory segment.
96  * This method has to return the same value everytime and may only depend
97  * on the other data set in the header and written to the shared memory
98  * segment.
99  * @return the size of the data segment
100  *
101  * @fn SharedMemoryHeader * SharedMemoryHeader::clone() const
102  * Clone this shared memory header.
103  * This method shall return a copied instance of this SharedMemoryHeader derivate.
104  * It should act the same way as the current instance.
105  * @return Clone instance. Remember to delete the instance.
106  *
107  * @fn bool SharedMemoryHeader::operator==(const SharedMemoryHeader &s) const
108  * Check for equality of headers.
109  * This shall be implemented that it compares the current and the given instances
110  * for equality. You probably want to use dynamic_cast to cast the given instance
111  * to a compatible type.
112  * @param s shared memory header to compare to
113  * @return true if the two instances identify the very same shared memory segments,
114  * false otherwise
115  */
116 
117 /** @class SharedMemory <utils/ipc/shm.h>
118  * Shared memory segment.
119  * This class gives access to shared memory segment to store arbitrary data.
120  * With shared memory data can be shared between several applications. Special
121  * means like semaphores have to be used to control access to the storage
122  * to prevent data corruption.
123  *
124  * The shared memory segment is divided into three parts.
125  * 1. General shared memory header
126  * 2. Data-specific header
127  * 3. Data
128  *
129  * The general header consists of a magic token of MagicTokenSize that is used
130  * to find the basically compatible shared memory segments out of all existing
131  * shared memory segments. This is done for convenience. Although in general
132  * shared memory is accessed via keys or IDs it is easier from the maintenance
133  * side to just scan the segments to find the correct one, especially if there
134  * may be more than just one segment for the same application.
135  * The header also includes a semaphore ID which is unused at the moment.
136  *
137  * The data-specific header is generated from a given SharedMemoryHeader
138  * implementation. It can be used to store any information that is needed to
139  * identify a specific shared memory segment and to store management data for
140  * the data segment. It should always contain enough information to derive
141  * the data segment size or if needed an explicit information about the memory
142  * size.
143  *
144  * The data segment can be filled with any data you like.
145  *
146  * Shared memory segments are protected with a read-write lock implemented with
147  * two IPC semaphores. The writer takes preference in locking. Only a limited
148  * number of concurrent readers can be allowed. The constant
149  * MaxNumberConcurrentReaders defines how many these are.
150  * If a shared memory segment already has a semaphore assigned at the time it
151  * is opened this semaphore is automatically opened. In any case add_semaphore()
152  * can be used to create (or open if it already exists) a semaphore for the
153  * shared memory segment. Information about the semaphore is stored in the
154  * shared memory general header.
155  *
156  * This class provides utilities to list, erase and check existence of given
157  * shared memory segments. For this often a SharedMemoryLister is used that
158  * takes care of formatting the output of the specific information about the
159  * shared memory segment.
160  *
161  * @see SharedMemoryHeader
162  * @see SharedMemorySegment
163  * @see qa_shmem.cpp
164  * @ingroup IPC
165  *
166  * @author Tim Niemueller
167  */
168 
169 /** @var SharedMemory::_memptr
170  * Pointer to the data segment.
171  */
172 /** @var SharedMemory::_mem_size
173  * Total size of the segment, including headers
174  */
175 /** @fn SharedMemory::_data_size
176  * Size of the data segment only
177  */
178 /** @var SharedMemory::_header
179  * Data-specific header
180  */
181 /** @var SharedMemory::_is_read_only
182  * Read-only.
183  * if true before attach() open segment read-only
184  */
185 /** @var SharedMemory::_destroy_on_delete
186  * destroy on delete.
187  * If true before free() segment is destroyed.
188  */
189 /** @var SharedMemory::_should_create
190  * Create shared memory segment.
191  * If true before attach shared memory segment is created if it does
192  * not exist.
193  */
194 /** @var SharedMemory::_magic_token
195  * Magic token
196  */
197 /** @var SharedMemory::_shm_magic_token
198  * Magic token as stored in the shared memory segment
199  */
200 /** @var SharedMemory::_shm_header
201  * general header as stored in the shared memory segment
202  */
203 /** @var SharedMemory::_shm_upper_bound
204  * Upper bound of memory. Used by ptr to determine if the given address is valid.
205  */
206 /** @var SharedMemory::_shm_offset
207  * Offset to the master's base addr.
208  */
209 
210 /** The magic token size.
211  * Your magic token identifier may have an arbitrary size. It is truncated
212  * at MagicTokenSize bytes or filled with zeros up to a length of
213  * MagicTokenSize bytes.
214  */
215 const unsigned int SharedMemory::MagicTokenSize = MAGIC_TOKEN_SIZE;
216 
217 /** Maximum number of concurrent readers.
218  * This constant defines how many readers may concurrently read from
219  * shared memory segments.
220  */
222 
223 #define WRITE_MUTEX_SEM 0
224 #define READ_SEM 1
225 
226 /** Constructor for derivates.
227  * This constructor may only be used by derivatives. It can be used to delay
228  * the call to attach() to do other preparations like creating a
229  * SharedMemoryHeader object.
230  * @param magic_token magic token of the shared memory segment
231  * @param is_read_only if true the shared memory segment is opened in
232  * read-only mode
233  * @param create if true the shared memory segment is created if
234  * no one matching the headers was found
235  * @param destroy_on_delete if true the shared memory segment is destroyed
236  * when this SharedMemory instance is deleted.
237  * @param registry_name name of the SharedMemoryRegistry to use
238  */
239 SharedMemory::SharedMemory(const char *magic_token,
240  bool is_read_only,
241  bool create,
242  bool destroy_on_delete,
243  const char *registry_name)
244 {
245  _magic_token = new char[MagicTokenSize];
246  memset(_magic_token, 0, MagicTokenSize);
247  strncpy(_magic_token, magic_token, MagicTokenSize);
248 
250  _destroy_on_delete = destroy_on_delete;
251  _should_create = create;
252 
253  _memptr = NULL;
254  _shm_magic_token = NULL;
255  _shm_header = NULL;
256  _header = NULL;
257  _data_size = 0;
258 
259  semset_ = NULL;
260  created_ = false;
261  shared_mem_ = NULL;
262  shared_mem_id_ = 0;
263  shared_mem_upper_bound_ = NULL;
264 
265  write_lock_aquired_ = false;
266 
267  registry_name_ = NULL;
268 
269  if (registry_name) {
270  registry_name_ = strdup(registry_name);
271  }
272  shm_registry_ = new SharedMemoryRegistry(registry_name);
273 }
274 
275 /** Copy constructor.
276  * If the given SharedMemory was attached this instance will also attach.
277  * @param s SharedMemory instance to copy.
278  */
280 {
281  _magic_token = new char[MagicTokenSize];
282  memset(_magic_token, 0, MagicTokenSize);
284 
288 
289  _memptr = NULL;
290  _shm_magic_token = NULL;
291  _shm_header = NULL;
292  _header = s._header->clone();
293  _data_size = 0;
294 
295  semset_ = NULL;
296  created_ = false;
297  shared_mem_ = NULL;
298  shared_mem_id_ = 0;
299  shared_mem_upper_bound_ = NULL;
300 
301  write_lock_aquired_ = false;
302  if (s.registry_name_) {
303  registry_name_ = strdup(s.registry_name_);
304  } else {
305  registry_name_ = NULL;
306  }
307 
308  try {
309  attach();
310  } catch (Exception &e) {
311  e.append("SharedMemory public copy constructor");
312  throw;
313  }
314 
315  if (_memptr == NULL) {
316  throw ShmCouldNotAttachException("Could not attach to created shared memory segment");
317  }
318 
319  shm_registry_ = new SharedMemoryRegistry(registry_name_);
320 }
321 
322 /** Create a new shared memory segment.
323  * This will open a shared memory segment that exactly fits the given
324  * SharedMemoryHeader. It the segment does not exist and create is assured
325  * the segment is created from the given data, otherwise the SharedMemory
326  * instance remains in an invalid state and an exception is thrown.
327  * The segment can be destroyed automatically if the instance is destroyed.
328  * Shared memory segments can be opened read-only.
329  * @param magic_token This is the magic token discussed above that is used
330  * to identify the shared memory segment. The magic_token
331  * can be of arbitrary size but at most MagicTokenSize
332  * bytes are used.
333  * @param header The data-sepcific header used for this shared memory
334  * segment
335  * @param is_read_only if true the shared memory segment is opened in
336  * read-only mode
337  * @param create if true the shared memory segment is created if
338  * no one matching the headers was found
339  * @param destroy_on_delete if true the shared memory segment is destroyed
340  * when this SharedMemory instance is deleted.
341  * @param registry_name name of the SharedMemoryRegistry to use
342  * @exception ShmNoHeaderException No header has been set
343  * @exception ShmInconsistentSegmentSizeException The memory size is not the
344  * expected memory size
345  * @exception ShmCouldNotAttachException Could not attach to shared
346  * memory segment
347  */
348 SharedMemory::SharedMemory(const char * magic_token,
349  SharedMemoryHeader *header,
350  bool is_read_only,
351  bool create,
352  bool destroy_on_delete,
353  const char * registry_name)
354 {
355  _magic_token = new char[MagicTokenSize];
356  memset(_magic_token, 0, MagicTokenSize);
357  strncpy(_magic_token, magic_token, MagicTokenSize);
358 
359  _header = header;
361  _destroy_on_delete = destroy_on_delete;
362  _should_create = create;
363 
364  _memptr = NULL;
365  _shm_magic_token = NULL;
366  _shm_header = NULL;
367  _data_size = 0;
368 
369  created_ = false;
370  semset_ = NULL;
371  shared_mem_ = NULL;
372  shared_mem_id_ = 0;
373  shared_mem_upper_bound_ = NULL;
374 
375  write_lock_aquired_ = false;
376 
377  registry_name_ = NULL;
378  if (registry_name) {
379  registry_name_ = strdup(registry_name);
380  }
381 
382  try {
383  attach();
384  } catch (Exception &e) {
385  e.append("SharedMemory public constructor");
386  throw;
387  }
388 
389  if (_memptr == NULL) {
390  throw ShmCouldNotAttachException("Could not attach to created shared memory segment");
391  }
392 
393  shm_registry_ = new SharedMemoryRegistry(registry_name_);
394 }
395 
396 /** Destructor */
398 {
399  if (semset_ != NULL) {
400  // if we destroy the shared memory region we can as well delete the semaphore,
401  // it is not necessary anymore.
404  _shm_header->semaphore = 0;
405  }
406  delete semset_;
407  }
408  delete[] _magic_token;
409  free();
410  delete shm_registry_;
411  if (registry_name_)
412  ::free(registry_name_);
413 }
414 
415 /** Assignment operator.
416  * If the given SharedMemory was attached, this instance will also attach.
417  * @param s SharedMemory instance to copy from
418  * @return reference to this instance
419  */
420 SharedMemory &
422 {
423  if (semset_ != NULL) {
424  // if we destroy the shared memory region we can as well delete the semaphore,
425  // it is not necessary anymore.
428  _shm_header->semaphore = 0;
429  }
430  delete semset_;
431  }
432  delete[] _magic_token;
433  free();
434  delete shm_registry_;
435  if (registry_name_)
436  ::free(registry_name_);
437 
438  _magic_token = new char[MagicTokenSize];
439  memset(_magic_token, 0, MagicTokenSize);
441 
445 
446  _memptr = NULL;
447  _shm_magic_token = NULL;
448  _shm_header = NULL;
449  _header = s._header->clone();
450  _data_size = 0;
451 
452  semset_ = NULL;
453  created_ = false;
454  shared_mem_ = NULL;
455  shared_mem_id_ = 0;
456  shared_mem_upper_bound_ = NULL;
457 
458  write_lock_aquired_ = false;
459  if (s.registry_name_) {
460  registry_name_ = strdup(s.registry_name_);
461  } else {
462  registry_name_ = NULL;
463  }
464 
465  try {
466  attach();
467  } catch (Exception &e) {
468  e.append("SharedMemory public copy constructor");
469  throw;
470  }
471 
472  if (_memptr == NULL) {
473  throw ShmCouldNotAttachException("Could not attach to created shared memory segment");
474  }
475 
476  shm_registry_ = new SharedMemoryRegistry(registry_name_);
477 
478  return *this;
479 }
480 
481 /** Detach from and maybe destroy the shared memory segment.
482  * This will detach from the shared memory segment. If destroy_on_delete is
483  * true this will destroy the shared memory segment before detaching.
484  */
485 void
487 {
488  _memptr = NULL;
489  _shm_header = NULL;
490  _shm_magic_token = NULL;
491 
492  if ((shared_mem_id_ != -1) && !_is_read_only && _destroy_on_delete) {
493  shmctl(shared_mem_id_, IPC_RMID, NULL);
494  shm_registry_->remove_segment(shared_mem_id_);
495  shared_mem_id_ = -1;
496  }
497  if (shared_mem_ != NULL) {
498  shmdt(shared_mem_);
499  shared_mem_ = NULL;
500  }
501 }
502 
503 /** Attach to the shared memory segment.
504  * This method will try to open and/or create the shared memory segment.
505  * @exception ShmNoHeaderException No header has been set
506  * @exception ShmInconsistentSegmentSizeException The memory size is not the
507  * expected memory size
508  * @exception ShmCouldNotAttachException Could not attach to shared
509  * memory segment
510  */
511 void
513 {
514  if (_header == NULL) {
515  // No shared memory header, needed!
516  throw ShmNoHeaderException();
517  }
518 
519  if ((_memptr != NULL) && (shared_mem_id_ != -1)) {
520  // a memptr has already been attached
521  return;
522  }
523 
524  std::list<SharedMemoryRegistry::SharedMemID> segments =
525  shm_registry_->find_segments(_magic_token);
526 
527  std::list<SharedMemoryRegistry::SharedMemID>::iterator s;
528 
529  void * shm_buf;
530  void * shm_ptr;
531  struct shmid_ds shm_segment;
532 
533  for (s = segments.begin(); (_memptr == NULL) && (s != segments.end()); ++s) {
534  if (shmctl(s->shmid, IPC_STAT, &shm_segment) < 0)
535  continue;
536 
537  shm_buf = shmat(s->shmid, NULL, _is_read_only ? SHM_RDONLY : 0);
538  if (shm_buf != (void *)-1) {
539  _shm_magic_token = (char *)shm_buf;
540  _shm_header = (SharedMemory_header_t *)((char *)shm_buf + MagicTokenSize);
541 
542  shm_ptr = (char *)shm_buf + MagicTokenSize + sizeof(SharedMemory_header_t);
543 
544  if (_header->matches(shm_ptr)) {
545  // matching memory segment found
546 
547  _header->set(shm_ptr);
550 
551  if (_mem_size != (unsigned int)shm_segment.shm_segsz) {
552  throw ShmInconsistentSegmentSizeException(_mem_size, (unsigned int)shm_segment.shm_segsz);
553  }
554 
555  shared_mem_id_ = s->shmid;
556  shared_mem_ = shm_buf;
557  shared_mem_upper_bound_ = (void *)((size_t)shared_mem_ + _mem_size);
558  _shm_upper_bound = (void *)((size_t)_shm_header->shm_addr + _mem_size);
559  _memptr = (char *)shm_ptr + _header->size();
560  _shm_offset = (size_t)shared_mem_ - (size_t)_shm_header->shm_addr;
561 
562  if (_shm_header->semaphore != 0) {
563  // Houston, we've got a semaphore, open it!
564  add_semaphore();
565  }
566 
567  } else {
568  // not the wanted memory segment
569  shmdt(shm_buf);
570  }
571  } // else could not attach, ignore
572  }
573 
574  if ((_memptr == NULL) && !_is_read_only && _should_create) {
575  // try to create a new shared memory segment
576  created_ = true;
577  key_t key = 1;
578 
581  while ((_memptr == NULL) && (key < INT_MAX)) {
582  // no shm segment found, create one
583  shared_mem_id_ = shmget(key, _mem_size, IPC_CREAT | IPC_EXCL | 0666);
584  if (shared_mem_id_ != -1) {
585  shared_mem_ = shmat(shared_mem_id_, NULL, 0);
586  if (shared_mem_ != (void *)-1) {
587  memset(shared_mem_, 0, _mem_size);
588 
589  _shm_magic_token = (char *)shared_mem_;
590  _shm_header = (SharedMemory_header_t *)((char *)shared_mem_ + MagicTokenSize);
591  _shm_header->shm_addr = shared_mem_;
592 
593  _memptr =
594  (char *)shared_mem_ + MagicTokenSize + sizeof(SharedMemory_header_t) + _header->size();
595  _shm_upper_bound = (void *)((size_t)shared_mem_ + _mem_size);
596  _shm_offset = 0;
597  shared_mem_upper_bound_ = _shm_upper_bound;
598 
600 
601  _header->initialize((char *)shared_mem_ + MagicTokenSize + sizeof(SharedMemory_header_t));
602  } else {
603  // It didn't work out, destroy shared mem and try again
604  shmctl(shared_mem_id_, IPC_RMID, NULL);
605  throw ShmCouldNotAttachException("Could not create shared memory segment");
606  }
607  } else {
608  if (errno == EEXIST) {
609  // non-free key number, try next one
610  // note: we don't care about existing shared memory regions as we scanned
611  // them before already!
612  ++key;
613  } else if (errno == EINVAL) {
614  throw ShmCouldNotAttachException("Could not attach, segment too small or too big");
615  } else {
616  throw ShmCouldNotAttachException("Could not attach, shmget failed");
617  }
618  }
619  }
620  }
621 
622  if (_memptr == NULL) {
623  throw ShmCouldNotAttachException("Could not attach to shared memory segment");
624  }
625 
626  try {
627  shm_registry_->add_segment(shared_mem_id_, _magic_token);
628  } catch (Exception &e) {
629  free();
630  throw;
631  }
632 }
633 
634 /** Get the real pointer to the data based on an address.
635  * If there is address-dependent data in the shared memory segment (like pointers
636  * to the next element in a linked list) these are only valid for the process
637  * that created the shared memory segment, they are not necessarily valid for
638  * other processes.
639  *
640  * The function takes an address that has been stored in the
641  * shared memory segment and transforms it into a valid local pointer.
642  * Not that this does only work with pointers inside the shared memory segment.
643  * You can only tranform addresses that point to somewhere inside the shared
644  * memory segment!
645  *
646  * We could also have added local offsets, starting with 0 at the beginning
647  * of the shared memory segment. We decided against this since our major our
648  * main concern is that this works fast for the master, because this will be the
649  * Fawkes main application, and for attached processes it may work slower and
650  * we don't care.
651  *
652  * @param addr memory address read from the shared memory segment
653  * @return pointer inside the shared memory segment
654  * @exception ShmAddrOutOfBoundsException This exception is thrown if addr is not NULL,
655  * smaller than the base addr and greater or equal to the base addr plus the memory size.
656  * @see addr()
657  */
658 void *
659 SharedMemory::ptr(void *addr) const
660 {
661  if (_shm_offset == 0)
662  return addr;
663  if (addr == NULL)
664  return NULL;
665  if ((addr < _shm_header->shm_addr) || (addr >= _shm_upper_bound)) {
667  }
668  return (void *)((size_t)addr + _shm_offset);
669 }
670 
671 /** Get an address from a real pointer.
672  * If there is address-dependent data in the shared memory segment (like pointers
673  * to the next element in a linked list) these are only valid for the process
674  * that created the shared memory segment, they are not necessarily valid for
675  * other processes.
676  *
677  * This method takes a pointer that points to data in the shared memory segment
678  * that is valid in the local process and transform it to a pointer that is valid
679  * inside the shared memory segment with respect to the base address used by the
680  * creating process.
681  *
682  * @param ptr pointer to data inside the shared memory segment
683  * @return memory address valid for the creator of the shared memory segment
684  * @exception ShmPtrOutOfBoundsException This exception is thrown if ptr is not NULL,
685  * smaller than the local base ptr and greater or equal to the local base ptr plus
686  * the memory size.
687  * @see ptr()
688  */
689 void *
690 SharedMemory::addr(void *ptr) const
691 {
692  if (_shm_offset == 0)
693  return ptr;
694  if (ptr == NULL)
695  return NULL;
696  if ((ptr < shared_mem_) || (ptr >= shared_mem_upper_bound_)) {
698  }
699  return (void *)((size_t)ptr - _shm_offset);
700 }
701 
702 /** Check for read-only mode
703  * @return true, if the segment is opened in read-only mode, false otherwise
704  */
705 bool
707 {
708  return _is_read_only;
709 }
710 
711 /** Determine if the shared memory segment has been created by this instance.
712  * In some situations you want to know if the current instance has created the shared
713  * memory segment or if it attached to an existing shared memory segment. This is
714  * handy for example in master-slave constellations where one process is the master
715  * over a given shared memory segment and other slaves may read but need special
716  * means to alter the data.
717  * This is a somewhat softer variant of exclusive access.
718  * @return true, if this instance of SharedMemory created the segment, false
719  * otherwise
720  */
721 bool
723 {
724  return created_;
725 }
726 
727 /** Get a pointer to the shared memory
728  * This method returns a pointer to the data-segment of the shared memory
729  * segment. It has the size stated as dataSize() from the header.
730  * @return pointer to the data-segment
731  * @see getDataSize()
732  */
733 void *
735 {
736  return _memptr;
737 }
738 
739 /** Get the size of the data-segment.
740  * Use this method to get the size of the data segment. Calls dataSize() of
741  * the data-specific header internally.
742  * @return size of the data-segment in bytes
743  */
744 size_t
746 {
747  return _data_size;
748 }
749 
750 /** Get shared memory ID.
751  * @return shared memory ID
752  */
753 int
755 {
756  return shared_mem_id_;
757 }
758 
759 /** Get number of attached processes.
760  * @return number of attached processes
761  */
762 unsigned int
764 {
765  return num_attached(shared_mem_id_);
766 }
767 
768 /** Copies data from the memptr to shared memory.
769  * Use this method to copy data from the given external memptr to the
770  * data segment of the shared memory.
771  * @param memptr the memptr to copy from
772  */
773 void
774 SharedMemory::set(void *memptr)
775 {
776  memcpy(_memptr, memptr, _data_size);
777 }
778 
779 /** Check if segment has been destroyed
780  * This can be used if the segment has been destroyed. This means that no
781  * other process can connect to the shared memory segment. As long as some
782  * process is attached to the shared memory segment the segment will still
783  * show up in the list
784  * @return true, if this shared memory segment has been destroyed, false
785  * otherwise
786  */
787 bool
789 {
790  return is_destroyed(shared_mem_id_);
791 }
792 
793 /** Check if memory can be swapped out.
794  * This method can be used to check if the memory can be swapped.
795  * @return true, if the memory can be swapped, false otherwise
796  */
797 bool
799 {
800  return is_swapable(shared_mem_id_);
801 }
802 
803 /** Check validity of shared memory segment.
804  * Use this to check if the shared memory segmentis valid. That means that
805  * this instance is attached to the shared memory and data can be read from
806  * or written to the memptr.
807  * @return true, if the shared memory segment is valid and can be utilized,
808  * false otherwise
809  */
810 bool
812 {
813  return (_memptr != NULL);
814 }
815 
816 /** Check if memory segment is protected.
817  * This method can be used to determine if a semaphore has been associated to
818  * this shared memory segment. Locking is not guaranteed, it depends on the
819  * application. Use lock(), tryLock() and unlock() appropriately. You can do
820  * this always, also if you start with unprotected memory. The operations are
821  * just noops in that case. Protection can be enabled by calling add_semaphore().
822  * If a memory segment was protected when it was opened it is automatically
823  * opened in protected mode.
824  * @return true, if semaphore is associated to memory, false otherwise
825  */
826 bool
828 {
829  return (semset_ != NULL);
830 }
831 
832 /** Set deletion behaviour.
833  * This has the same effect as the destroy_on_delete parameter given to the
834  * constructor.
835  * @param destroy set to true to destroy the shared memory segment on
836  * deletion
837  */
838 void
840 {
841  _destroy_on_delete = destroy;
842 }
843 
844 /** Add semaphore to shared memory segment.
845  * This adds a semaphore to the system and puts its key in the shared memory
846  * segment header. The semaphore can then be protected via the semaphore by
847  * appropriate locking. If a semaphore has been assigned to the shared memory
848  * segment already but after the segment was opened the semaphore is opened
849  * and no new semaphore is created.
850  */
851 void
853 {
854  if (semset_ != NULL)
855  return;
856  if (_memptr == NULL)
857  throw Exception("Cannot add semaphore if not attached");
858 
859  if (_shm_header->semaphore != 0) {
860  // a semaphore has been created but not been opened
861  semset_ = new SemaphoreSet(_shm_header->semaphore,
862  /* num sems */ 2,
863  /* create */ false,
864  /* dest on del */ false);
865  } else {
866  // no semaphore exist, create one, but only if shmem is not
867  // opened read-only!
868  if (!_is_read_only) {
869  semset_ = new SemaphoreSet(/* num sems */ 2,
870  /* dest on del */ true);
871  // one and only one (writer) may lock the memory
872  semset_->unlock(WRITE_MUTEX_SEM);
873  // up to MaxNumConcurrentReaders readers can lock the memory
874  semset_->set_value(READ_SEM, MaxNumConcurrentReaders);
875  _shm_header->semaphore = semset_->key();
876  } else {
877  throw Exception("Cannot create semaphore for read-only shmem segment");
878  }
879  }
880 }
881 
882 /** Set shared memory swapable.
883  * Setting memory unswapable (in terms of Linux memory management: lock all
884  * pages related to this memory segment) will only succeed for very small
885  * portions of memory. A resource limit is implied (see getrlimit(2)). In
886  * most cases the maximum amout of locked memory is about 32 KB.
887  * @param swapable set to true, if memory should be allowed to be swaped out.
888  */
889 void
891 {
892 #ifdef USE_MISC_
893  if (swapable) {
894  shmctl(shared_mem_id_, SHM_UNLOCK, NULL);
895  } else {
896  shmctl(shared_mem_id_, SHM_LOCK, NULL);
897  }
898 #endif
899 }
900 
901 /** Lock shared memory segment for reading.
902  * If the shared memory segment is protected by an associated semaphore it can be
903  * locked with this semaphore by calling this method.
904  * @see isProtected()
905  * @see unlock()
906  * @see try_lock_for_read()
907  */
908 void
910 {
911  if (semset_ == NULL) {
912  return;
913  }
914 
915  semset_->lock(READ_SEM);
916  lock_aquired_ = true;
917 }
918 
919 /** Try to aquire lock on shared memory segment for reading.
920  * If the shared memory segment is protected by an associated semaphore it can be
921  * locked. With tryLock() you can try to aquire the lock, but the method will not
922  * block if it cannot get the lock but simply return false. This can be used to detect
923  * if memory is locked:
924  * @code
925  * if (mem->tryLock()) {
926  * // was not locked
927  * mem->unlock();
928  * } else {
929  * // is locked
930  * }
931  * @endcode
932  * @return true if the lock was acquired for reading, false if lock was not acquired.
933  * @see isProtected()
934  * @see unlock()
935  * @see lock()
936  */
937 bool
939 {
940  if (semset_ == NULL)
941  return false;
942 
943  if (semset_->try_lock(READ_SEM)) {
944  lock_aquired_ = true;
945  return true;
946  } else {
947  return false;
948  }
949 }
950 
951 /** Lock shared memory segment for writing.
952  * If the shared memory segment is protected by an associated semaphore it can be
953  * locked with this semaphore by calling this method.
954  * @see is_protected()
955  * @see unlock()
956  * @see try_lock_for_read()
957  */
958 void
960 {
961  if (semset_ == NULL) {
962  return;
963  }
964 
965  semset_->lock(WRITE_MUTEX_SEM);
966  for (short i = 0; i < MaxNumConcurrentReaders; ++i) {
967  semset_->lock(READ_SEM);
968  }
969  write_lock_aquired_ = true;
970  lock_aquired_ = true;
971  semset_->unlock(WRITE_MUTEX_SEM);
972 }
973 
974 /** Try to aquire lock on shared memory segment for writing.
975  * If the shared memory segment is protected by an associated semaphore it can be
976  * locked. With tryLock() you can try to aquire the lock, but the method will not
977  * block if it cannot get the lock but simply return false. This can be used to detect
978  * if memory is locked:
979  * @code
980  * if (mem->tryLock()) {
981  * // was not locked
982  * mem->unlock();
983  * } else {
984  * // is locked
985  * }
986  * @endcode
987  * @return true if the lock was acquired for writing, false if lock was not acquired.
988  * @see isProtected()
989  * @see unlock()
990  * @see lock()
991  */
992 bool
994 {
995  if (semset_ == NULL)
996  return false;
997 
998  if (semset_->try_lock(WRITE_MUTEX_SEM)) {
999  for (short i = 0; i < MaxNumConcurrentReaders; ++i) {
1000  if (!semset_->try_lock(READ_SEM)) {
1001  // we up to now locked i-1 readers, unlock 'em and fail
1002  for (short j = 0; j < i - 1; ++j) {
1003  semset_->unlock(READ_SEM);
1004  }
1005  semset_->unlock(WRITE_MUTEX_SEM);
1006  return false;
1007  }
1008  }
1009  lock_aquired_ = true;
1010  write_lock_aquired_ = true;
1011  semset_->unlock(WRITE_MUTEX_SEM);
1012  return true;
1013  } else {
1014  return false;
1015  }
1016 }
1017 
1018 /** Unlock memory.
1019  * If the shared memory segment is protected by an associated semaphore it can be
1020  * locked. With unlock() you lift the lock on the memory. Be aware that unlocking
1021  * a not-locked piece of memory will result in havoc and insanity! Have only exactly
1022  * guaranteed pairs of lock/successful tryLock() and unlock()!
1023  */
1024 void
1026 {
1027  if (semset_ == NULL || !lock_aquired_)
1028  return;
1029 
1030  if (write_lock_aquired_) {
1031  for (short i = 0; i < MaxNumConcurrentReaders; ++i) {
1032  semset_->unlock(READ_SEM);
1033  }
1034  write_lock_aquired_ = false;
1035  } else {
1036  semset_->unlock(READ_SEM);
1037  }
1038 }
1039 
1040 /* ==================================================================
1041  * STATICs
1042  */
1043 
1044 /** Check if a segment has been destroyed.
1045  * Check for a shared memory segment of the given ID.
1046  * @param shm_id ID of the shared memory segment.
1047  * @return true, if the shared memory segment is marked as destroyed or
1048  * does not exist at all, false otherwise.
1049  */
1050 bool
1052 {
1053  struct shmid_ds shm_segment;
1054 
1055  if (shmctl(shm_id, IPC_STAT, &shm_segment) == -1) {
1056  return true;
1057  } else {
1058 #ifdef USE_MISC_
1059  struct ipc_perm *perm = &shm_segment.shm_perm;
1060  return (perm->mode & SHM_DEST);
1061 #else
1062  return false;
1063 #endif
1064  }
1065 }
1066 
1067 /** Check if memory can be swapped out.
1068  * This method can be used to check if the memory can be swapped.
1069  * @param shm_id ID of the shared memory segment.
1070  * @return true, if the memory can be swapped, false otherwise
1071  */
1072 bool
1074 {
1075 #ifdef USE_MISC_
1076  struct shmid_ds shm_segment;
1077  struct ipc_perm *perm = &shm_segment.shm_perm;
1078 
1079  if (shmctl(shm_id, IPC_STAT, &shm_segment) < 0) {
1080  return true;
1081  } else {
1082  return !(perm->mode & SHM_LOCKED);
1083  }
1084 #else
1085  return true;
1086 #endif
1087 }
1088 
1089 /** Get number of attached processes.
1090  * @param shm_id ID of the shared memory segment.
1091  * @return number of attached processes
1092  */
1093 unsigned int
1095 {
1096  struct shmid_ds shm_segment;
1097 
1098  if (shmctl(shm_id, IPC_STAT, &shm_segment) < 0) {
1099  return 0;
1100  } else {
1101  return shm_segment.shm_nattch;
1102  }
1103 }
1104 
1105 /** List shared memory segments of a given type.
1106  * This method lists all shared memory segments that match the given magic
1107  * token (first MagicTokenSize bytes, filled with zero) and the given
1108  * header. The lister is called to format the output.
1109  * @param magic_token Token to look for
1110  * @param header header to identify interesting segments with matching
1111  * magic_token
1112  * @param lister Lister used to format output
1113  * @param registry_name name of the SharedMemoryRegistry to use
1114  */
1115 void
1116 SharedMemory::list(const char * magic_token,
1117  SharedMemoryHeader *header,
1118  SharedMemoryLister *lister,
1119  const char * registry_name)
1120 {
1121  //printf("Looking for '%s' @ registry '%s'\n", magic_token,
1122  // registry_name ? registry_name : "default");
1123  lister->print_header();
1124  SharedMemoryIterator i = find(magic_token, header, registry_name);
1125  SharedMemoryIterator endi = end();
1126 
1127  if (i == endi) {
1128  lister->print_no_segments();
1129  }
1130 
1131  while (i != endi) {
1132  lister->print_info(*i, i.shmid(), i.semaphore(), i.segmsize(), i.databuf());
1133  ++i;
1134  }
1135 
1136  lister->print_footer();
1137 }
1138 
1139 /** Erase shared memory segments of a given type.
1140  * This method erases (destroys) all shared memory segments that match the
1141  * given magic token (first MagicTokenSize bytes, filled with zero) and the
1142  * given header. The lister is called to format the output. If a semaphore
1143  * has been assigned to this shared memory segment it is destroyed as well.
1144  * @param magic_token Token to look for
1145  * @param header header to identify interesting segments with matching
1146  * magic_token
1147  * @param lister Lister used to format output, maybe NULL (default)
1148  * @param registry_name name of the SharedMemoryRegistry to use
1149  */
1150 void
1151 SharedMemory::erase(const char * magic_token,
1152  SharedMemoryHeader *header,
1153  SharedMemoryLister *lister,
1154  const char * registry_name)
1155 {
1156  if (lister != NULL)
1157  lister->print_header();
1158 
1159  SharedMemoryIterator i = find(magic_token, header, registry_name);
1160  SharedMemoryIterator endi = end();
1161 
1162  if ((i == endi) && (lister != NULL)) {
1163  lister->print_no_segments();
1164  }
1165 
1166  while (i != endi) {
1167  if (i.semaphore() != 0) {
1168  // a semaphore has been assigned, destroy!
1170  }
1171 
1172  // Mark shared memory segment as destroyed
1173  shmctl(i.shmid(), IPC_RMID, NULL);
1174 
1175  if (lister != NULL) {
1176  lister->print_info(*i, i.shmid(), i.semaphore(), i.segmsize(), i.databuf());
1177  }
1178 
1179  ++i;
1180  }
1181 
1182  if (lister != NULL)
1183  lister->print_footer();
1184 }
1185 
1186 /** Erase orphaned (attach count = 0) shared memory segments of a given type.
1187  * This method erases (destroys) all shared memory segments that match the
1188  * given magic token (first MagicTokenSize bytes, filled with zero) and the
1189  * given header and where no process is attached to. If a semaphore has been
1190  * assigned to this shared memory segment it is destroyed as well.
1191  * The lister is called to format the output.
1192  * @param magic_token Token to look for
1193  * @param header header to identify interesting segments with matching
1194  * magic_token
1195  * @param lister Lister used to format output, maybe NULL (default)
1196  * @param registry_name name of the SharedMemoryRegistry to use
1197  */
1198 void
1199 SharedMemory::erase_orphaned(const char * magic_token,
1200  SharedMemoryHeader *header,
1201  SharedMemoryLister *lister,
1202  const char * registry_name)
1203 {
1204  if (lister != NULL)
1205  lister->print_header();
1206 
1207  SharedMemoryIterator i = find(magic_token, header);
1208  SharedMemoryIterator endi = end();
1209 
1210  if ((i == endi) && (lister != NULL)) {
1211  lister->print_no_segments();
1212  }
1213 
1214  unsigned int num_segments = 0;
1215 
1216  while (i != endi) {
1217  if (i.segmnattch() == 1) {
1218  // only iterator attached
1219  if (i.semaphore() != 0) {
1220  // a semaphore has been assigned, destroy!
1222  }
1223 
1224  // Mark shared memory segment as destroyed
1225  shmctl(i.shmid(), IPC_RMID, NULL);
1226 
1227  if (lister != NULL) {
1228  lister->print_info(*i, i.shmid(), i.semaphore(), i.segmsize(), i.databuf());
1229  }
1230 
1231  ++num_segments;
1232  }
1233  ++i;
1234  }
1235 
1236  if ((num_segments == 0) && (lister != NULL)) {
1237  lister->print_no_orphaned_segments();
1238  }
1239 
1240  if (lister != NULL)
1241  lister->print_footer();
1242 }
1243 
1244 /** Check if a specific shared memory segment exists.
1245  * This method will search for a memory chunk that matches the given magic
1246  * token and header.
1247  * @param magic_token Token to look for
1248  * @param header header to identify interesting segments with matching
1249  * magic_token
1250  * @param registry_name name of the SharedMemoryRegistry to use
1251  * @return true, if a matching shared memory segment was found, else
1252  * otherwise
1253  */
1254 bool
1255 SharedMemory::exists(const char *magic_token, SharedMemoryHeader *header, const char *registry_name)
1256 {
1257  return (find(magic_token, header, registry_name) != end());
1258 }
1259 
1260 /** Find SharedMemory segments.
1261  * Find SharedMemory segments identified by the supplied magic_token and header.
1262  * @param magic_token magic token
1263  * @param header shared memory header
1264  * @param registry_name name of the SharedMemoryRegistry to use
1265  * @return iterator pointing to the first found element (or end() if none found)
1266  */
1268 SharedMemory::find(const char *magic_token, SharedMemoryHeader *header, const char *registry_name)
1269 {
1270  try {
1271  SharedMemoryRegistry shm_registry(registry_name);
1272  return SharedMemoryIterator(shm_registry.find_segments(magic_token), header);
1273  } catch (Exception &e) {
1274  return end();
1275  }
1276 }
1277 
1278 /** Get invalid iterator.
1279  * Returns an iterator to a non-existing element.
1280  * @return Non-existing element
1281  */
1284 {
1285  return SharedMemoryIterator();
1286 }
1287 
1288 /** @class SharedMemory::SharedMemoryIterator <utils/ipc/shm.h>
1289  * Shared Memory iterator.
1290  * This iterator is used to iterate over shared memory segments which satisfy some
1291  * criterion. Use SharedMemory::find() and SharedMemory::list() to get the iterator.
1292  * @author Tim Niemueller
1293  */
1294 
1295 /** Constructor.
1296  * Constructs invalid iterator.
1297  */
1299 {
1300  id_it_ = ids_.end();
1301  cur_shmid_ = -1;
1302  header_ = NULL;
1303  shm_buf_ = NULL;
1304  segmsize_ = 0;
1305  segmnattch_ = 0;
1306  initialized_ = true;
1307 }
1308 
1309 /** Copy constructor.
1310  * @param shmit shared memory iterator to copy
1311  */
1313 {
1314  header_ = shmit.header_->clone();
1315  cur_shmid_ = shmit.cur_shmid_;
1316  shm_buf_ = NULL;
1317  segmsize_ = 0;
1318  segmnattch_ = 0;
1319  ids_ = shmit.ids_;
1320  initialized_ = true;
1321 
1322  if (shmit.id_it_ == shmit.ids_.end()) {
1323  id_it_ = ids_.end();
1324  } else {
1325  std::list<SharedMemoryRegistry::SharedMemID>::iterator s;
1326  for (s = ids_.begin(); s != ids_.end(); ++s) {
1327  if (s->shmid == shmit.id_it_->shmid)
1328  break;
1329  }
1330  }
1331 
1332  if (shmit.shm_buf_ != (void *)-1) {
1333  // other iterator is attach, attach as well
1334  try {
1335  attach();
1336  } catch (Exception &e) {
1337  // ignore
1338  }
1339  }
1340 }
1341 
1342 /** Constructor.
1343  * @param ids The IDs of the shared memory segments to iterate over
1344  * @param header shared memory header
1345  */
1347  std::list<SharedMemoryRegistry::SharedMemID> ids,
1348  SharedMemoryHeader * header)
1349 {
1350  header_ = header->clone();
1351  cur_shmid_ = -1;
1352  shm_buf_ = (void *)-1;
1353  segmsize_ = 0;
1354  segmnattch_ = 0;
1355  ids_ = ids;
1356  initialized_ = false;
1357 
1358  // Find first shm segment
1359  ++(*this);
1360 }
1361 
1362 /** Destructor. */
1364 {
1365  delete header_;
1366  if (shm_buf_ != (void *)-1) {
1367  shmdt(shm_buf_);
1368  shm_buf_ = (void *)-1;
1369  }
1370 }
1371 
1372 /** Attach. */
1373 void
1374 SharedMemory::SharedMemoryIterator::attach()
1375 {
1376  struct shmid_ds shm_segment;
1377 
1378  // Check if segment exists and get info
1379  cur_shmid_ = id_it_->shmid;
1380  if (cur_shmid_ < 0) {
1381  throw ShmCouldNotAttachException("SharedMemoryIterator could not stat");
1382  }
1383 
1384  /* Could be done, since we probably want to list destroyed segments we don't do it here
1385  // check if segment has not been destroyed
1386  if ( shm_segment.shm_perm.mode & SHM_DEST ) {
1387  throw ShmCouldNotAttachException("SharedMemoryIterator: Segment already destroyed");
1388  }
1389  */
1390 
1391  // actually attach
1392  shm_buf_ = shmat(cur_shmid_, NULL, SHM_RDONLY);
1393  if (shm_buf_ == (void *)-1) {
1394  throw ShmCouldNotAttachException("SharedMemoryIterator could not attach");
1395  }
1396 
1397  // do STAT again to get up2date values
1398  if (shmctl(cur_shmid_, IPC_STAT, &shm_segment) < 0) {
1399  shmdt(shm_buf_);
1400  throw ShmCouldNotAttachException("SharedMemoryIterator could not stat (2)");
1401  }
1402 
1403  segmsize_ = shm_segment.shm_segsz;
1404  segmnattch_ = shm_segment.shm_nattch;
1405 }
1406 
1407 /** Reset. */
1408 void
1409 SharedMemory::SharedMemoryIterator::reset()
1410 {
1411  if (header_)
1412  header_->reset();
1413  if (shm_buf_ != (void *)-1) {
1414  shmdt(shm_buf_);
1415  shm_buf_ = (void *)-1;
1416  }
1417  data_buf_ = NULL;
1418  semaphore_ = -1;
1419  cur_shmid_ = -1;
1420  segmsize_ = 0;
1421  segmnattch_ = 0;
1422 }
1423 
1424 /** Prefix increment.
1425  * @return reference to this instance
1426  */
1427 SharedMemory::SharedMemoryIterator &
1429 {
1430  reset();
1431 
1432  if (!initialized_) {
1433  id_it_ = ids_.begin();
1434  }
1435 
1436  if (id_it_ == ids_.end())
1437  return *this;
1438 
1439  if (initialized_)
1440  ++id_it_;
1441  else
1442  initialized_ = true;
1443 
1444  for (; id_it_ != ids_.end(); ++id_it_) {
1445  try {
1446  attach();
1447 
1448  if (!header_
1449  || header_->matches((char *)shm_buf_ + MagicTokenSize + sizeof(SharedMemory_header_t))) {
1450  SharedMemory_header_t *shm_header =
1451  (SharedMemory_header_t *)((char *)shm_buf_ + MagicTokenSize);
1452 
1453  // Found one!
1454  semaphore_ = shm_header->semaphore;
1455  data_buf_ = (char *)shm_buf_ + MagicTokenSize + sizeof(SharedMemory_header_t)
1456  + (header_ ? header_->size() : 0);
1457 
1458  if (header_) {
1459  header_->set((char *)shm_buf_ + MagicTokenSize + sizeof(SharedMemory_header_t));
1460  }
1461 
1462  break;
1463  } else {
1464  reset();
1465  }
1466  } catch (ShmCouldNotAttachException &e) {
1467  // ignore
1468  }
1469  }
1470 
1471  return *this;
1472 }
1473 
1474 /** Postfix increment operator.
1475  * @param inc ignored
1476  * @return instance before advancing to the next shared memory segment
1477  */
1480 {
1481  SharedMemoryIterator rv(*this);
1482  ++(*this);
1483  return rv;
1484 }
1485 
1486 /** Advance by i steps.
1487  * @param i number of (matching) segments to advance.
1488  * @return reference to this after advancing
1489  */
1492 {
1493  for (unsigned int j = 0; j < i; ++j) {
1494  ++(*this);
1495  }
1496  return *this;
1497 }
1498 
1499 /** Advance by i steps.
1500  * @param i number of (matching) segments to advance.
1501  * @return reference to this after advancing
1502  */
1505 {
1506  for (unsigned int j = 0; j < i; ++j) {
1507  ++(*this);
1508  }
1509  return *this;
1510 }
1511 
1512 /** Check iterators for equality.
1513  * @param s iterator to compare to
1514  * @return true if iterators point to the same shared memory segment, false otherwise
1515  */
1516 bool
1518 {
1519  return (cur_shmid_ == s.cur_shmid_);
1520 }
1521 
1522 /** Check iterators for inequality.
1523  * @param s iterator to compare to
1524  * @return true if iteraters point to the same shared memory segment, false otherwise
1525  */
1526 bool
1528 {
1529  return !(*this == s);
1530 }
1531 
1532 /** Get SharedMemoryHeader.
1533  * @return shared memory header
1534  */
1536 {
1537  return header_;
1538 }
1539 
1540 /** Make this instance point to the same segment as shmit.
1541  * @param shmit shared memory iterator
1542  * @return reference to this instance
1543  */
1546 {
1547  if (shm_buf_ != (void *)-1) {
1548  shmdt(shm_buf_);
1549  shm_buf_ = (void *)-1;
1550  }
1551  delete header_;
1552 
1553  header_ = shmit.header_->clone();
1554  ids_ = shmit.ids_;
1555  cur_shmid_ = shmit.cur_shmid_;
1556  shm_buf_ = NULL;
1557 
1558  if (shmit.id_it_ != shmit.ids_.end()) {
1559  for (id_it_ = ids_.begin(); id_it_ != ids_.end(); ++id_it_) {
1560  if (id_it_->shmid == shmit.id_it_->shmid)
1561  break;
1562  }
1563  }
1564 
1565  if (shmit.shm_buf_ != (void *)-1) {
1566  // other iterator is attach, attach as well
1567  attach();
1568  }
1569 
1570  return *this;
1571 }
1572 
1573 /** Get magic token.
1574  * @return magic token.
1575  */
1576 const char *
1578 {
1579  if (id_it_ == ids_.end()) {
1580  return "";
1581  } else {
1582  return id_it_->magic_token;
1583  }
1584 }
1585 
1586 /** Get shared memory ID.
1587  * @return shared memory ID
1588  */
1589 int
1591 {
1592  return cur_shmid_;
1593 }
1594 
1595 /** Get semaphore.
1596  * @return semaphore
1597  */
1598 int
1600 {
1601  return semaphore_;
1602 }
1603 
1604 /** Get segment size.
1605  * @return segment size
1606  */
1607 size_t
1609 {
1610  return segmsize_;
1611 }
1612 
1613 /** Get number of attached parties.
1614  * @return number of attached parties
1615  */
1616 size_t
1618 {
1619  return segmnattch_;
1620 }
1621 
1622 /** Get pointer to data buffer.
1623  * @return data buffer
1624  */
1625 void *
1627 {
1628  return data_buf_;
1629 }
1630 
1631 } // end namespace fawkes
static void erase_orphaned(const char *magic_token, SharedMemoryHeader *header, SharedMemoryLister *lister=0, const char *registry_name=0)
Erase orphaned (attach count = 0) shared memory segments of a given type.
Definition: shm.cpp:1199
IPC semaphore set.
Definition: semset.h:31
virtual void set(void *memptr)=0
Set information from memptr.
virtual size_t data_size()=0
Return the size of the data.
void add_segment(int shmid, const char *magic_token)
Register a segment.
virtual void print_footer()=0
Print footer of the table.
bool is_protected() const
Check if memory segment is protected.
Definition: shm.cpp:827
void lock_for_write()
Lock shared memory segment for writing.
Definition: shm.cpp:959
SharedMemory(const char *magic_token, SharedMemoryHeader *header, bool is_read_only, bool create, bool destroy_on_delete, const char *registry_name=0)
Create a new shared memory segment.
Definition: shm.cpp:348
Fawkes library namespace.
virtual void print_header()=0
Print header of the table.
size_t _mem_size
Total size of the segment, including headers.
Definition: shm.h:183
bool _should_create
Create shared memory segment.
Definition: shm.h:188
Shared Memory iterator.
Definition: shm.h:118
bool try_lock_for_write()
Try to aquire lock on shared memory segment for writing.
Definition: shm.cpp:993
size_t _data_size
Size of the data segment only.
Definition: shm.h:184
SharedMemory_header_t * _shm_header
general header as stored in the shared memory segment
Definition: shm.h:191
static void destroy(int key)
Destroy a semaphore set.
Definition: semset.cpp:404
Shared memory registry.
Definition: shm_registry.h:37
void * databuf() const
Get pointer to data buffer.
Definition: shm.cpp:1626
virtual bool matches(void *memptr)=0
Method to check if the given memptr matches this header.
bool is_swapable() const
Check if memory can be swapped out.
Definition: shm.cpp:798
void * _shm_upper_bound
Upper bound of memory.
Definition: shm.h:192
bool is_creator() const
Determine if the shared memory segment has been created by this instance.
Definition: shm.cpp:722
void lock_for_read()
Lock shared memory segment for reading.
Definition: shm.cpp:909
bool try_lock_for_read()
Try to aquire lock on shared memory segment for reading.
Definition: shm.cpp:938
void * addr(void *ptr) const
Get an address from a real pointer.
Definition: shm.cpp:690
size_t segmsize() const
Get segment size.
Definition: shm.cpp:1608
int semaphore
Semaphore set ID.
Definition: shm.h:170
void lock(unsigned short sem_num=0, short num=1)
Lock resources on the semaphore set.
Definition: semset.cpp:244
bool is_valid() const
Check validity of shared memory segment.
Definition: shm.cpp:811
char * _magic_token
Magic token.
Definition: shm.h:189
char * _shm_magic_token
Magic token as stored in the shared memory segment.
Definition: shm.h:190
The address points out of the shared memory.
static SharedMemoryIterator end()
Get invalid iterator.
Definition: shm.cpp:1283
bool _destroy_on_delete
destroy on delete.
Definition: shm.h:187
void set_swapable(bool swapable)
Set shared memory swapable.
Definition: shm.cpp:890
static void erase(const char *magic_token, SharedMemoryHeader *header, SharedMemoryLister *lister=0, const char *registry_name=0)
Erase shared memory segments of a given type.
Definition: shm.cpp:1151
SharedMemory & operator=(const SharedMemory &s)
Assignment operator.
Definition: shm.cpp:421
size_t segmnattch() const
Get number of attached parties.
Definition: shm.cpp:1617
bool is_destroyed() const
Check if segment has been destroyed This can be used if the segment has been destroyed.
Definition: shm.cpp:788
bool is_read_only() const
Check for read-only mode.
Definition: shm.cpp:706
SharedMemoryIterator & operator++()
Prefix increment.
Definition: shm.cpp:1428
void free()
Detach from and maybe destroy the shared memory segment.
Definition: shm.cpp:486
void set_destroy_on_delete(bool destroy)
Set if semaphore set should be destroyed on delete.
Definition: semset.cpp:365
Base class for exceptions in Fawkes.
Definition: exception.h:35
void attach()
Attach to the shared memory segment.
Definition: shm.cpp:512
int key()
Get key of semaphore.
Definition: semset.cpp:353
virtual void initialize(void *memptr)=0
Initialize the header.
void * shm_addr
Desired shared memory address.
Definition: shm.h:169
void * ptr(void *addr) const
Get the real pointer to the data based on an address.
Definition: shm.cpp:659
static bool exists(const char *magic_token, SharedMemoryHeader *header, const char *registry_name=0)
Check if a specific shared memory segment exists.
Definition: shm.cpp:1255
void * memptr() const
Get a pointer to the shared memory This method returns a pointer to the data-segment of the shared me...
Definition: shm.cpp:734
unsigned int num_attached() const
Get number of attached processes.
Definition: shm.cpp:763
virtual SharedMemoryHeader * clone() const =0
Clone this shared memory header.
void * _memptr
Pointer to the data segment.
Definition: shm.h:182
void set_destroy_on_delete(bool destroy)
Set deletion behaviour.
Definition: shm.cpp:839
Could not attach to shared memory segment.
virtual ~SharedMemory()
Destructor.
Definition: shm.cpp:397
Format list output for shared memory segments.
Definition: shm_lister.h:37
void unlock(unsigned short sem_num=0, short num=-1)
Unlock resources on the semaphore set.
Definition: semset.cpp:299
const SharedMemoryHeader * operator*() const
Get SharedMemoryHeader.
Definition: shm.cpp:1535
int semaphore() const
Get semaphore.
Definition: shm.cpp:1599
SharedMemoryIterator & operator=(const SharedMemoryIterator &shmit)
Make this instance point to the same segment as shmit.
Definition: shm.cpp:1545
void add_semaphore()
Add semaphore to shared memory segment.
Definition: shm.cpp:852
Shared memory segment.
Definition: shm.h:52
void set_value(int sem_num, int val)
Set the semaphore value.
Definition: semset.cpp:322
static SharedMemoryIterator find(const char *magic_token, SharedMemoryHeader *header, const char *registry_name=0)
Find SharedMemory segments.
Definition: shm.cpp:1268
std::list< SharedMemoryRegistry::SharedMemID > find_segments(const char *magic_token) const
Find segments with particular magic token.
static const short MaxNumConcurrentReaders
Maximum number of concurrent readers.
Definition: shm.h:56
bool operator==(const SharedMemoryIterator &s) const
Check iterators for equality.
Definition: shm.cpp:1517
bool _is_read_only
Read-only.
Definition: shm.h:186
virtual size_t size()=0
Size of the header.
bool operator!=(const SharedMemoryIterator &s) const
Check iterators for inequality.
Definition: shm.cpp:1527
size_t data_size() const
Get the size of the data-segment.
Definition: shm.cpp:745
SharedMemoryHeader * _header
Data-specific header.
Definition: shm.h:185
No shared memory header set before attach()
virtual void print_info(const SharedMemoryHeader *header, int shm_id, int semaphore, unsigned int mem_size, const void *memptr)=0
Print info about segment.
static const unsigned int MagicTokenSize
The magic token size.
Definition: shm.h:55
int shmid() const
Get shared memory ID.
Definition: shm.cpp:1590
void remove_segment(int shmid)
Remove segment.
int shmem_id() const
Get shared memory ID.
Definition: shm.cpp:754
virtual void print_no_segments()=0
Print this if no matching segment was found.
void set(void *memptr)
Copies data from the memptr to shared memory.
Definition: shm.cpp:774
SharedMemoryIterator & operator+(unsigned int i)
Advance by i steps.
Definition: shm.cpp:1491
long unsigned int _shm_offset
Offset to the master's base addr.
Definition: shm.h:193
static void list(const char *magic_token, SharedMemoryHeader *header, SharedMemoryLister *lister, const char *registry_name=0)
List shared memory segments of a given type.
Definition: shm.cpp:1116
SharedMemoryIterator & operator+=(unsigned int i)
Advance by i steps.
Definition: shm.cpp:1504
bool try_lock(unsigned short sem_num=0, short num=1)
Try to lock resources on the semaphore set.
Definition: semset.cpp:270
Interface for shared memory header.
Definition: shm.h:33
void unlock()
Unlock memory.
Definition: shm.cpp:1025
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
const char * magic_token() const
Get magic token.
Definition: shm.cpp:1577
virtual void print_no_orphaned_segments()=0
Print this if no matching orphaned segment was found.
The pointer does not point inside the shared memory.