Fawkes API Fawkes Development Version
semset.cpp
1
2/***************************************************************************
3 * semset.cpp - ICP semaphore sets
4 *
5 * Generated: Tue Sep 19 15:02:32 2006
6 * Copyright 2005-2006 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/exceptions/system.h>
25#include <sys/ipc.h>
26#include <sys/sem.h>
27#include <sys/types.h>
28#include <utils/ipc/sem_exceptions.h>
29#include <utils/ipc/semset.h>
30
31#include <errno.h>
32#include <limits.h>
33
34namespace fawkes {
35
36/// @cond INTERNALS
37class SemaphoreSetData
38{
39public:
40 key_t key;
41 int semid;
42 int semflg;
43 int num_sems;
44};
45
46#if defined(_SEM_SEMUN_UNDEFINED) || defined(__FreeBSD__)
47union semun {
48 int val; /* value for SETVAL */
49 struct semid_ds * buf; /* buffer for IPC_STAT & IPC_SET */
50 unsigned short int *array; /* array for GETALL & SETALL */
51 struct seminfo * buf_; /* buffer for IPC_INFO */
52};
53#endif
54
55/// @endcond
56
57/** @class SemaphoreSet utils/ipc/semset.h
58 * IPC semaphore set.
59 * This class handles semaphore sets. A semaphore is a tool to control access
60 * to so-called critical sections. It is used to ensure that only a single
61 * process at a time is in the critical section or modifying shared data
62 * to avoid corruption.
63 *
64 * Semaphores use a single integer as the semaphore value. It denotes the
65 * number of resources that are available for the given semaphore. For
66 * example if you have two cameras on a robot you may have a value of two
67 * for the semaphore value. If the value reaches zero no more resources are
68 * available. You will have to wait until more resources are freed again.
69 *
70 * Now these individual semaphores are bundled to sets of semaphores. This is
71 * useful since there are situations where you want different semaphores
72 * for different operations on the shared resource. In the case of a shared
73 * memory segment for instance you could have one semaphore for reading
74 * and one for writing.
75 *
76 * @ingroup IPC
77 * @see qa_ipc_semset.cpp
78 * @author Tim Niemueller
79 *
80 *
81 * @var SemaphoreSet::destroy_on_delete
82 * Destroy this semaphore on delete?
83 */
84
85/** Constructor.
86 * Creates a new semaphore set. Will try to open the semaphore if it does
87 * exist. Tries to create if create is assured.
88 * @param path Path to generate the id from
89 * @param id Additional info for id.
90 * @param num_sems Number of semaphores to generate in this set. Only used
91 * if semaphore set did not already exist and create is
92 * assured.
93 * @param destroy_on_delete If true semaphore set is destroyed if instance
94 * is deleted.
95 * @param create If true semaphore set is created if it does not exist.
96 */
98 char id,
99 int num_sems,
100 bool create,
101 bool destroy_on_delete)
102{
103 data = new SemaphoreSetData();
104
105 if (num_sems < 0) {
106 num_sems = -num_sems;
107 }
108
109 this->destroy_on_delete = destroy_on_delete;
110 data->num_sems = num_sems;
111
112 data->semflg = 0666;
113 if (create) {
114 data->semflg |= IPC_CREAT;
115 }
116
117 data->key = ftok(path, id);
118 data->semid = semget(data->key, num_sems, data->semflg);
119}
120
121/** Constructor.
122 * Creates a new semaphore set. Will try to open the semaphore if it does
123 * exist. Tries to create if create is assured.
124 * @param key Key of semaphore set as printed by ipcs.
125 * @param num_sems Number of semaphores to generate in this set. Only used
126 * if semaphore set did not already exist and create is
127 * assured.
128 * @param destroy_on_delete If true semaphore set is destroyed if instance
129 * is deleted.
130 * @param create If true semaphore set is created if it does not exist.
131 */
132SemaphoreSet::SemaphoreSet(int key, int num_sems, bool create, bool destroy_on_delete)
133{
134 data = new SemaphoreSetData();
135
136 if (num_sems < 0) {
137 num_sems = -num_sems;
138 }
139
140 this->destroy_on_delete = destroy_on_delete;
141 data->num_sems = num_sems;
142
143 data->semflg = 0666;
144 if (create) {
145 data->semflg |= IPC_CREAT;
146 }
147
148 data->key = key;
149 data->semid = semget(data->key, num_sems, data->semflg);
150
151 if (data->semid == -1) {
152 throw Exception(errno, "Creating the semaphore set failed, maybe key does not exist");
153 }
154}
155
156/** Constructor.
157 * Creates a new semaphore set with a new ID supplied by the system. The
158 * id can be queried with getID.
159 * @param num_sems Number of semaphores to generate in this set. Only used
160 * if semaphore set did not already exist and create is
161 * assured.
162 * @param destroy_on_delete If true semaphore set is destroyed if instance
163 * is deleted.
164 */
165SemaphoreSet::SemaphoreSet(int num_sems, bool destroy_on_delete)
166{
167 data = new SemaphoreSetData();
168
169 if (num_sems < 0) {
170 num_sems = -num_sems;
171 }
172
173 this->destroy_on_delete = destroy_on_delete;
174 data->num_sems = num_sems;
175
176 data->semflg = 0666;
177 data->semflg |= IPC_CREAT;
178 data->semflg |= IPC_EXCL;
179
180 for (data->key = 1; data->key < INT_MAX; data->key++) {
181 data->semid = semget(data->key, num_sems, data->semflg);
182 if (data->semid != -1) {
183 // valid semaphore found
184 break;
185 }
186 }
187}
188
189/** Destructor */
191{
192 if ((data->semid != -1) && destroy_on_delete) {
193 semctl(data->semid, 0, IPC_RMID, 0);
194 }
195 delete data;
196}
197
198/** Check if the semaphore set is valid.
199 * If the queue could not be opened yet (for example if you gave create=false to the
200 * constructor) isValid() will try to open the queue.
201 * @return This method returns false if the message queue could not be opened
202 * or if it has been closed, it returns true if messages can be sent or received.
203 */
204bool
206{
207 if (data->semid == -1) {
208 data->semid = semget(data->key, data->num_sems, data->semflg);
209 if (data->semid == -1) {
210 return false;
211 } else {
212 struct semid_ds semds;
213 union semun s;
214 s.buf = &semds;
215 if (semctl(data->semid, 0, IPC_STAT, s) != -1) {
216 return true;
217 } else {
218 data->semid = -1;
219 return false;
220 }
221 }
222 } else {
223 struct semid_ds semds;
224 union semun s;
225 s.buf = &semds;
226 if (semctl(data->semid, 0, IPC_STAT, s) != -1) {
227 return true;
228 } else {
229 data->semid = -1;
230 return false;
231 }
232 }
233}
234
235/** Lock resources on the semaphore set.
236 * Locks num resources on semaphore sem_num.
237 * @param sem_num The semaphore number in the set
238 * @param num How many resources to lock? Positive number.
239 * @exception InterruptedException Operation was interrupted (for instance by a signal)
240 * @exception SemCannotLockException Semaphore cannot be locked
241 * @exception SemInvalidException Semaphore set is invalid
242 */
243void
244SemaphoreSet::lock(unsigned short sem_num, short num)
245{
246 if (data->semid == -1)
247 throw SemInvalidException();
248
249 struct sembuf sop;
250 sop.sem_num = sem_num;
251 sop.sem_op = (short)((num <= 0) ? num : -num);
252 sop.sem_flg = 0;
253 if (semop(data->semid, &sop, 1) != 0) {
254 if (errno == EINTR)
255 throw InterruptedException();
256 else
258 }
259}
260
261/** Try to lock resources on the semaphore set.
262 * @param sem_num The semaphore number in the set
263 * @param num How many resources to lock? Positive number.
264 * @return true, if the semaphore could be locked, false otherwise
265 * @exception InterruptedException Operation was interrupted (for instance by a signal)
266 * @exception SemCannotLockException Semaphore cannot be locked
267 * @exception SemInvalidException Semaphore set is invalid
268 */
269bool
270SemaphoreSet::try_lock(unsigned short sem_num, short num)
271{
272 if (data->semid == -1)
273 throw SemInvalidException();
274
275 struct sembuf sop;
276 sop.sem_num = sem_num;
277 sop.sem_op = (short)((num <= 0) ? num : -num);
278 sop.sem_flg = IPC_NOWAIT;
279 if (semop(data->semid, &sop, 1) != 0) {
280 if (errno == EAGAIN) {
281 return false;
282 } else if (errno == EINTR) {
283 throw InterruptedException();
284 } else {
286 }
287 }
288 return true;
289}
290
291/** Unlock resources on the semaphore set.
292 * @param sem_num The semaphore number in the set
293 * @param num How many resources to unlock? Negative number.
294 * @exception InterruptedException Operation was interrupted (for instance by a signal)
295 * @exception SemCannotUnlockException Semaphore cannot be unlocked
296 * @exception SemInvalidException Semaphore set is invalid
297 */
298void
299SemaphoreSet::unlock(unsigned short sem_num, short num)
300{
301 if (data->semid == -1)
302 throw SemInvalidException();
303
304 struct sembuf sop;
305 sop.sem_num = sem_num;
306 sop.sem_op = (short)((num >= 0) ? num : -num);
307 sop.sem_flg = 0;
308 if (semop(data->semid, &sop, 1) != 0) {
309 if (errno == EINTR)
310 throw InterruptedException();
311 else
313 }
314}
315
316/** Set the semaphore value.
317 * @param sem_num The semaphore number in the set
318 * @param val The value to set
319 * @exception SemCannotSetValException Cannot set value
320 */
321void
322SemaphoreSet::set_value(int sem_num, int val)
323{
324 if (data->semid == -1)
325 throw SemInvalidException();
326
327 union semun s;
328 s.val = val;
329
330 if (semctl(data->semid, sem_num, SETVAL, s) == -1) {
332 }
333}
334
335/** Get the semaphore value.
336 * @param sem_num The semaphore number in the set
337 * @return value of the semaphore
338 * @exception SemInvalidException Semaphore set is invalid
339 */
340int
342{
343 if (data->semid == -1)
344 throw SemInvalidException();
345
346 return (semctl(data->semid, sem_num, GETVAL, 0) != 0);
347}
348
349/** Get key of semaphore.
350 * @return Key of semaphore as listed by ipcs.
351 */
352int
354{
355 return data->key;
356}
357
358/** Set if semaphore set should be destroyed on delete.
359 * If this is set to true the semaphore set is destroyed from the system if this
360 * instance is deleted.
361 * @param destroy set to true, if semaphore set should be destroyed on delete,
362 * false otherwise
363 */
364void
366{
368}
369
370/* ==================================================================
371 * STATICs
372 */
373
374/** Get a non-zero free key
375 * Scans the key space sequentially until a non-zero unused key is found. Not
376 * that using this can cause a race-condition. You are in most cases better off
377 * using the appropriate constructor that automatically finds a free key.
378 * @return 0, if no free key could be found, otherwise the non-zero unused key
379 */
380int
382{
383 bool found = false;
384 int key;
385 int semid;
386 for (key = 1; key < INT_MAX; ++key) {
387 semid = semget(key, 1, IPC_CREAT | IPC_EXCL);
388 if (semid != -1) {
389 // valid semaphore found
390 semctl(semid, 0, IPC_RMID, 0);
391 found = true;
392 break;
393 }
394 }
395 return (found ? key : 0);
396}
397
398/** Destroy a semaphore set.
399 * Destroy the semaphore denoted by key. No tests are done if some other
400 * process is using this semaphore. Use with care!
401 * @param key key of the semaphore set
402 */
403void
405{
406 int semid = semget(key, 0, 0);
407 if (semid == -1)
408 return;
409 semctl(semid, 0, IPC_RMID, 0);
410}
411
412} // end namespace fawkes
Base class for exceptions in Fawkes.
Definition: exception.h:36
The current system call has been interrupted (for instance by a signal).
Definition: system.h:39
Cannot lock semaphore.
Cannot set value on semaphore.
Cannot unlock semaphore.
Semaphore or semaphore set invalid.
bool destroy_on_delete
Destroy this semaphore on delete?
Definition: semset.h:59
void set_destroy_on_delete(bool destroy)
Set if semaphore set should be destroyed on delete.
Definition: semset.cpp:365
bool valid()
Check if the semaphore set is valid.
Definition: semset.cpp:205
void unlock(unsigned short sem_num=0, short num=-1)
Unlock resources on the semaphore set.
Definition: semset.cpp:299
int get_value(int sem_num)
Get the semaphore value.
Definition: semset.cpp:341
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
SemaphoreSet(const char *path, char id, int num_sems, bool create=false, bool destroy_on_delete=false)
Constructor.
Definition: semset.cpp:97
~SemaphoreSet()
Destructor.
Definition: semset.cpp:190
int key()
Get key of semaphore.
Definition: semset.cpp:353
static void destroy(int key)
Destroy a semaphore set.
Definition: semset.cpp:404
static int free_key()
Get a non-zero free key Scans the key space sequentially until a non-zero unused key is found.
Definition: semset.cpp:381
void set_value(int sem_num, int val)
Set the semaphore value.
Definition: semset.cpp:322
Fawkes library namespace.