Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * semset.cpp - ICP semaphore sets 00004 * 00005 * Generated: Tue Sep 19 15:02:32 2006 00006 * Copyright 2005-2006 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <utils/ipc/semset.h> 00025 #include <utils/ipc/sem_exceptions.h> 00026 #include <core/exceptions/system.h> 00027 00028 #include <errno.h> 00029 00030 #include <sys/types.h> 00031 #include <sys/ipc.h> 00032 #include <sys/sem.h> 00033 #include <limits.h> 00034 00035 namespace fawkes { 00036 00037 00038 /// @cond INTERNALS 00039 class SemaphoreSetData 00040 { 00041 public: 00042 key_t key; 00043 int semid; 00044 int semflg; 00045 int num_sems; 00046 }; 00047 00048 #ifdef _SEM_SEMUN_UNDEFINED 00049 union semun 00050 { 00051 int val; /* value for SETVAL */ 00052 struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ 00053 unsigned short int *array; /* array for GETALL & SETALL */ 00054 struct seminfo *__buf; /* buffer for IPC_INFO */ 00055 }; 00056 #endif 00057 00058 /// @endcond 00059 00060 00061 /** @class SemaphoreSet utils/ipc/semset.h 00062 * IPC semaphore set. 00063 * This class handles semaphore sets. A semaphore is a tool to control access 00064 * to so-called critical sections. It is used to ensure that only a single 00065 * process at a time is in the critical section or modifying shared data 00066 * to avoid corruption. 00067 * 00068 * Semaphores use a single integer as the semaphore value. It denotes the 00069 * number of resources that are available for the given semaphore. For 00070 * example if you have two cameras on a robot you may have a value of two 00071 * for the semaphore value. If the value reaches zero no more resources are 00072 * available. You will have to wait until more resources are freed again. 00073 * 00074 * Now these individual semaphores are bundled to sets of semaphores. This is 00075 * useful since there are situations where you want different semaphores 00076 * for different operations on the shared resource. In the case of a shared 00077 * memory segment for instance you could have one semaphore for reading 00078 * and one for writing. 00079 * 00080 * @ingroup IPC 00081 * @see qa_ipc_semset.cpp 00082 * @author Tim Niemueller 00083 * 00084 * 00085 * @var SemaphoreSet::destroy_on_delete 00086 * Destroy this semaphore on delete? 00087 */ 00088 00089 00090 /** Constructor. 00091 * Creates a new semaphore set. Will try to open the semaphore if it does 00092 * exist. Tries to create if create is assured. 00093 * @param path Path to generate the id from 00094 * @param id Additional info for id. 00095 * @param num_sems Number of semaphores to generate in this set. Only used 00096 * if semaphore set did not already exist and create is 00097 * assured. 00098 * @param destroy_on_delete If true semaphore set is destroyed if instance 00099 * is deleted. 00100 * @param create If true semaphore set is created if it does not exist. 00101 */ 00102 SemaphoreSet::SemaphoreSet(const char *path, char id, 00103 int num_sems, 00104 bool create, bool destroy_on_delete) 00105 { 00106 data = new SemaphoreSetData(); 00107 00108 if ( num_sems < 0 ) { 00109 num_sems = - num_sems; 00110 } 00111 00112 this->destroy_on_delete = destroy_on_delete; 00113 data->num_sems = num_sems; 00114 00115 data->semflg = 0666; 00116 if (create) { 00117 data->semflg |= IPC_CREAT; 00118 } 00119 00120 data->key = ftok(path, id); 00121 data->semid = semget(data->key, num_sems, data->semflg); 00122 00123 } 00124 00125 00126 /** Constructor. 00127 * Creates a new semaphore set. Will try to open the semaphore if it does 00128 * exist. Tries to create if create is assured. 00129 * @param key Key of semaphore set as printed by ipcs. 00130 * @param num_sems Number of semaphores to generate in this set. Only used 00131 * if semaphore set did not already exist and create is 00132 * assured. 00133 * @param destroy_on_delete If true semaphore set is destroyed if instance 00134 * is deleted. 00135 * @param create If true semaphore set is created if it does not exist. 00136 */ 00137 SemaphoreSet::SemaphoreSet(int key, 00138 int num_sems, 00139 bool create, bool destroy_on_delete) 00140 { 00141 data = new SemaphoreSetData(); 00142 00143 if ( num_sems < 0 ) { 00144 num_sems = - num_sems; 00145 } 00146 00147 this->destroy_on_delete = destroy_on_delete; 00148 data->num_sems = num_sems; 00149 00150 data->semflg = 0666; 00151 if (create) { 00152 data->semflg |= IPC_CREAT; 00153 } 00154 00155 data->key = key; 00156 data->semid = semget(data->key, num_sems, data->semflg); 00157 00158 if ( data->semid == -1 ) { 00159 throw Exception(errno, "Creating the semaphore set failed, maybe key does not exist"); 00160 } 00161 } 00162 00163 00164 /** Constructor. 00165 * Creates a new semaphore set with a new ID supplied by the system. The 00166 * id can be queried with getID. 00167 * @param num_sems Number of semaphores to generate in this set. Only used 00168 * if semaphore set did not already exist and create is 00169 * assured. 00170 * @param destroy_on_delete If true semaphore set is destroyed if instance 00171 * is deleted. 00172 */ 00173 SemaphoreSet::SemaphoreSet(int num_sems, 00174 bool destroy_on_delete) 00175 { 00176 data = new SemaphoreSetData(); 00177 00178 if ( num_sems < 0 ) { 00179 num_sems = - num_sems; 00180 } 00181 00182 this->destroy_on_delete = destroy_on_delete; 00183 data->num_sems = num_sems; 00184 00185 data->semflg = 0666; 00186 data->semflg |= IPC_CREAT; 00187 data->semflg |= IPC_EXCL; 00188 00189 for (data->key = 1; data->key < INT_MAX; data->key++) { 00190 data->semid = semget(data->key, num_sems, data->semflg); 00191 if ( data->semid != -1 ) { 00192 // valid semaphore found 00193 break; 00194 } 00195 } 00196 } 00197 00198 00199 /** Destructor */ 00200 SemaphoreSet::~SemaphoreSet() 00201 { 00202 if ((data->semid != -1) && destroy_on_delete) { 00203 semctl(data->semid, 0, IPC_RMID, 0); 00204 } 00205 delete data; 00206 } 00207 00208 00209 /** Check if the semaphore set is valid. 00210 * If the queue could not be opened yet (for example if you gave create=false to the 00211 * constructor) isValid() will try to open the queue. 00212 * @return This method returns false if the message queue could not be opened 00213 * or if it has been closed, it returns true if messages can be sent or received. 00214 */ 00215 bool 00216 SemaphoreSet::valid() 00217 { 00218 if (data->semid == -1) { 00219 data->semid = semget(data->key, data->num_sems, data->semflg); 00220 if (data->semid == -1) { 00221 return false; 00222 } else { 00223 struct semid_ds semds; 00224 union semun s; 00225 s.buf = &semds; 00226 if (semctl(data->semid, 0, IPC_STAT, s) != -1) { 00227 return true; 00228 } else { 00229 data->semid = -1; 00230 return false; 00231 } 00232 } 00233 } else { 00234 struct semid_ds semds; 00235 union semun s; 00236 s.buf = &semds; 00237 if (semctl(data->semid, 0, IPC_STAT, s) != -1) { 00238 return true; 00239 } else { 00240 data->semid = -1; 00241 return false; 00242 } 00243 } 00244 } 00245 00246 /** Lock resources on the semaphore set. 00247 * Locks num resources on semaphore sem_num. 00248 * @param sem_num The semaphore number in the set 00249 * @param num How many resources to lock? Positive number. 00250 * @exception InterruptedException Operation was interrupted (for instance by a signal) 00251 * @exception SemCannotLockException Semaphore cannot be locked 00252 * @exception SemInvalidException Semaphore set is invalid 00253 */ 00254 void 00255 SemaphoreSet::lock(unsigned short sem_num, short num) 00256 { 00257 if ( data->semid == -1 ) throw SemInvalidException(); 00258 00259 struct sembuf sop; 00260 sop.sem_num = sem_num; 00261 sop.sem_op = (short)((num <= 0) ? num : -num); 00262 sop.sem_flg = 0; 00263 if ( semop(data->semid, &sop, 1) != 0 ) { 00264 if ( errno == EINTR ) throw InterruptedException(); 00265 else throw SemCannotLockException(); 00266 } 00267 } 00268 00269 00270 /** Try to lock resources on the semaphore set. 00271 * @param sem_num The semaphore number in the set 00272 * @param num How many resources to lock? Positive number. 00273 * @return true, if the semaphore could be locked, false otherwise 00274 * @exception InterruptedException Operation was interrupted (for instance by a signal) 00275 * @exception SemCannotLockException Semaphore cannot be locked 00276 * @exception SemInvalidException Semaphore set is invalid 00277 */ 00278 bool 00279 SemaphoreSet::try_lock(unsigned short sem_num, short num) 00280 { 00281 if ( data->semid == -1 ) throw SemInvalidException(); 00282 00283 struct sembuf sop; 00284 sop.sem_num = sem_num; 00285 sop.sem_op = (short)((num <= 0) ? num : -num); 00286 sop.sem_flg = IPC_NOWAIT; 00287 if ( semop(data->semid, &sop, 1) != 0 ) { 00288 if (errno == EAGAIN) { 00289 return false; 00290 } else if ( errno == EINTR ) { 00291 throw InterruptedException(); 00292 } else { 00293 throw SemCannotLockException(); 00294 } 00295 } 00296 return true; 00297 } 00298 00299 00300 /** Unlock resources on the semaphore set. 00301 * @param sem_num The semaphore number in the set 00302 * @param num How many resources to unlock? Negative number. 00303 * @exception InterruptedException Operation was interrupted (for instance by a signal) 00304 * @exception SemCannotUnlockException Semaphore cannot be unlocked 00305 * @exception SemInvalidException Semaphore set is invalid 00306 */ 00307 void 00308 SemaphoreSet::unlock(unsigned short sem_num, short num) 00309 { 00310 if ( data->semid == -1 ) throw SemInvalidException(); 00311 00312 struct sembuf sop; 00313 sop.sem_num = sem_num; 00314 sop.sem_op = (short)((num >= 0) ? num : -num); 00315 sop.sem_flg = 0; 00316 if ( semop(data->semid, &sop, 1) != 0 ) { 00317 if ( errno == EINTR ) throw InterruptedException(); 00318 else throw SemCannotUnlockException(); 00319 } 00320 } 00321 00322 00323 /** Set the semaphore value. 00324 * @param sem_num The semaphore number in the set 00325 * @param val The value to set 00326 * @exception SemCannotSetValException Cannot set value 00327 */ 00328 void 00329 SemaphoreSet::set_value(int sem_num, int val) 00330 { 00331 if ( data->semid == -1 ) throw SemInvalidException(); 00332 00333 union semun s; 00334 s.val = val; 00335 00336 if ( semctl(data->semid, sem_num, SETVAL, s) == -1 ) { 00337 throw SemCannotSetValException(); 00338 } 00339 } 00340 00341 00342 /** Get the semaphore value. 00343 * @param sem_num The semaphore number in the set 00344 * @return value of the semaphore 00345 * @exception SemInvalidException Semaphore set is invalid 00346 */ 00347 int 00348 SemaphoreSet::get_value(int sem_num) 00349 { 00350 if ( data->semid == -1 ) throw SemInvalidException(); 00351 00352 return ( semctl(data->semid, sem_num, GETVAL, 0) != 0 ); 00353 } 00354 00355 00356 /** Get key of semaphore. 00357 * @return Key of semaphore as listed by ipcs. 00358 */ 00359 int 00360 SemaphoreSet::key() 00361 { 00362 return data->key; 00363 } 00364 00365 00366 /** Set if semaphore set should be destroyed on delete. 00367 * If this is set to true the semaphore set is destroyed from the system if this 00368 * instance is deleted. 00369 * @param destroy set to true, if semaphore set should be destroyed on delete, 00370 * false otherwise 00371 */ 00372 void 00373 SemaphoreSet::set_destroy_on_delete(bool destroy) 00374 { 00375 destroy_on_delete = destroy; 00376 } 00377 00378 00379 /* ================================================================== 00380 * STATICs 00381 */ 00382 00383 /** Get a non-zero free key 00384 * Scans the key space sequentially until a non-zero unused key is found. Not 00385 * that using this can cause a race-condition. You are in most cases better off 00386 * using the appropriate constructor that automatically finds a free key. 00387 * @return 0, if no free key could be found, otherwise the non-zero unused key 00388 */ 00389 int 00390 SemaphoreSet::free_key() 00391 { 00392 bool found = false; 00393 int key; 00394 int semid; 00395 for (key = 1; key < INT_MAX; ++key) { 00396 semid = semget(key, 1, IPC_CREAT | IPC_EXCL); 00397 if ( semid != -1 ) { 00398 // valid semaphore found 00399 semctl(semid, 0, IPC_RMID, 0); 00400 found = true; 00401 break; 00402 } 00403 } 00404 return (found ? key : 0); 00405 } 00406 00407 00408 /** Destroy a semaphore set. 00409 * Destroy the semaphore denoted by key. No tests are done if some other 00410 * process is using this semaphore. Use with care! 00411 * @param key key of the semaphore set 00412 */ 00413 void 00414 SemaphoreSet::destroy(int key) 00415 { 00416 int semid = semget(key, 0, 0); 00417 if ( semid == -1 ) return; 00418 semctl(semid, 0, IPC_RMID, 0); 00419 } 00420 00421 00422 } // end namespace fawkes