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 
34 namespace fawkes {
35 
36 /// @cond INTERNALS
37 class SemaphoreSetData
38 {
39 public:
40  key_t key;
41  int semid;
42  int semflg;
43  int num_sems;
44 };
45 
46 #if defined(_SEM_SEMUN_UNDEFINED) || defined(__FreeBSD__)
47 union 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  */
97 SemaphoreSet::SemaphoreSet(const char *path,
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  */
132 SemaphoreSet::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  */
165 SemaphoreSet::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  */
204 bool
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  */
243 void
244 SemaphoreSet::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
257  throw SemCannotLockException();
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  */
269 bool
270 SemaphoreSet::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 {
285  throw SemCannotLockException();
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  */
298 void
299 SemaphoreSet::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
312  throw SemCannotUnlockException();
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  */
321 void
322 SemaphoreSet::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) {
331  throw SemCannotSetValException();
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  */
340 int
341 SemaphoreSet::get_value(int sem_num)
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  */
352 int
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  */
364 void
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  */
380 int
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  */
403 void
404 SemaphoreSet::destroy(int key)
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
fawkes::SemaphoreSet::SemaphoreSet
SemaphoreSet(const char *path, char id, int num_sems, bool create=false, bool destroy_on_delete=false)
Constructor.
Definition: semset.cpp:101
fawkes::SemaphoreSet::free_key
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:385
fawkes::InterruptedException
Definition: system.h:42
fawkes::SemCannotUnlockException
Cannot unlock semaphore.
Definition: sem_exceptions.h:58
fawkes::SemaphoreSet::set_destroy_on_delete
void set_destroy_on_delete(bool destroy)
Set if semaphore set should be destroyed on delete.
Definition: semset.cpp:369
fawkes::SemCannotSetValException
Cannot set value on semaphore.
Definition: sem_exceptions.h:68
fawkes::SemaphoreSet::destroy_on_delete
bool destroy_on_delete
Definition: semset.h:63
fawkes::SemaphoreSet::set_value
void set_value(int sem_num, int val)
Set the semaphore value.
Definition: semset.cpp:326
fawkes::SemaphoreSet::try_lock
bool try_lock(unsigned short sem_num=0, short num=1)
Try to lock resources on the semaphore set.
Definition: semset.cpp:274
fawkes::SemaphoreSet::valid
bool valid()
Check if the semaphore set is valid.
Definition: semset.cpp:209
fawkes
fawkes::SemaphoreSet::key
int key()
Get key of semaphore.
Definition: semset.cpp:357
fawkes::SemaphoreSet::get_value
int get_value(int sem_num)
Get the semaphore value.
Definition: semset.cpp:345
fawkes::SemaphoreSet::~SemaphoreSet
~SemaphoreSet()
Destructor.
Definition: semset.cpp:194
fawkes::SemaphoreSet::lock
void lock(unsigned short sem_num=0, short num=1)
Lock resources on the semaphore set.
Definition: semset.cpp:248
fawkes::SemCannotLockException
Cannot lock semaphore.
Definition: sem_exceptions.h:48
fawkes::SemaphoreSet::unlock
void unlock(unsigned short sem_num=0, short num=-1)
Unlock resources on the semaphore set.
Definition: semset.cpp:303
fawkes::SemaphoreSet::destroy
static void destroy(int key)
Destroy a semaphore set.
Definition: semset.cpp:408