00001 /* 00002 * TimeoutBlock.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_TIMEOUT_BLOCK_HPP 00017 #define COH_TIMEOUT_BLOCK_HPP 00018 00019 #include "coherence/lang/compatibility.hpp" 00020 00021 #include "coherence/lang/Thread.hpp" 00022 00023 COH_OPEN_NAMESPACE2(coherence, lang) 00024 00025 /** 00026 * TimeoutBlock provides a mechanism for allowing a thread to interrupt itself if it doesn't return 00027 * to a specific call site within a given timeout. TimeoutBlock instances are intended to be 00028 * used only with the COH_TIMEOUT_AFTER helper macro. Once constructed a TimeoutBlock attempts to ensure that 00029 * the corresponding block completes within the specified timeout and if it does not the thread will 00030 * self-interrupt. Exiting the timeout block will automatically clear any interrupt present on the thread 00031 * and in such a case an InterruptedException will be thrown. 00032 * 00033 * <pre> 00034 * try 00035 * { 00036 * COH_TIMEOUT_AFTER(5000) 00037 * { 00038 * doSomething(); 00039 * } 00040 * } // this thread will self-interrupt if it doesn't reach this line within 5 seconds 00041 * catch (InterruptedException::View vEx) 00042 * { 00043 * // thread timed out or was otherwise interrupted 00044 * } 00045 * </pre> 00046 * 00047 * Note that when catching the InterruptedException the preferred form is to surround the COH_TIMEOUT block with a try/catch 00048 * rather then embed the try/catch within the block. This allows handling of cases where the thread gets interrupted but 00049 * the doSomething() method does not choose to throw the InterruptedException, in which case the TimeoutBlock destructor will 00050 * throw it, but this happens as the block terminates and thus would not be catchable within the block. 00051 * 00052 * Note that TimeoutBlock can only self-interrupt at interruptible points, and does not defend against 00053 * CPU bound loops for example. 00054 * 00055 * @author mf 2015.03.03 00056 */ 00057 class COH_EXPORT TimeoutBlock 00058 { 00059 // ----- constructors --------------------------------------------------- 00060 00061 public: 00062 /** 00063 * Specify a new timeout. 00064 * 00065 * This constructor variant allows the caller to override a parent timeout. This is 00066 * rarely needed, and is roughly the equivalent of silently consuming a thread interrupt 00067 * without rethrowing the InterruptedException. 00068 * 00069 * @param cMillis the new timeout. 00070 * @param fForceOverride true if this timeout is allowed to extend a parent timeout. 00071 */ 00072 TimeoutBlock(int64_t cMillis, bool fForceOverride = false); 00073 00074 /** 00075 * Copy constructor for COH_TIMEOUT macros. 00076 */ 00077 TimeoutBlock(const TimeoutBlock& that); 00078 00079 /** 00080 * Destroy a TimeoutBlock object. 00081 * 00082 * This will automatically reset the timeout to any former value. 00083 */ 00084 ~TimeoutBlock(); 00085 00086 00087 // ----- operators ------------------------------------------------------ 00088 00089 public: 00090 /* 00091 * Boolean conversion for use in COH_TIMEOUT macros. 00092 * 00093 * @return false always 00094 */ 00095 operator bool() const 00096 { 00097 return false; 00098 } 00099 00100 private: 00101 /** 00102 * Blocked assignment operator. 00103 */ 00104 const TimeoutBlock& operator=(const TimeoutBlock&); 00105 00106 /** 00107 * Blocked dynamic allocation. 00108 */ 00109 static void* operator new(size_t); 00110 00111 00112 // ----- data members --------------------------------------------------- 00113 00114 protected: 00115 /** 00116 * This TimeoutBlock's timeout. 00117 */ 00118 int64_t m_cMillisTimeout; 00119 00120 /** 00121 * The original timeout before this instance changed it. 00122 */ 00123 int64_t m_lTimeoutOrig; 00124 00125 /** 00126 * The current thread, or NULL if this block is inactive. 00127 */ 00128 mutable Thread::Handle m_hThread; 00129 }; 00130 00131 COH_CLOSE_NAMESPACE2 00132 00133 /** 00134 * Macro for making more readable timeout code blocks See the 00135 * documentation of TimeoutBlock for a usage example. 00136 * 00137 * @see coherence::lang::TimeoutBlock 00138 */ 00139 #define COH_TIMEOUT_AFTER(CMILLIS) \ 00140 if (coherence::lang::TimeoutBlock COH_UNIQUE_IDENTIFIER(_coh_timeout_) \ 00141 = coherence::lang::TimeoutBlock(CMILLIS)) \ 00142 { \ 00143 COH_THROW(coherence::lang::IllegalStateException::create()); \ 00144 } \ 00145 else 00146 00147 /** 00148 * Macro for making more readable timeout code blocks which is allowed to 00149 * extend an already active timeout. 00150 * 00151 * This variant allows the caller to extend a parent timeout. This is rarely 00152 * needed, and is roughly the equivalent of silently consuming a thread interrupt 00153 * without rethrowing the InterruptedException. Use of this method should 00154 * be extremely limited. 00155 * 00156 * @see coherence::lang::TimeoutBlock 00157 */ 00158 #define COH_TIMEOUT_OVERRIDE(CMILLIS) \ 00159 if (coherence::lang::TimeoutBlock COH_UNIQUE_IDENTIFIER(_coh_timeout_) \ 00160 = coherence::lang::TimeoutBlock(CMILLIS, /*fForceOverride*/ true)) \ 00161 { \ 00162 COH_THROW(coherence::lang::IllegalStateException::create()); \ 00163 } \ 00164 else 00165 00166 #endif // COH_TIMEOUT_BLOCK_HPP