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