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