Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SemaphoreManager.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_SemaphoreManager_h_
00003 #define INCLUDED_SemaphoreManager_h_
00004 
00005 #ifdef PLATFORM_APERIOS
00006 #  warning SemaphoreManager is not Aperios compatable, this is not going to compile
00007 #else
00008 
00009 #include "ListMemBuf.h"
00010 #include "Shared/attributes.h"
00011 #include <sys/types.h>
00012 #include <sys/sem.h>
00013 
00014 #ifndef SYSTEM_MAX_SEM
00015 //! Ideally, this would be SEMMSL, but that is hard to portably determine at compile time
00016 /*! If you can't increase your system's SEMMSL (and possibly SEMMNS), you
00017  *  may want to consider decreasing this. */
00018 #define SYSTEM_MAX_SEM 250
00019 #endif
00020 
00021 //! initializes, manages, and releases a set of System V style semaphores
00022 /*! Should be initialized pre-fork into a shared region */
00023 class SemaphoreManager {
00024 protected:
00025   typedef ListMemBuf<bool,SYSTEM_MAX_SEM> sems_t; //!< shorthand for the type of #sems
00026   
00027 public:
00028   //! wouldn't want to claim the entire system's worth, even if we could
00029   static const unsigned int MAX_SEM=SYSTEM_MAX_SEM;
00030 
00031   //! shorthand for the semaphore indexing type
00032   typedef sems_t::index_t semid_t;
00033   //! specify options for how to handle EINTR (signal occurred) error condition during a semaphore operation, see setInterruptPolicy()
00034   enum IntrPolicy_t {
00035     INTR_CANCEL_VERBOSE, //!< give up, return failure, display error message on console
00036     INTR_CANCEL, //!< give up, return failure
00037     INTR_RETRY_VERBOSE, //!< just repeat semaphore operation, display error message on console
00038     INTR_RETRY, //!< just repeat semaphore operation
00039     INTR_THROW_VERBOSE, //!< throw a std::runtime_error exception, display error message on console
00040     INTR_THROW, //!< throw a std::runtime_error exception
00041     INTR_EXIT, //!< kill process, with error message
00042   };
00043   
00044   //! Creates a SemaphoreManager with room for sems_t::MAX_ENTRIES entries
00045   /*! 2 of these entries are reserved for internal use, so user code
00046    *  will actually only have access to sems_t::MAX_ENTRIES-2 entries.
00047    *  Use available() to determine this value at runtime. */
00048   SemaphoreManager();
00049   
00050   //! Creates a SemaphoreManager with room for @a numRequest entries
00051   /*! adds 2 for SemaphoreManager's own reference count and mutex lock,
00052    *  so you'll actually have @a numRequest semaphores available */
00053   explicit SemaphoreManager(unsigned int numRequest);
00054   
00055   SemaphoreManager(const SemaphoreManager& mm); //!< copy supported
00056   SemaphoreManager& operator=(const SemaphoreManager& mm); //!< assignment supported
00057   ~SemaphoreManager(); //!< destructor
00058   
00059   //! call this on semaphores in shared memory regions if a fork is about to occur so reference counts can be updated for the other process
00060   void aboutToFork();
00061   //! call this if semaphores need to be released during an emergency shutdown (otherwise semaphore sets can leak past process shutdown -- bad system design IMHO!)
00062   void faultShutdown();
00063   //! returns true if #semid is invalid, indicating further semaphore operations are bogus
00064   bool hadFault() const { return semid==-1; }
00065 
00066   //! returns a new semaphore id, or invalid() if none are available
00067   semid_t getSemaphore() ATTR_must_check;
00068   //! marks a semaphore as available for reassignment
00069   void releaseSemaphore(semid_t id); 
00070 
00071   //! return the semaphore's interrupt policy (doesn't check @a id validity)
00072   IntrPolicy_t getInterruptPolicy(semid_t id) const { return intrPolicy[id]; }
00073   //! set the semaphore's interrupt policy (doesn't check @a id validity)
00074   void setInterruptPolicy(semid_t id, IntrPolicy_t p) { intrPolicy[id]=p; }
00075   
00076   //! lowers a semaphore's value by @a x, optionally blocking if the value would go negative until it is raised enough to succeed
00077   /*! returns true if the semaphore was successfully lowered.*/
00078   bool lower(semid_t id, unsigned int x, bool block=true) const;
00079   //! raises a semaphore's value by @a x
00080   void raise(semid_t id, unsigned int x) const;
00081 
00082   int getValue(semid_t id) const; //!< returns the semaphore's value
00083   void setValue(semid_t id, int x) const; //!< sets the semaphore's value
00084   
00085   //! tests if the semaphore's value is zero, optionally blocking until it is
00086   /*! returns true if the semaphore's value is zero.
00087    *  @see testZero_add(), add_testZero() */
00088   bool testZero(semid_t id, bool block=true) const;
00089   //! tests if the semaphore's value is zero, optionally blocking until it is, and then adding @a x
00090   /*! If @a x is negative, then @a addblock will cause it to block
00091    *  again until someone else raises the semaphore.  Otherwise, the
00092    *  add should be performed as an atomic unit with the test.  If @a
00093    *  x is non-negative, then the add should never block.
00094    *  @see add_testZero(), testZero() */
00095   bool testZero_add(semid_t id, unsigned int x, bool testblock=true, bool addblock=true) const;
00096   //! adds @a x to the semaphore's value, optionally blocking in the case that @a x is negative and larger than the semaphore's value.  After adding, test whether the semaphore is zero, optionally blocking again until it is.
00097   /*! If no blocking is required (e.g. @a x is positive) then the add
00098    *  and test should be an atomic pair.
00099    *  @see testZero_add(), testZero() */
00100   bool add_testZero(semid_t id, unsigned int x, bool addblock=true, bool testblock=true) const;
00101   
00102   //! returns the number of semaphores currently available in the set
00103   unsigned int available() const { return sems_t::MAX_ENTRIES-sems.size(); }
00104   //! returns the number of semaphores which have been used
00105   /*! the SemaphoreManager requires 2 semaphores from the set, one for
00106    *  reference counting and one for mutual exclusion during function
00107    *  calls */
00108   unsigned int used() const { return sems.size()-(sems_t::MAX_ENTRIES-nsem); }
00109   //! returns the "invalid" id value, for testing against getSemaphore
00110   semid_t invalid() const { return sems.end(); }
00111 
00112 protected:
00113   void init(); //!< basic initialization called by the constructor -- don't call twice
00114 
00115   sems_t sems; //!< tracks which semaphores have been handed out; the bool value isn't actually used
00116   unsigned int nsem; //!< number of real semaphores in the set obtained from the system
00117   int semid; //!< the system's identifier for the set
00118   semid_t mysem; //!< a lock semaphore for management operations on the set (handing out or taking back semaphores from clients)
00119   semid_t refc; //!< a reference count of this semaphore set -- when it goes back to 0, the set is released from the system
00120   IntrPolicy_t intrPolicy[sems_t::MAX_ENTRIES]; //!< interrupt policy for each semaphore
00121 };
00122 
00123 /*! @file
00124  * @brief Defines SemaphoreManager, which initializes, manages, and releases a set of System V style semaphores
00125  * @author ejt (Creator)
00126  *
00127  * $Author: ejt $
00128  * $Name: tekkotsu-3_0 $
00129  * $Revision: 1.12 $
00130  * $State: Exp $
00131  * $Date: 2006/05/08 22:06:35 $
00132  */
00133 
00134 #endif //Aperios check
00135 
00136 #endif //INCLUDED
00137 

Tekkotsu v3.0
Generated Wed Oct 4 00:03:46 2006 by Doxygen 1.4.7