coherence/util/ThreadGate.hpp

00001 /*
00002 * ThreadGate.hpp
00003 *
00004 * Copyright (c) 2000, 2009, 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> m_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
Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.