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 - 1);
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);
283  strncpy(_magic_token, s._magic_token, MagicTokenSize - 1);
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 - 1);
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);
440  strncpy(_magic_token, s._magic_token, MagicTokenSize - 1);
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  */
1535 const SharedMemoryHeader *
1537 {
1538  return header_;
1539 }
1540 
1541 /** Make this instance point to the same segment as shmit.
1542  * @param shmit shared memory iterator
1543  * @return reference to this instance
1544  */
1547 {
1548  if (shm_buf_ != (void *)-1) {
1549  shmdt(shm_buf_);
1550  shm_buf_ = (void *)-1;
1551  }
1552  delete header_;
1553 
1554  header_ = shmit.header_->clone();
1555  ids_ = shmit.ids_;
1556  cur_shmid_ = shmit.cur_shmid_;
1557  shm_buf_ = NULL;
1558 
1559  if (shmit.id_it_ != shmit.ids_.end()) {
1560  for (id_it_ = ids_.begin(); id_it_ != ids_.end(); ++id_it_) {
1561  if (id_it_->shmid == shmit.id_it_->shmid)
1562  break;
1563  }
1564  }
1565 
1566  if (shmit.shm_buf_ != (void *)-1) {
1567  // other iterator is attach, attach as well
1568  attach();
1569  }
1570 
1571  return *this;
1572 }
1573 
1574 /** Get magic token.
1575  * @return magic token.
1576  */
1577 const char *
1579 {
1580  if (id_it_ == ids_.end()) {
1581  return "";
1582  } else {
1583  return id_it_->magic_token;
1584  }
1585 }
1586 
1587 /** Get shared memory ID.
1588  * @return shared memory ID
1589  */
1590 int
1592 {
1593  return cur_shmid_;
1594 }
1595 
1596 /** Get semaphore.
1597  * @return semaphore
1598  */
1599 int
1601 {
1602  return semaphore_;
1603 }
1604 
1605 /** Get segment size.
1606  * @return segment size
1607  */
1608 size_t
1610 {
1611  return segmsize_;
1612 }
1613 
1614 /** Get number of attached parties.
1615  * @return number of attached parties
1616  */
1617 size_t
1619 {
1620  return segmnattch_;
1621 }
1622 
1623 /** Get pointer to data buffer.
1624  * @return data buffer
1625  */
1626 void *
1628 {
1629  return data_buf_;
1630 }
1631 
1632 } // end namespace fawkes
Base class for exceptions in Fawkes.
Definition: exception.h:36
void append(const char *format,...) noexcept
Append messages to the message list.
Definition: exception.cpp:333
IPC semaphore set.
Definition: semset.h:32
void set_destroy_on_delete(bool destroy)
Set if semaphore set should be destroyed on delete.
Definition: semset.cpp:365
void unlock(unsigned short sem_num=0, short num=-1)
Unlock resources on the semaphore set.
Definition: semset.cpp:299
bool try_lock(unsigned short sem_num=0, short num=1)
Try to lock resources on the semaphore set.
Definition: semset.cpp:270
void lock(unsigned short sem_num=0, short num=1)
Lock resources on the semaphore set.
Definition: semset.cpp:244
int key()
Get key of semaphore.
Definition: semset.cpp:353
static void destroy(int key)
Destroy a semaphore set.
Definition: semset.cpp:404
void set_value(int sem_num, int val)
Set the semaphore value.
Definition: semset.cpp:322
Interface for shared memory header.
Definition: shm.h:34
virtual size_t size()=0
Size of the header.
virtual SharedMemoryHeader * clone() const =0
Clone this shared memory header.
virtual void set(void *memptr)=0
Set information from memptr.
virtual size_t data_size()=0
Return the size of the data.
virtual bool matches(void *memptr)=0
Method to check if the given memptr matches this header.
virtual void initialize(void *memptr)=0
Initialize the header.
Format list output for shared memory segments.
Definition: shm_lister.h:38
virtual void print_header()=0
Print header of the table.
virtual void print_info(const SharedMemoryHeader *header, int shm_id, int semaphore, unsigned int mem_size, const void *memptr)=0
Print info about segment.
virtual void print_no_segments()=0
Print this if no matching segment was found.
virtual void print_footer()=0
Print footer of the table.
virtual void print_no_orphaned_segments()=0
Print this if no matching orphaned segment was found.
Shared memory registry.
Definition: shm_registry.h:38
void add_segment(int shmid, const char *magic_token)
Register a segment.
void remove_segment(int shmid)
Remove segment.
std::list< SharedMemoryRegistry::SharedMemID > find_segments(const char *magic_token) const
Find segments with particular magic token.
Shared Memory iterator.
Definition: shm.h:119
bool operator==(const SharedMemoryIterator &s) const
Check iterators for equality.
Definition: shm.cpp:1517
SharedMemoryIterator & operator+(unsigned int i)
Advance by i steps.
Definition: shm.cpp:1491
const char * magic_token() const
Get magic token.
Definition: shm.cpp:1578
SharedMemoryIterator & operator=(const SharedMemoryIterator &shmit)
Make this instance point to the same segment as shmit.
Definition: shm.cpp:1546
int semaphore() const
Get semaphore.
Definition: shm.cpp:1600
void * databuf() const
Get pointer to data buffer.
Definition: shm.cpp:1627
SharedMemoryIterator & operator++()
Prefix increment.
Definition: shm.cpp:1428
const SharedMemoryHeader * operator*() const
Get SharedMemoryHeader.
Definition: shm.cpp:1536
SharedMemoryIterator & operator+=(unsigned int i)
Advance by i steps.
Definition: shm.cpp:1504
size_t segmsize() const
Get segment size.
Definition: shm.cpp:1609
int shmid() const
Get shared memory ID.
Definition: shm.cpp:1591
bool operator!=(const SharedMemoryIterator &s) const
Check iterators for inequality.
Definition: shm.cpp:1527
size_t segmnattch() const
Get number of attached parties.
Definition: shm.cpp:1618
Shared memory segment.
Definition: shm.h:53
bool try_lock_for_read()
Try to aquire lock on shared memory segment for reading.
Definition: shm.cpp:938
bool is_read_only() const
Check for read-only mode.
Definition: shm.cpp:706
void free()
Detach from and maybe destroy the shared memory segment.
Definition: shm.cpp:486
static SharedMemoryIterator find(const char *magic_token, SharedMemoryHeader *header, const char *registry_name=0)
Find SharedMemory segments.
Definition: shm.cpp:1268
int shmem_id() const
Get shared memory ID.
Definition: shm.cpp:754
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
void * addr(void *ptr) const
Get an address from a real pointer.
Definition: shm.cpp:690
bool is_valid() const
Check validity of shared memory segment.
Definition: shm.cpp:811
void add_semaphore()
Add semaphore to shared memory segment.
Definition: shm.cpp:852
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
virtual ~SharedMemory()
Destructor.
Definition: shm.cpp:397
bool _is_read_only
Read-only.
Definition: shm.h:186
char * _magic_token
Magic token.
Definition: shm.h:189
bool is_destroyed() const
Check if segment has been destroyed This can be used if the segment has been destroyed.
Definition: shm.cpp:788
void * _shm_upper_bound
Upper bound of memory.
Definition: shm.h:192
size_t data_size() const
Get the size of the data-segment.
Definition: shm.cpp:745
bool is_swapable() const
Check if memory can be swapped out.
Definition: shm.cpp:798
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_header_t * _shm_header
general header as stored in the shared memory segment
Definition: shm.h:191
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
void set(void *memptr)
Copies data from the memptr to shared memory.
Definition: shm.cpp:774
unsigned int num_attached() const
Get number of attached processes.
Definition: shm.cpp:763
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
size_t _data_size
Size of the data segment only.
Definition: shm.h:184
SharedMemoryHeader * _header
Data-specific header.
Definition: shm.h:185
SharedMemory & operator=(const SharedMemory &s)
Assignment operator.
Definition: shm.cpp:421
void * _memptr
Pointer to the data segment.
Definition: shm.h:182
void * ptr(void *addr) const
Get the real pointer to the data based on an address.
Definition: shm.cpp:659
void unlock()
Unlock memory.
Definition: shm.cpp:1025
char * _shm_magic_token
Magic token as stored in the shared memory segment.
Definition: shm.h:190
long unsigned int _shm_offset
Offset to the master's base addr.
Definition: shm.h:193
static const short MaxNumConcurrentReaders
Maximum number of concurrent readers.
Definition: shm.h:56
static const unsigned int MagicTokenSize
The magic token size.
Definition: shm.h:55
bool try_lock_for_write()
Try to aquire lock on shared memory segment for writing.
Definition: shm.cpp:993
void set_destroy_on_delete(bool destroy)
Set deletion behaviour.
Definition: shm.cpp:839
void set_swapable(bool swapable)
Set shared memory swapable.
Definition: shm.cpp:890
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
bool is_creator() const
Determine if the shared memory segment has been created by this instance.
Definition: shm.cpp:722
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
static SharedMemoryIterator end()
Get invalid iterator.
Definition: shm.cpp:1283
void attach()
Attach to the shared memory segment.
Definition: shm.cpp:512
size_t _mem_size
Total size of the segment, including headers.
Definition: shm.h:183
bool _destroy_on_delete
destroy on delete.
Definition: shm.h:187
void lock_for_read()
Lock shared memory segment for reading.
Definition: shm.cpp:909
bool _should_create
Create shared memory segment.
Definition: shm.h:188
The address points out of the shared memory.
Could not attach to shared memory segment.
No shared memory header set before attach()
The pointer does not point inside the shared memory.
Fawkes library namespace.
int semaphore
Semaphore set ID.
Definition: shm.h:170
void * shm_addr
Desired shared memory address.
Definition: shm.h:169