00001 // -*- C++ -*- 00002 00003 //============================================================================= 00004 /** 00005 * @file Token.h 00006 * 00007 * $Id: Token.h 77152 2007-02-15 13:41:25Z johnnyw $ 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 @a 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 @a 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 * @a 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 */