Token.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 //=============================================================================
00004 /**
00005  *  @file    Token.h
00006  *
00007  *  Token.h,v 4.48 2006/05/30 13:15:25 schmidt Exp
00008  *
00009  *  @author Original author
00010  *  @author Karl-Heinz Dorn (kdorn@erlh.siemens.de)
00011  *  @author Ported to ACE by
00012  *  @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
00013  */
00014 //=============================================================================
00015 
00016 #ifndef ACE_TOKEN_H
00017 #define ACE_TOKEN_H
00018 #include /**/ "ace/pre.h"
00019 
00020 #include "ace/ACE_export.h"
00021 
00022 #if !defined (ACE_LACKS_PRAGMA_ONCE)
00023 # pragma once
00024 #endif /* ACE_LACKS_PRAGMA_ONCE */
00025 
00026 #include "ace/Null_Mutex.h"
00027 
00028 #if defined (ACE_HAS_THREADS)
00029 
00030 #include "ace/Thread_Mutex.h"
00031 
00032 #if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || defined (ACE_VXWORKS)
00033 // If platforms support semaphores with timed wait, then we use semaphores instead of c.v.
00034 # define ACE_TOKEN_USES_SEMAPHORE
00035 #endif /* (ACE_WIN32 && !ACE_HAS_WINCE) || VXWORKS */
00036 
00037 #if defined (ACE_TOKEN_USES_SEMAPHORE)
00038 #  include "ace/Semaphore.h"
00039 #endif /* ACE_TOKEN_USES_SEMAPHORE */
00040 
00041 #include "ace/Condition_Thread_Mutex.h"
00042 
00043 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00044 
00045 class ACE_Time_Value;
00046 
00047 /**
00048  * @class ACE_Token
00049  *
00050  * @brief Class that acquires, renews, and releases a synchronization
00051  * token that is serviced in strict FIFO/LIFO ordering and that also
00052  * supports (1) recursion and (2) readers/writer semantics.
00053  *
00054  * This class is a more general-purpose synchronization mechanism
00055  * than many native OS mutexes.  For example, it implements
00056  * "recursive mutex" semantics, where a thread that owns the token
00057  * can reacquire it without deadlocking.  If the same thread calls
00058  * <acquire> multiple times, however, it must call <release> an
00059  * equal number of times before the token is actually released.
00060  * Threads that are blocked awaiting the token are serviced in
00061  * strict FIFO/LIFO order as other threads release the token (Solaris
00062  * and Pthread mutexes don't strictly enforce an acquisition
00063  * order).  There are two lists within the class.  Write
00064  * acquires always have higher priority over read acquires.  Which
00065  * means, if you use both write/read operations, care must be
00066  * taken to avoid starvation on the readers.  Notice that the
00067  * read/write acquire operations do not have the usual semantic of
00068  * reader/writer locks.  Only one reader can acquire the token at
00069  * a time (which is different from the usual reader/writer locks
00070  * where several readers can acquire a lock at the same time as
00071  * long as there is no writer waiting for the lock).  We choose
00072  * the names to (1) borrow the semantic to give writers higher
00073  * priority and (2) support a common interface for all locking
00074  * classes in ACE.
00075  */
00076 class ACE_Export ACE_Token
00077 {
00078 public:
00079 
00080   /**
00081    * Available queueing strategies.
00082    */
00083   enum QUEUEING_STRATEGY
00084   {
00085     /// FIFO, First In, First Out.
00086     FIFO = -1,
00087     /// LIFO, Last In, First Out
00088     LIFO = 0
00089   };
00090 
00091   // = Initialization and termination.
00092 
00093   /// Constructor
00094   ACE_Token (const ACE_TCHAR *name = 0, void * = 0);
00095 
00096   /// Destructor
00097   virtual ~ACE_Token (void);
00098 
00099   // = Strategies
00100 
00101   /// Retrieve the current queueing strategy.
00102   int queueing_strategy (void);
00103 
00104   /// Set the queueing strategy.
00105   void queueing_strategy (int queueing_strategy);
00106 
00107   // = Synchronization operations.
00108 
00109   /**
00110    * Acquire the token, sleeping until it is obtained or until the
00111    * expiration of <timeout>, which is treated as "absolute" time.  If
00112    * some other thread currently holds the token then <sleep_hook> is
00113    * called before our thread goes to sleep.  This <sleep_hook> can be
00114    * used by the requesting thread to unblock a token-holder that is
00115    * sleeping, e.g., by means of writing to a pipe (the ACE
00116    * ACE_Reactor uses this functionality).  Return values: 0 if
00117    * acquires without calling <sleep_hook> 1 if <sleep_hook> is
00118    * called.  2 if the token is signaled.  -1 if failure or timeout
00119    * occurs (if timeout occurs errno == ETIME) If <timeout> ==
00120    * <&ACE_Time_Value::zero> then acquire has polling semantics (and
00121    * does *not* call <sleep_hook>).
00122    */
00123   int acquire (void (*sleep_hook)(void *),
00124                void *arg = 0,
00125                ACE_Time_Value *timeout = 0);
00126 
00127   /**
00128    * This behaves just like the previous <acquire> method, except that
00129    * it invokes the virtual function called <sleep_hook> that can be
00130    * overridden by a subclass of ACE_Token.
00131    */
00132   int acquire (ACE_Time_Value *timeout = 0);
00133 
00134   /**
00135    * This should be overridden by a subclass to define the appropriate
00136    * behavior before <acquire> goes to sleep.  By default, this is a
00137    * no-op...
00138    */
00139   virtual void sleep_hook (void);
00140 
00141   /**
00142    * An optimized method that efficiently reacquires the token if no
00143    * other threads are waiting.  This is useful for situations where
00144    * you don't want to degrade the quality of service if there are
00145    * other threads waiting to get the token.  If <requeue_position> ==
00146    * -1 and there are other threads waiting to obtain the token we are
00147    * queued according to the queueing strategy.  If <requeue_position>
00148    * > -1 then it indicates how many entries to skip over before
00149    * inserting our thread into the list of waiters (e.g.,
00150    * <requeue_position> == 0 means "insert at front of the queue").
00151    * Renew has the rather odd semantics such that if there are other
00152    * waiting threads it will give up the token even if the
00153    * nesting_level_ > 1.  I'm not sure if this is really the right
00154    * thing to do (since it makes it possible for shared data to be
00155    * changed unexpectedly) so use with caution...  This method
00156    * maintians the original token priority.  As in <acquire>, the
00157    * <timeout> value is an absolute time.
00158    */
00159   int renew (int requeue_position = 0,
00160              ACE_Time_Value *timeout = 0);
00161 
00162   /// Become interface-compliant with other lock mechanisms (implements
00163   /// a non-blocking <acquire>).
00164   int tryacquire (void);
00165 
00166   /// Shuts down the ACE_Token instance.
00167   int remove (void);
00168 
00169   /// Relinquish the token.  If there are any waiters then the next one
00170   /// in line gets it.
00171   int release (void);
00172 
00173   /// Behaves like acquire() but at a lower priority.  It should probably
00174   /// be called acquire_yield() since the semantics aren't really
00175   /// what's commonly expected for readers/writer locks.  See the class
00176   /// documentation above for more details.
00177   int acquire_read (void);
00178 
00179   /// Behaves like acquire() but at a lower priority.  It should probably
00180   /// be called acquire_yield() since the semantics aren't really
00181   /// what's commonly expected for readers/writer locks.  See the class
00182   /// documentation above for more details.
00183   int acquire_read (void (*sleep_hook)(void *),
00184                     void *arg = 0,
00185                     ACE_Time_Value *timeout = 0);
00186 
00187   /// Calls acquire().
00188   int acquire_write (void);
00189 
00190   /// Calls acquire().
00191   int acquire_write (void (*sleep_hook)(void *),
00192                      void *arg = 0,
00193                      ACE_Time_Value *timeout = 0);
00194 
00195   /// Lower priority try_acquire().
00196   int tryacquire_read (void);
00197 
00198   /// Just calls <tryacquire>.
00199   int tryacquire_write (void);
00200 
00201   /// Assumes the caller has acquired the token and returns 0.
00202   int tryacquire_write_upgrade (void);
00203 
00204   // = Accessor methods.
00205 
00206   /// Return the number of threads that are currently waiting to get
00207   /// the token.
00208   int waiters (void);
00209 
00210   /// Return the id of the current thread that owns the token.
00211   ACE_thread_t current_owner (void);
00212 
00213   /// Dump the state of an object.
00214   void dump (void) const;
00215 
00216   /// Declare the dynamic allocation hooks.
00217   ACE_ALLOC_HOOK_DECLARE;
00218 
00219   /// The following structure implements a LIFO/FIFO queue of waiter threads
00220   /// that are asleep waiting to obtain the token.
00221   struct ACE_Token_Queue_Entry
00222   {
00223     /// Constructor
00224     ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
00225                            ACE_thread_t t_id);
00226 
00227     /// Constructor using a pre-allocated attributes
00228     ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
00229                            ACE_thread_t t_id,
00230                            ACE_Condition_Attributes &attributes);
00231 
00232     /// Entry blocks on the token.
00233     int wait (ACE_Time_Value *timeout, ACE_Thread_Mutex &lock);
00234 
00235     /// Notify (unblock) the entry.
00236     int signal (void);
00237 
00238     /// Pointer to next waiter.
00239     ACE_Token_Queue_Entry *next_;
00240 
00241     /// ACE_Thread id of this waiter.
00242     ACE_thread_t thread_id_;
00243 
00244 #if defined (ACE_TOKEN_USES_SEMAPHORE)
00245     /// ACE_Semaphore object used to wake up waiter when it can run again.
00246     ACE_Semaphore cv_;
00247 #else
00248     /// ACE_Condition object used to wake up waiter when it can run again.
00249     ACE_Condition_Thread_Mutex cv_;
00250 #endif /* ACE_TOKEN_USES_SEMAPHORE */
00251 
00252     /// Ok to run.
00253     int runable_;
00254   };
00255 
00256 private:
00257   enum ACE_Token_Op_Type
00258   {
00259     READ_TOKEN = 1,
00260     WRITE_TOKEN
00261   };
00262 
00263   struct ACE_Token_Queue
00264   {
00265     /// Constructor
00266     ACE_Token_Queue (void);
00267 
00268     /// Remove a waiter from the queue.
00269     void remove_entry (ACE_Token_Queue_Entry *);
00270 
00271     /// Insert a waiter into the queue.
00272     void insert_entry (ACE_Token_Queue_Entry &entry,
00273                        int requeue_position = -1);
00274 
00275     /// Head of the list of waiting threads.
00276     ACE_Token_Queue_Entry *head_;
00277 
00278     /// Tail of the list of waiting threads.
00279     ACE_Token_Queue_Entry *tail_;
00280   };
00281 
00282   /// Implements the <acquire> and <tryacquire> methods above.
00283   int shared_acquire (void (*sleep_hook_func)(void *),
00284                       void *arg,
00285                       ACE_Time_Value *timeout,
00286                       ACE_Token_Op_Type op_type);
00287 
00288   /// Wake next in line for ownership.
00289   void wakeup_next_waiter (void);
00290 
00291   /// A queue of writer threads.
00292   ACE_Token_Queue writers_;
00293 
00294   /// A queue of reader threads.
00295   ACE_Token_Queue readers_;
00296 
00297   /// ACE_Thread_Mutex used to lock internal data structures.
00298   ACE_Thread_Mutex lock_;
00299 
00300   /// Current owner of the token.
00301   ACE_thread_t owner_;
00302 
00303   /// Some thread (i.e., <owner_>) is using the token.  We need this
00304   /// extra variable to deal with POSIX pthreads madness...
00305   int in_use_;
00306 
00307   /// Number of waiters.
00308   int waiters_;
00309 
00310   /// Current nesting level.
00311   int nesting_level_;
00312 
00313   /// The attributes for the condition variables, optimizes lock time.
00314   ACE_Condition_Attributes attributes_;
00315 
00316   /// Queueing strategy, LIFO/FIFO.
00317   int queueing_strategy_;
00318 };
00319 
00320 ACE_END_VERSIONED_NAMESPACE_DECL
00321 
00322 #else
00323 
00324 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00325 
00326 class ACE_Export ACE_Token
00327 {
00328 public:
00329   int queueing_strategy (void) { ACE_NOTSUP_RETURN (-1); }
00330   void queueing_strategy (int /*queueing_strategy*/) { }
00331   int acquire (ACE_Time_Value * = 0) { ACE_NOTSUP_RETURN (-1); }
00332   int tryacquire (void) { ACE_NOTSUP_RETURN (-1); }
00333   int remove (void) { ACE_NOTSUP_RETURN (-1); }
00334   int release (void) { ACE_NOTSUP_RETURN (-1); }
00335 };
00336 
00337 ACE_END_VERSIONED_NAMESPACE_DECL
00338 
00339 #endif /* ACE_HAS_THREADS */
00340 
00341 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00342 
00343 class ACE_Export ACE_Noop_Token : public ACE_Null_Mutex
00344 {
00345 public:
00346   /// Queueing strategy
00347   enum QUEUEING_STRATEGY
00348   {
00349     FIFO = -1,
00350     LIFO = 0
00351   };
00352 
00353   /// Get queueing strategy.
00354   int queueing_strategy (void);
00355 
00356   /// Set queueing strategy.
00357   void queueing_strategy (int queueing_strategy);
00358 
00359   int renew (int = 0, ACE_Time_Value * =0);
00360 
00361   /// Dump the state of an object.
00362   void dump (void) const;
00363 
00364   /// Declare the dynamic allocation hooks.
00365   ACE_ALLOC_HOOK_DECLARE;
00366 };
00367 
00368 ACE_END_VERSIONED_NAMESPACE_DECL
00369 
00370 #if defined (__ACE_INLINE__)
00371 #include "ace/Token.inl"
00372 #endif /* __ACE_INLINE__ */
00373 
00374 
00375 #include /**/ "ace/post.h"
00376 #endif /* ACE_TOKEN_H */

Generated on Thu Nov 9 09:42:08 2006 for ACE by doxygen 1.3.6