00001 /* 00002 * ThreadGate.hpp 00003 * 00004 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 00005 * 00006 * Oracle is a registered trademarks of Oracle Corporation and/or its 00007 * affiliates. 00008 * 00009 * This software is the confidential and proprietary information of Oracle 00010 * Corporation. You shall not disclose such confidential and proprietary 00011 * information and shall use it only in accordance with the terms of the 00012 * license agreement you entered into with Oracle. 00013 * 00014 * This notice may not be removed or altered. 00015 */ 00016 #ifndef COH_THREAD_GATE_HPP 00017 #define COH_THREAD_GATE_HPP 00018 00019 #include "coherence/lang.ns" 00020 00021 COH_OPEN_NAMESPACE2(coherence,util) 00022 00023 00024 /** 00025 * Use this class in cases that large numbers of threads can operate 00026 * concurrently with an additional requirement that all threads be blocked for 00027 * certain operations. The algorithm is based on a gate concept, allowing 00028 * threads in (enter) and out (exit), but occasionally shutting the gate (close) 00029 * such that other threads cannot enter and exit. However, since threads may 00030 * "be inside", the gate cannot fully close until they leave (exit). Once all 00031 * threads are out, the gate is closed, and can be re-opened (open) or 00032 * permanently closed (destroy). 00033 * 00034 * Each call to enter requires a corresponding call to exit, similar to the 00035 * implementation of the COH_SYNCHRONIZED macro that calls Object::lock at the 00036 * the beginning of the synchronized portion and protects the synchronized 00037 * portion with a try..catch construct that ensures the execution of a 00038 * Object::unlock call. For example, the following would ensure proper clean-up 00039 * using a ThreadGate: 00040 * </p> 00041 * The enter/exit calls can be nested; the same thread can invoke enter multiple 00042 * times as long as exit is invoked a corresponding number of times. The 00043 * close/open calls work in the same manner. Lastly, the thread that closes the 00044 * gate may continue to enter/exit the gate even when it is closed since that 00045 * thread has exclusive control of the gate. 00046 * <p> 00047 * To make usage of these calls easier, the following macros have been defined: 00048 * <ul> 00049 * <li> COH_GATE_ENTER enters and automatically exits the gate 00050 * <li> COH_GATE_CLOSE closes and automatically opens the gate 00051 * <li> COH_GATE_BAR bars entry and automatically opens the gate 00052 * </ul> 00053 * <pre> 00054 * COH_GATE_ENTER (hGate) // read lock acquired 00055 * { 00056 * // read operations go here 00057 * // ... 00058 * // ... 00059 * } // read lock released 00060 * // outside of sync block 00061 * 00062 * COH_GATE_CLOSE (hGate) // write lock acquired 00063 * { 00064 * // write operations go here 00065 * // ... 00066 * // ... 00067 * } // write lock released 00068 * // outside of sync block 00069 * 00070 * COH_GATE_BAR (hGate) // additional readers are blocked 00071 * { 00072 * // non-synchronized ops 00073 * COH_GATE_CLOSE (hGate) // write lock acquired 00074 * { 00075 * // ... 00076 * // ... 00077 * } // inner-write lock released 00078 * // gate still locked 00079 * } // gate opened 00080 * // outside of sync block 00081 * </pre> 00082 * 00083 * @author nsa 2008.01.03 00084 */ 00085 class COH_EXPORT ThreadGate 00086 : public class_spec<ThreadGate> 00087 { 00088 friend class factory<ThreadGate>; 00089 00090 // ----- enum: State ---------------------------------------------------- 00091 00092 public: 00093 /** 00094 * State identifiers 00095 */ 00096 typedef enum 00097 { 00098 gate_open = 0, 00099 gate_closing = 1, 00100 gate_closed = 2, 00101 gate_destroyed = 4 00102 } Status; 00103 00104 00105 // ----- constructor ---------------------------------------------------- 00106 00107 protected: 00108 /** 00109 * Create a new ThreadGate. 00110 */ 00111 ThreadGate(); 00112 00113 00114 // ----- ThreadGate interface ------------------------------------------- 00115 00116 public: 00117 /** 00118 * Bar entry of the thread gate by other threads, but do not wait for 00119 * the gate to close. When all other threads have exited, the thread 00120 * gate will be closeable by the thread which barred entry. Each 00121 * successful invocation of this method must ultimately have a 00122 * corresponding invocation of the open() method (assuming the thread 00123 * gate is not destroyed), even if the calling thread does not 00124 * subsequently close the gate. 00125 * 00126 * @param cMillis maximum number of milliseconds to wait; pass 00127 * infinite for forever or immediate for no wait 00128 * 00129 * @return true iff entry into the gate was successfully barred by the 00130 * calling thread 00131 */ 00132 virtual bool barEntry(int64_t cMillis = infinite); 00133 00134 /** 00135 * Close the thread gate. A thread uses this method to obtain exclusive 00136 * access to the resource represented by the thread gate. Each 00137 * invocation of this method must ultimately have a corresponding 00138 * invocation of the open() method. 00139 * 00140 * @param cMillis maximum number of milliseconds to wait; pass 00141 * infinite for forever or immediate for no wait 00142 * 00143 * @return true iff the entry into the thread gate was successfully 00144 * barred by the calling thread and no other threads 00145 * remain in the gate. 00146 */ 00147 virtual bool close(int64_t cMillis = infinite); 00148 00149 /** 00150 * Destroy the thread gate. This method can only be invoked if the 00151 * gate is already closed by the calling thread. 00152 */ 00153 virtual void destroy(); 00154 00155 /** 00156 * Enter the thread gate. A thread uses this method to obtain 00157 * non-exclusive access to the resource represented by the thread gate. 00158 * Each successful invocation of this method must ultimately have a 00159 * corresponding invocation of the exit() method. 00160 * 00161 * @param cMillis maximum number of milliseconds to wait; pass 00162 * infinite for forever or immediate for no wait 00163 * 00164 * @return true iff the calling thread successfully entered the gate 00165 */ 00166 virtual bool enter(int64_t cMillis = infinite); 00167 00168 /** 00169 * Exit the gate. A thread must invoke this method corresponding to 00170 * each successful invocation of the enter method. 00171 */ 00172 virtual void exit(); 00173 00174 /** 00175 * After entry into the ThreadGate is restricted by a call to 00176 * barEntry() or close(), it can be re-opened by calling this method. 00177 * Only the thread that called barEntry() or close() can call open(). 00178 */ 00179 virtual void open(); 00180 00181 /** 00182 * Return the number of entered threads. 00183 * 00184 * @return the number of entered threads 00185 */ 00186 virtual int32_t getActiveCount() const; 00187 00188 /** 00189 * Determine if the current thread has entered and not exited. This is 00190 * useful for detecting re-entrancy. 00191 * 00192 * @return true if the current thread has entered and not exited. 00193 */ 00194 virtual bool isActiveThread() const; 00195 00196 /** 00197 * Return the number of unmatched completed close/barEntry calls. 00198 * 00199 * @return the number of unmatched completed close/barEntry calls. 00200 */ 00201 virtual int32_t getCloseCount() const; 00202 00203 /** 00204 * Return the current thread gate status. 00205 * 00206 * @return the current thread gate status 00207 */ 00208 virtual Status getStatus() const; 00209 00210 00211 // ----- Object interface ----------------------------------------------- 00212 00213 public: 00214 /** 00215 * {@inheritDoc} 00216 */ 00217 virtual void toStream(std::ostream& out) const; 00218 00219 00220 // ----- inner class: Counter ------------------------------------------- 00221 00222 public: 00223 /** 00224 * Counter is a mutable integer class. 00225 */ 00226 class Counter 00227 : public class_spec<Counter> 00228 { 00229 friend class factory<Counter>; 00230 00231 // ----- constructor ---------------------------------------- 00232 00233 protected: 00234 /** 00235 * Create a Counter initialized with a specified value. 00236 * 00237 * @param c the initial value of the Counter 00238 */ 00239 Counter(int32_t c = 0); 00240 00241 // ----- Counter interface ---------------------------------- 00242 00243 public: 00244 /** 00245 * Return the count. 00246 * 00247 * @return the count 00248 */ 00249 virtual int32_t getCount() const; 00250 00251 /** 00252 * Set the count. 00253 * 00254 * @param c the value to set the count to. 00255 */ 00256 virtual void setCount(int32_t c); 00257 00258 /** 00259 * Increment the count by 1. 00260 * 00261 * @return the incremented count. 00262 */ 00263 virtual int32_t increment(); 00264 00265 /** 00266 * Decrement the count. 00267 * 00268 * @return the decremented count. 00269 */ 00270 virtual int32_t decrement(); 00271 00272 // ----- Object interface ----------------------------------- 00273 00274 public: 00275 /** 00276 * {@inheritDoc} 00277 */ 00278 virtual void toStream(std::ostream& out) const; 00279 00280 // ----- data members --------------------------------------- 00281 00282 private: 00283 /** 00284 * The count. 00285 */ 00286 int32_t m_c; 00287 }; 00288 00289 00290 // ----- inner class: GateBlock ----------------------------------------- 00291 00292 public: 00293 /** 00294 * The EnterBlock class allows for easy creation of ThreadGate::enter 00295 * code. The EnterBlock object will ensure that the gate is entered 00296 * and exited as a part of starting and ending the code block. It's 00297 * used by the COH_GATE_ENTER macro 00298 */ 00299 class GateBlock 00300 { 00301 // ----- enums ---------------------------------------------- 00302 public: 00303 /** 00304 * The type of GateBlock that will be constructed 00305 */ 00306 typedef enum 00307 { 00308 bar, 00309 close, 00310 enter 00311 } BlockType; 00312 00313 // ----- constructor ---------------------------------------- 00314 00315 public: 00316 /** 00317 * Construct a new EnterBlock object entering the supplied 00318 * gate. 00319 * 00320 * @param nType the type of GateBlock to construct 00321 * @param hGate the gate to enter 00322 * @param lTime maximum number of milliseconds to wait; pass 00323 * infinite for forever or immediate for no wait 00324 */ 00325 GateBlock(BlockType nType, ThreadGate::Handle hGate, 00326 int64_t lTime); 00327 00328 /** 00329 * Copy constructor used by the COH_GATE_ENTERED macro. 00330 * 00331 * The new block takes over ownership of the gate. 00332 */ 00333 GateBlock(const GateBlock& that); 00334 00335 /** 00336 * Destroy an EnterBlock object, exiting the associated gate 00337 */ 00338 ~GateBlock(); 00339 00340 // ----- GateBlock interface -------------------------------- 00341 00342 public: 00343 /** 00344 * Boolean conversion for the COH_GATE_ENTER macro 00345 * 00346 * @return true always 00347 * 00348 * @throw IllegalStateException if the gate is null 00349 */ 00350 operator bool() const; 00351 00352 private: 00353 /** 00354 * Blocked assignment operator. 00355 */ 00356 const GateBlock& operator=(const GateBlock&); 00357 00358 /** 00359 * Blocked dynamic allocation. 00360 */ 00361 static void* operator new(size_t); 00362 00363 // ----- data members --------------------------------------- 00364 00365 protected: 00366 /** 00367 * Gate used by the EnterBlock 00368 */ 00369 mutable ThreadGate::Handle m_hGate; // on stack 00370 00371 /** 00372 * The operation requested when the GateBlock is entered. 00373 */ 00374 BlockType m_nType; 00375 }; 00376 00377 // ----- helper methods ------------------------------------------------- 00378 00379 protected: 00380 /** 00381 * Specify the number of unmatched completed close/barEntry calls. The 00382 * caller must have the gate closed/closing. 00383 * 00384 * @param cClose the number of unmatched completed close/barEntry 00385 * calls. 00386 */ 00387 virtual void setCloseCount(int32_t cClose); 00388 00389 /** 00390 * Return the thread that is closing the gate. 00391 * 00392 * @return the thread that is closing the gate 00393 */ 00394 virtual Thread::View getClosingThread() const; 00395 00396 /** 00397 * Specify the thread id that is closing the gate. The caller must be 00398 * synchronized on the thread gate. 00399 * 00400 * @param vThread the thread id that is closing the gate. 00401 */ 00402 virtual void setClosingThread(Thread::View vThread); 00403 00404 /** 00405 * Update the current thread gate status, without changing the active 00406 * count. The caller must hold synchronization on the ThreadGate. 00407 * 00408 * @param nStatus the new status 00409 * 00410 * @return the old status 00411 */ 00412 virtual Status updateStatus(Status nStatus); 00413 00414 /** 00415 * Wait up to the specified number of milliseconds for notification. 00416 * Caller must be synchronized on this gate. 00417 * 00418 * @param cMillis the number of milliseconds to wait;; pass 00419 * infinite for forever or immediate for no wait 00420 * 00421 * @return the remaining wait time in milliseconds 00422 */ 00423 virtual int64_t doWait(int64_t cMillis); 00424 00425 private: 00426 /** 00427 * Perform cleanup related to returning from the close() method. 00428 * 00429 * @param fReenter true iff the calling thread needs to reenter the 00430 * gate 00431 * @param fReopen true iff the calling thread needs to reopen the 00432 * gate 00433 */ 00434 void closeFinally(bool fReenter, bool fReopen); 00435 00436 /** 00437 * Perform cleanup related to returning from the enter() method. 00438 * 00439 * @param hCounter the thread-local counter 00440 * @param fSuccess true iff the gate was successfully entered 00441 */ 00442 void enterFinally(Counter::Handle hCounter, bool fSuccess); 00443 00444 /** 00445 * Return the thread local counter object. 00446 * 00447 * @return the thread local counter object 00448 */ 00449 Counter::Handle getCounter() const; 00450 00451 00452 // ----- data members --------------------------------------------------- 00453 00454 public: 00455 /** 00456 * The maximum number of threads allowed in the gate at one time. 00457 */ 00458 static const int32_t max_enters = 0xEFFFFFFF; 00459 00460 /** 00461 * The constant representing wait forever. 00462 */ 00463 static const int64_t infinite = int64_t(-1); 00464 00465 /** 00466 * The constant representing not to wait. 00467 */ 00468 static const int64_t immediate = int64_t(0); 00469 00470 private: 00471 /** 00472 * The state of the ThreadGate. This counter is overloaded for two 00473 * responsibilities: It tracks the number of threads that have 00474 * entered the gate, and the status of the gate (OPEN, CLOSING 00475 * CLOSED or DESTROYED). 00476 */ 00477 NativeAtomic64 m_lAtomicState; 00478 00479 /** 00480 * Number of unmatched completed close/barEntry calls. 00481 */ 00482 int32_t m_cClose; 00483 00484 /** 00485 * The id of the thread that's currently closing the gate. 00486 */ 00487 MemberView<Thread> m_vClosingThread; 00488 00489 /** 00490 * Count of unmatched enter calls per thread. 00491 */ 00492 mutable FinalHandle<ThreadLocalReference> f_htlcEnters; 00493 }; 00494 00495 00496 // ----- non-member operators and functions --------------------------------- 00497 00498 /** 00499 * Macro for more readable ThreadGate blocks. See the ThreadGate docs for 00500 * more details. 00501 */ 00502 #define COH_GATE_ENTER(GATE, TIME) \ 00503 if (coherence::util::ThreadGate::GateBlock COH_UNIQUE_IDENTIFIER(gateblock) = \ 00504 coherence::util::ThreadGate::GateBlock( \ 00505 coherence::util::ThreadGate::GateBlock::enter, GATE, TIME)) 00506 00507 /** 00508 * Macro for more readable ThreadGate blocks. See the ThreadGate docs for 00509 * more details. 00510 */ 00511 #define COH_GATE_BAR(GATE, TIME) \ 00512 if (coherence::util::ThreadGate::GateBlock COH_UNIQUE_IDENTIFIER(gateblock) = \ 00513 coherence::util::ThreadGate::GateBlock( \ 00514 coherence::util::ThreadGate::GateBlock::bar, GATE, TIME)) 00515 /** 00516 * Macro for more readable ThreadGate blocks. See the ThreadGate docs for 00517 * more details. 00518 */ 00519 #define COH_GATE_CLOSE(GATE, TIME) \ 00520 if (coherence::util::ThreadGate::GateBlock COH_UNIQUE_IDENTIFIER(gateblock) = \ 00521 coherence::util::ThreadGate::GateBlock( \ 00522 coherence::util::ThreadGate::GateBlock::close, GATE, TIME)) 00523 00524 COH_CLOSE_NAMESPACE2 00525 00526 #endif // COH_THREAD_GATE_HPP