semset.cpp

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

Generated on 1 Mar 2011 for Fawkes API by  doxygen 1.6.1