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