Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Token.h
blob4c3bcc80b5a8a255d21a21f8b45222d29c2ecfb2
1 // -*- C++ -*-
3 //=============================================================================
4 /**
5 * @file Token.h
7 * @author Original author
8 * @author Karl-Heinz Dorn (kdorn@erlh.siemens.de)
9 * @author Ported to ACE by
10 * @author Douglas C. Schmidt (d.schmidt@vanderbilt.edu)
12 //=============================================================================
14 #ifndef ACE_TOKEN_H
15 #define ACE_TOKEN_H
16 #include /**/ "ace/pre.h"
18 #include /**/ "ace/ACE_export.h"
20 #if !defined (ACE_LACKS_PRAGMA_ONCE)
21 # pragma once
22 #endif /* ACE_LACKS_PRAGMA_ONCE */
24 #include "ace/Null_Mutex.h"
26 #if defined (ACE_HAS_THREADS)
28 #include "ace/Thread_Mutex.h"
30 #if defined (ACE_WIN32) || defined (ACE_HAS_VXTHREADS)
31 // If platforms support semaphores with timed wait, then we use semaphores instead of c.v.
32 # define ACE_TOKEN_USES_SEMAPHORE
33 #endif /* ACE_WIN32 || ACE_HAS_VXTHREADS */
35 #if defined (ACE_TOKEN_USES_SEMAPHORE)
36 # include "ace/Semaphore.h"
37 #endif /* ACE_TOKEN_USES_SEMAPHORE */
39 #include "ace/Condition_Thread_Mutex.h"
41 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
43 class ACE_Time_Value;
45 /**
46 * @class ACE_Token
48 * @brief Class that acquires, renews, and releases a synchronization
49 * token that is serviced in strict FIFO/LIFO ordering and that also
50 * supports (1) recursion and (2) readers/writer semantics.
52 * This class is a more general-purpose synchronization mechanism
53 * than many native OS mutexes. For example, it implements
54 * "recursive mutex" semantics, where a thread that owns the token
55 * can reacquire it without deadlocking. If the same thread calls
56 * <acquire> multiple times, however, it must call <release> an
57 * equal number of times before the token is actually released.
58 * Threads that are blocked awaiting the token are serviced in
59 * strict FIFO/LIFO order as other threads release the token
60 * (Pthread mutexes don't strictly enforce an acquisition
61 * order). There are two lists within the class. Write
62 * acquires always have higher priority over read acquires. Which
63 * means, if you use both write/read operations, care must be
64 * taken to avoid starvation on the readers. Notice that the
65 * read/write acquire operations do not have the usual semantic of
66 * reader/writer locks. Only one reader can acquire the token at
67 * a time (which is different from the usual reader/writer locks
68 * where several readers can acquire a lock at the same time as
69 * long as there is no writer waiting for the lock). We choose
70 * the names to (1) borrow the semantic to give writers higher
71 * priority and (2) support a common interface for all locking
72 * classes in ACE.
74 class ACE_Export ACE_Token
76 public:
77 /**
78 * Available queueing strategies.
80 enum QUEUEING_STRATEGY
82 /// FIFO, First In, First Out.
83 FIFO = -1,
84 /// LIFO, Last In, First Out
85 LIFO = 0
88 /// Constructor
89 ACE_Token (const ACE_TCHAR *name = 0, void * = 0);
91 /// Destructor
92 virtual ~ACE_Token ();
94 // = Strategies
96 /// Retrieve the current queueing strategy.
97 int queueing_strategy ();
99 /// Set the queueing strategy.
100 void queueing_strategy (int queueing_strategy);
102 // = Synchronization operations.
105 * Acquire the token, sleeping until it is obtained or until the
106 * expiration of @a timeout, which is treated as "absolute" time. If
107 * some other thread currently holds the token then <sleep_hook> is
108 * called before our thread goes to sleep. This <sleep_hook> can be
109 * used by the requesting thread to unblock a token-holder that is
110 * sleeping, e.g., by means of writing to a pipe (the ACE
111 * ACE_Reactor uses this functionality). Return values: 0 if
112 * acquires without calling <sleep_hook> 1 if <sleep_hook> is
113 * called. 2 if the token is signaled. -1 if failure or timeout
114 * occurs (if timeout occurs errno == ETIME) If @a timeout ==
115 * <&ACE_Time_Value::zero> then acquire has polling semantics (and
116 * does *not* call <sleep_hook>).
118 int acquire (void (*sleep_hook)(void *),
119 void *arg = 0,
120 ACE_Time_Value *timeout = 0);
123 * This behaves just like the previous <acquire> method, except that
124 * it invokes the virtual function called <sleep_hook> that can be
125 * overridden by a subclass of ACE_Token.
127 int acquire (ACE_Time_Value *timeout = 0);
130 * This should be overridden by a subclass to define the appropriate
131 * behavior before <acquire> goes to sleep. By default, this is a
132 * no-op...
134 virtual void sleep_hook ();
137 * An optimized method that efficiently reacquires the token if no
138 * other threads are waiting. This is useful for situations where
139 * you don't want to degrade the quality of service if there are
140 * other threads waiting to get the token. If <requeue_position> ==
141 * -1 and there are other threads waiting to obtain the token we are
142 * queued according to the queueing strategy. If <requeue_position>
143 * > -1 then it indicates how many entries to skip over before
144 * inserting our thread into the list of waiters (e.g.,
145 * <requeue_position> == 0 means "insert at front of the queue").
146 * Renew has the rather odd semantics such that if there are other
147 * waiting threads it will give up the token even if the
148 * nesting_level_ > 1. I'm not sure if this is really the right
149 * thing to do (since it makes it possible for shared data to be
150 * changed unexpectedly) so use with caution... This method
151 * maintians the original token priority. As in <acquire>, the
152 * @a timeout value is an absolute time.
154 int renew (int requeue_position = 0,
155 ACE_Time_Value *timeout = 0);
157 /// Become interface-compliant with other lock mechanisms (implements
158 /// a non-blocking <acquire>).
159 int tryacquire ();
161 /// Shuts down the ACE_Token instance.
162 int remove ();
164 /// Relinquish the token. If there are any waiters then the next one
165 /// in line gets it.
166 int release ();
168 /// Behaves like acquire() but at a lower priority. It should probably
169 /// be called acquire_yield() since the semantics aren't really
170 /// what's commonly expected for readers/writer locks. See the class
171 /// documentation above for more details.
172 int acquire_read ();
174 /// Behaves like acquire() but at a lower priority. It should probably
175 /// be called acquire_yield() since the semantics aren't really
176 /// what's commonly expected for readers/writer locks. See the class
177 /// documentation above for more details.
178 int acquire_read (void (*sleep_hook)(void *),
179 void *arg = 0,
180 ACE_Time_Value *timeout = 0);
182 /// Calls acquire().
183 int acquire_write ();
185 /// Calls acquire().
186 int acquire_write (void (*sleep_hook)(void *),
187 void *arg = 0,
188 ACE_Time_Value *timeout = 0);
190 /// Lower priority try_acquire().
191 int tryacquire_read ();
193 /// Just calls <tryacquire>.
194 int tryacquire_write ();
196 /// Assumes the caller has acquired the token and returns 0.
197 int tryacquire_write_upgrade ();
199 // = Accessor methods.
201 /// Return the number of threads that are currently waiting to get
202 /// the token.
203 int waiters ();
205 /// Return the id of the current thread that owns the token.
206 ACE_thread_t current_owner ();
208 /// Dump the state of an object.
209 void dump () const;
211 /// Declare the dynamic allocation hooks.
212 ACE_ALLOC_HOOK_DECLARE;
214 /// The following structure implements a LIFO/FIFO queue of waiter threads
215 /// that are asleep waiting to obtain the token.
216 struct ACE_Token_Queue_Entry
218 /// Constructor
219 ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
220 ACE_thread_t t_id);
222 /// Constructor using a pre-allocated attributes
223 ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
224 ACE_thread_t t_id,
225 ACE_Condition_Attributes &attributes);
227 /// Entry blocks on the token.
228 int wait (ACE_Time_Value *timeout, ACE_Thread_Mutex &lock);
230 /// Notify (unblock) the entry.
231 int signal ();
233 /// Pointer to next waiter.
234 ACE_Token_Queue_Entry *next_;
236 /// ACE_Thread id of this waiter.
237 ACE_thread_t thread_id_;
239 #if defined (ACE_TOKEN_USES_SEMAPHORE)
240 /// ACE_Semaphore object used to wake up waiter when it can run again.
241 ACE_Semaphore cv_;
242 #else
243 /// ACE_Condition object used to wake up waiter when it can run again.
244 ACE_Condition_Thread_Mutex cv_;
245 #endif /* ACE_TOKEN_USES_SEMAPHORE */
247 /// Ok to run.
248 int runable_;
251 private:
252 enum ACE_Token_Op_Type
254 READ_TOKEN = 1,
255 WRITE_TOKEN
258 struct ACE_Token_Queue
260 /// Constructor
261 ACE_Token_Queue ();
263 /// Remove a waiter from the queue.
264 void remove_entry (ACE_Token_Queue_Entry *);
266 /// Insert a waiter into the queue.
267 void insert_entry (ACE_Token_Queue_Entry &entry,
268 int requeue_position = -1);
270 /// Head of the list of waiting threads.
271 ACE_Token_Queue_Entry *head_;
273 /// Tail of the list of waiting threads.
274 ACE_Token_Queue_Entry *tail_;
277 /// Implements the <acquire> and <tryacquire> methods above.
278 int shared_acquire (void (*sleep_hook_func)(void *),
279 void *arg,
280 ACE_Time_Value *timeout,
281 ACE_Token_Op_Type op_type);
283 /// Wake next in line for ownership.
284 void wakeup_next_waiter ();
286 /// A queue of writer threads.
287 ACE_Token_Queue writers_;
289 /// A queue of reader threads.
290 ACE_Token_Queue readers_;
292 /// ACE_Thread_Mutex used to lock internal data structures.
293 ACE_Thread_Mutex lock_;
295 /// Current owner of the token.
296 ACE_thread_t owner_;
298 /// Some thread (i.e., <owner_>) is using the token. We need this
299 /// extra variable to deal with POSIX pthreads madness...
300 int in_use_;
302 /// Number of waiters.
303 int waiters_;
305 /// Current nesting level.
306 int nesting_level_;
308 /// The attributes for the condition variables, optimizes lock time.
309 ACE_Condition_Attributes attributes_;
311 /// Queueing strategy, LIFO/FIFO.
312 int queueing_strategy_;
315 ACE_END_VERSIONED_NAMESPACE_DECL
317 #else
319 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
321 class ACE_Export ACE_Token
323 public:
324 int queueing_strategy () { ACE_NOTSUP_RETURN (-1); }
325 void queueing_strategy (int /*queueing_strategy*/) { }
326 int acquire (ACE_Time_Value * = 0) { ACE_NOTSUP_RETURN (-1); }
327 int tryacquire () { ACE_NOTSUP_RETURN (-1); }
328 int remove () { ACE_NOTSUP_RETURN (-1); }
329 int release () { ACE_NOTSUP_RETURN (-1); }
332 ACE_END_VERSIONED_NAMESPACE_DECL
334 #endif /* ACE_HAS_THREADS */
336 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
338 class ACE_Export ACE_Noop_Token : public ACE_Null_Mutex
340 public:
341 /// Queueing strategy
342 enum QUEUEING_STRATEGY
344 FIFO = -1,
345 LIFO = 0
348 /// Get queueing strategy.
349 int queueing_strategy ();
351 /// Set queueing strategy.
352 void queueing_strategy (int queueing_strategy);
354 int renew (int = 0, ACE_Time_Value * =0);
356 /// Dump the state of an object.
357 void dump () const;
359 /// Declare the dynamic allocation hooks.
360 ACE_ALLOC_HOOK_DECLARE;
363 ACE_END_VERSIONED_NAMESPACE_DECL
365 #if defined (__ACE_INLINE__)
366 #include "ace/Token.inl"
367 #endif /* __ACE_INLINE__ */
370 #include /**/ "ace/post.h"
371 #endif /* ACE_TOKEN_H */