Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Token.h

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

Generated on Mon Jun 16 11:21:56 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002