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
38namespace 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 */
215const 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 */
239SharedMemory::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);
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 */
348SharedMemory::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.
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 */
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.
429 }
430 delete semset_;
431 }
432 delete[] _magic_token;
433 free();
434 delete shm_registry_;
435 if (registry_name_)
436 ::free(registry_name_);
437
438 _magic_token = new char[MagicTokenSize];
439 memset(_magic_token, 0, MagicTokenSize);
441
445
446 _memptr = NULL;
447 _shm_magic_token = NULL;
448 _shm_header = NULL;
449 _header = s._header->clone();
450 _data_size = 0;
451
452 semset_ = NULL;
453 created_ = false;
454 shared_mem_ = NULL;
455 shared_mem_id_ = 0;
456 shared_mem_upper_bound_ = NULL;
457
458 write_lock_aquired_ = false;
459 if (s.registry_name_) {
460 registry_name_ = strdup(s.registry_name_);
461 } else {
462 registry_name_ = NULL;
463 }
464
465 try {
466 attach();
467 } catch (Exception &e) {
468 e.append("SharedMemory public copy constructor");
469 throw;
470 }
471
472 if (_memptr == NULL) {
473 throw ShmCouldNotAttachException("Could not attach to created shared memory segment");
474 }
475
476 shm_registry_ = new SharedMemoryRegistry(registry_name_);
477
478 return *this;
479}
480
481/** Detach from and maybe destroy the shared memory segment.
482 * This will detach from the shared memory segment. If destroy_on_delete is
483 * true this will destroy the shared memory segment before detaching.
484 */
485void
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 */
511void
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!
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 */
658void *
659SharedMemory::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 */
689void *
690SharedMemory::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 */
705bool
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 */
721bool
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 */
733void *
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 */
744size_t
746{
747 return _data_size;
748}
749
750/** Get shared memory ID.
751 * @return shared memory ID
752 */
753int
755{
756 return shared_mem_id_;
757}
758
759/** Get number of attached processes.
760 * @return number of attached processes
761 */
762unsigned 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 */
773void
774SharedMemory::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 */
787bool
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 */
797bool
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 */
810bool
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 */
826bool
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 */
838void
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 */
851void
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 */
889void
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 */
908void
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 */
937bool
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 */
958void
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 */
992bool
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 */
1024void
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 */
1050bool
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 */
1072bool
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 */
1093unsigned 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 */
1115void
1116SharedMemory::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 */
1150void
1151SharedMemory::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 */
1198void
1199SharedMemory::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)) {
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 */
1254bool
1255SharedMemory::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 */
1268SharedMemory::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. */
1373void
1374SharedMemory::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. */
1408void
1409SharedMemory::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 */
1427SharedMemory::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 */
1516bool
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 */
1526bool
1528{
1529 return !(*this == s);
1530}
1531
1532/** Get SharedMemoryHeader.
1533 * @return shared memory header
1534 */
1535const 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 */
1577const 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 */
1590int
1592{
1593 return cur_shmid_;
1594}
1595
1596/** Get semaphore.
1597 * @return semaphore
1598 */
1599int
1601{
1602 return semaphore_;
1603}
1604
1605/** Get segment size.
1606 * @return segment size
1607 */
1608size_t
1610{
1611 return segmsize_;
1612}
1613
1614/** Get number of attached parties.
1615 * @return number of attached parties
1616 */
1617size_t
1619{
1620 return segmnattch_;
1621}
1622
1623/** Get pointer to data buffer.
1624 * @return data buffer
1625 */
1626void *
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