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

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:50 2016 by Doxygen 1.6.3