Fawkes API Fawkes Development Version
shm_registry.cpp
1
2/***************************************************************************
3 * shm_registry.cpp - shared memory registry
4 *
5 * Created: Sun Mar 06 12:08:09 2011
6 * Copyright 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 <core/exception.h>
25#include <sys/mman.h>
26#include <sys/stat.h>
27#include <utils/ipc/shm_registry.h>
28
29#include <cerrno>
30#include <cstdlib>
31#include <cstring>
32#include <fcntl.h>
33#include <unistd.h>
34
35namespace fawkes {
36
37/** @class SharedMemoryRegistry <utils/ipc/shm_registry.h>
38 * Shared memory registry.
39 * This class opens a named POSIX shared memory segment, which
40 * contains one instance of the MemInfo struct. It is used to detect
41 * and maintain existing SysV IPC shared memory segments in a platform
42 * independent way. SysV IPC shared memory segments have some advanced
43 * functionality, for example reporting how many processes have
44 * attached to the segment. For the registry however, we are more
45 * interested in using a symbolic name which is the same for registry
46 * entries. Therefore, we use this here. The struct is protected by a
47 * lock implemented as a semaphore. Whenever a shared memory segment
48 * is created, it is registered to the registry so others can find
49 * it. On destruction, it is unregistered from the registry.
50 *
51 * @author Tim Niemueller
52 */
53
54/** Constructor.
55 * @param name name of the shared memory region. Must follow the rules
56 * set by shm_open(). If NULL defaults to "/fawkes-shmem-registry".
57 */
59{
60 shm_name_ = name ? strdup(name) : strdup(DEFAULT_SHM_NAME);
61
62 sem_ = sem_open(shm_name_, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 1);
63
64 if (sem_ == SEM_FAILED) {
65 free(shm_name_);
66 throw Exception(errno, "Failed to init shared memory registry semaphore");
67 }
68
69 sem_wait(sem_);
70
71 shmfd_ = shm_open(shm_name_, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
72
73 bool created = false;
74
75 if ((shmfd_ < 0) && (errno == EEXIST)) {
76 shmfd_ = shm_open(shm_name_, O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
77 } else {
78 if (ftruncate(shmfd_, sizeof(MemInfo)) != 0) {
79 close(shmfd_);
80 shm_unlink(shm_name_);
81 sem_post(sem_);
82 sem_close(sem_);
83 sem_unlink(shm_name_);
84 free(shm_name_);
85 throw Exception(errno, "Failed to resize memory for shared memory registry");
86 }
87
88 created = true;
89 }
90
91 if (shmfd_ < 0) {
92 sem_post(sem_);
93 sem_close(sem_);
94 sem_unlink(shm_name_);
95 free(shm_name_);
96 throw Exception(errno, "Failed to open shared memory registry");
97 }
98
99 meminfo_ = (MemInfo *)mmap(NULL, sizeof(MemInfo), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd_, 0);
100 if (meminfo_ == MAP_FAILED) {
101 close(shmfd_);
102 sem_close(sem_);
103 free(shm_name_);
104 throw Exception(errno, "Failed to mmap shared memory registry");
105 }
106
107 if (created) {
108 memset(meminfo_, 0, sizeof(MemInfo));
109
110 for (unsigned int i = 0; i < MAXNUM_SHM_SEGMS; ++i) {
111 meminfo_->segments[i].shmid = -1;
112 }
113 }
114
115 master_ = created;
116
117 sem_post(sem_);
118}
119
120/** Destructor. */
122{
123 close(shmfd_);
124 sem_close(sem_);
125 if (master_) {
126 shm_unlink(shm_name_);
127 }
128
129 free(shm_name_);
130}
131
132/** Cleanup existing shared memory segments.
133 * @param name shared memory segment name
134 */
135void
137{
138 shm_unlink(name ? name : DEFAULT_SHM_NAME);
139 sem_unlink(name ? name : DEFAULT_SHM_NAME);
140}
141
142/** Get a snapshot of currently registered segments.
143 * @return list of all currently registered segments
144 */
145std::list<SharedMemoryRegistry::SharedMemID>
147{
148 std::list<SharedMemID> rv;
149
150 sem_wait(sem_);
151
152 for (unsigned int i = 0; i < MAXNUM_SHM_SEGMS; ++i) {
153 if (meminfo_->segments[i].shmid > 0) {
154 rv.push_back(meminfo_->segments[i]);
155 }
156 }
157
158 sem_post(sem_);
159
160 return rv;
161}
162
163/** Find segments with particular magic token.
164 * @param magic_token magic token to return IDs for
165 * @return list of segments that currently exist with the given
166 * magic token
167 */
168std::list<SharedMemoryRegistry::SharedMemID>
169SharedMemoryRegistry::find_segments(const char *magic_token) const
170{
171 std::list<SharedMemID> rv;
172
173 sem_wait(sem_);
174
175 for (unsigned int i = 0; i < MAXNUM_SHM_SEGMS; ++i) {
176 if ((meminfo_->segments[i].shmid > 0)
177 && (strncmp(magic_token, meminfo_->segments[i].magic_token, MAGIC_TOKEN_SIZE) == 0)) {
178 rv.push_back(meminfo_->segments[i]);
179 }
180 }
181
182 sem_post(sem_);
183
184 return rv;
185}
186
187/** Register a segment.
188 * @param shmid shared memory ID of the SysV IPC segment
189 * @param magic_token magic token for the new segment
190 */
191void
192SharedMemoryRegistry::add_segment(int shmid, const char *magic_token)
193{
194 sem_wait(sem_);
195
196 bool valid = false;
197 for (unsigned int i = 0; i < MAXNUM_SHM_SEGMS; ++i) {
198 if (meminfo_->segments[i].shmid == shmid) {
199 valid = true;
200 break;
201 }
202 }
203
204 for (unsigned int i = 0; !valid && i < MAXNUM_SHM_SEGMS; ++i) {
205 if (meminfo_->segments[i].shmid == -1) {
206 meminfo_->segments[i].shmid = shmid;
207 strncpy(meminfo_->segments[i].magic_token, magic_token, MAGIC_TOKEN_SIZE);
208 valid = true;
209 }
210 }
211
212 sem_post(sem_);
213
214 if (!valid) {
215 throw Exception("Maximum number of shared memory segments already registered");
216 }
217}
218
219/** Remove segment.
220 * @param shmid shared memory ID of the segment to remove.
221 */
222void
224{
225 sem_wait(sem_);
226
227 for (unsigned int i = 0; i < MAXNUM_SHM_SEGMS; ++i) {
228 if (meminfo_->segments[i].shmid == shmid) {
229 meminfo_->segments[i].shmid = -1;
230 }
231 }
232
233 sem_post(sem_);
234}
235
236} // end namespace fawkes
Base class for exceptions in Fawkes.
Definition: exception.h:36
void add_segment(int shmid, const char *magic_token)
Register a segment.
std::list< SharedMemoryRegistry::SharedMemID > get_snapshot() const
Get a snapshot of currently registered segments.
void remove_segment(int shmid)
Remove segment.
SharedMemoryRegistry(const char *name=0)
Constructor.
static void cleanup(const char *name=0)
Cleanup existing shared memory segments.
std::list< SharedMemoryRegistry::SharedMemID > find_segments(const char *magic_token) const
Find segments with particular magic token.
Fawkes library namespace.