<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> <title>Crypto++: wait.cpp Source File</title> <link href="doxygen.css" rel="stylesheet" type="text/css"> </head><body> <!-- Generated by Doxygen 1.3.7 --> <div class="qindex"><a class="qindex" href="index.html">Main Page</a> | <a class="qindex" href="namespaces.html">Namespace List</a> | <a class="qindex" href="hierarchy.html">Class Hierarchy</a> | <a class="qindex" href="classes.html">Alphabetical List</a> | <a class="qindex" href="annotated.html">Class List</a> | <a class="qindex" href="files.html">File List</a> | <a class="qindex" href="namespacemembers.html">Namespace Members</a> | <a class="qindex" href="functions.html">Class Members</a> | <a class="qindex" href="globals.html">File Members</a></div> <h1>wait.cpp</h1><pre class="fragment"><div>00001 <span class="comment">// wait.cpp - written and placed in the public domain by Wei Dai</span> 00002 00003 <span class="preprocessor">#include "pch.h"</span> 00004 <span class="preprocessor">#include "wait.h"</span> 00005 <span class="preprocessor">#include "misc.h"</span> 00006 00007 <span class="preprocessor">#ifdef SOCKETS_AVAILABLE</span> 00008 <span class="preprocessor"></span> 00009 <span class="preprocessor">#ifdef USE_BERKELEY_STYLE_SOCKETS</span> 00010 <span class="preprocessor"></span><span class="preprocessor">#include <errno.h></span> 00011 <span class="preprocessor">#include <sys/types.h></span> 00012 <span class="preprocessor">#include <sys/time.h></span> 00013 <span class="preprocessor">#include <unistd.h></span> 00014 <span class="preprocessor">#endif</span> 00015 <span class="preprocessor"></span> 00016 <span class="preprocessor">#define TRACE_WAIT 0</span> 00017 <span class="preprocessor"></span> 00018 <span class="preprocessor">#if TRACE_WAIT</span> 00019 <span class="preprocessor"></span><span class="preprocessor">#include "hrtimer.h"</span> 00020 <span class="preprocessor">#endif</span> 00021 <span class="preprocessor"></span> 00022 NAMESPACE_BEGIN(CryptoPP) 00023 00024 unsigned <span class="keywordtype">int</span> <a class="code" href="class_wait_object_container.html">WaitObjectContainer</a>::MaxWaitObjects() 00025 { 00026 <span class="preprocessor">#ifdef USE_WINDOWS_STYLE_SOCKETS</span> 00027 <span class="preprocessor"></span> <span class="keywordflow">return</span> MAXIMUM_WAIT_OBJECTS * (MAXIMUM_WAIT_OBJECTS-1); 00028 <span class="preprocessor">#else</span> 00029 <span class="preprocessor"></span> <span class="keywordflow">return</span> FD_SETSIZE; 00030 <span class="preprocessor">#endif</span> 00031 <span class="preprocessor"></span>} 00032 00033 WaitObjectContainer::WaitObjectContainer() 00034 #<span class="keywordflow">if</span> CRYPTOPP_DETECT_NO_WAIT 00035 : m_sameResultCount(0), m_timer(Timer::MILLISECONDS) 00036 #endif 00037 { 00038 Clear(); 00039 } 00040 00041 <span class="keywordtype">void</span> WaitObjectContainer::Clear() 00042 { 00043 <span class="preprocessor">#ifdef USE_WINDOWS_STYLE_SOCKETS</span> 00044 <span class="preprocessor"></span> m_handles.clear(); 00045 <span class="preprocessor">#else</span> 00046 <span class="preprocessor"></span> m_maxFd = 0; 00047 FD_ZERO(&m_readfds); 00048 FD_ZERO(&m_writefds); 00049 <span class="preprocessor">#endif</span> 00050 <span class="preprocessor"></span> m_noWait = <span class="keyword">false</span>; 00051 } 00052 00053 <span class="keywordtype">void</span> WaitObjectContainer::SetNoWait() 00054 { 00055 <span class="preprocessor">#if CRYPTOPP_DETECT_NO_WAIT</span> 00056 <span class="preprocessor"></span> <span class="keywordflow">if</span> (-1 == m_lastResult && m_timer.<a class="code" href="class_timer_base.html#_timer_basea5">ElapsedTime</a>() > 1000) 00057 { 00058 <span class="keywordflow">if</span> (m_sameResultCount > m_timer.<a class="code" href="class_timer_base.html#_timer_basea5">ElapsedTime</a>()) 00059 <span class="keywordflow">try</span> {<span class="keywordflow">throw</span> 0;} <span class="keywordflow">catch</span> (...) {} <span class="comment">// possible no-wait loop, break in debugger</span> 00060 m_timer.<a class="code" href="class_timer_base.html#_timer_basea3">StartTimer</a>(); 00061 } 00062 <span class="preprocessor">#endif</span> 00063 <span class="preprocessor"></span> m_noWait = <span class="keyword">true</span>; 00064 } 00065 00066 <span class="preprocessor">#ifdef USE_WINDOWS_STYLE_SOCKETS</span> 00067 <span class="preprocessor"></span> 00068 <span class="keyword">struct </span>WaitingThreadData 00069 { 00070 <span class="keywordtype">bool</span> waitingToWait, terminate; 00071 HANDLE startWaiting, stopWaiting; 00072 <span class="keyword">const</span> HANDLE *waitHandles; 00073 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> count; 00074 HANDLE threadHandle; 00075 DWORD threadId; 00076 DWORD* error; 00077 }; 00078 00079 WaitObjectContainer::~WaitObjectContainer() 00080 { 00081 <span class="keywordflow">try</span> <span class="comment">// don't let exceptions escape destructor</span> 00082 { 00083 <span class="keywordflow">if</span> (!m_threads.empty()) 00084 { 00085 HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS]; 00086 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i; 00087 <span class="keywordflow">for</span> (i=0; i<m_threads.size(); i++) 00088 { 00089 WaitingThreadData &thread = *m_threads[i]; 00090 <span class="keywordflow">while</span> (!thread.waitingToWait) <span class="comment">// spin until thread is in the initial "waiting to wait" state</span> 00091 Sleep(0); 00092 thread.terminate = <span class="keyword">true</span>; 00093 threadHandles[i] = thread.threadHandle; 00094 } 00095 PulseEvent(m_startWaiting); 00096 ::WaitForMultipleObjects(m_threads.size(), threadHandles, TRUE, INFINITE); 00097 <span class="keywordflow">for</span> (i=0; i<m_threads.size(); i++) 00098 CloseHandle(threadHandles[i]); 00099 CloseHandle(m_startWaiting); 00100 CloseHandle(m_stopWaiting); 00101 } 00102 } 00103 <span class="keywordflow">catch</span> (...) 00104 { 00105 } 00106 } 00107 00108 00109 <span class="keywordtype">void</span> WaitObjectContainer::AddHandle(HANDLE handle) 00110 { 00111 <span class="preprocessor">#if CRYPTOPP_DETECT_NO_WAIT</span> 00112 <span class="preprocessor"></span> <span class="keywordflow">if</span> (m_handles.size() == m_lastResult && m_timer.<a class="code" href="class_timer_base.html#_timer_basea5">ElapsedTime</a>() > 1000) 00113 { 00114 <span class="keywordflow">if</span> (m_sameResultCount > m_timer.<a class="code" href="class_timer_base.html#_timer_basea5">ElapsedTime</a>()) 00115 <span class="keywordflow">try</span> {<span class="keywordflow">throw</span> 0;} <span class="keywordflow">catch</span> (...) {} <span class="comment">// possible no-wait loop, break in debugger</span> 00116 m_timer.<a class="code" href="class_timer_base.html#_timer_basea3">StartTimer</a>(); 00117 } 00118 <span class="preprocessor">#endif</span> 00119 <span class="preprocessor"></span> m_handles.push_back(handle); 00120 } 00121 00122 DWORD WINAPI WaitingThread(LPVOID lParam) 00123 { 00124 std::auto_ptr<WaitingThreadData> pThread((WaitingThreadData *)lParam); 00125 WaitingThreadData &thread = *pThread; 00126 std::vector<HANDLE> handles; 00127 00128 <span class="keywordflow">while</span> (<span class="keyword">true</span>) 00129 { 00130 thread.waitingToWait = <span class="keyword">true</span>; 00131 ::WaitForSingleObject(thread.startWaiting, INFINITE); 00132 thread.waitingToWait = <span class="keyword">false</span>; 00133 00134 <span class="keywordflow">if</span> (thread.terminate) 00135 <span class="keywordflow">break</span>; 00136 <span class="keywordflow">if</span> (!thread.count) 00137 <span class="keywordflow">continue</span>; 00138 00139 handles.resize(thread.count + 1); 00140 handles[0] = thread.stopWaiting; 00141 std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1); 00142 00143 DWORD result = ::WaitForMultipleObjects(handles.size(), &handles[0], FALSE, INFINITE); 00144 00145 <span class="keywordflow">if</span> (result == WAIT_OBJECT_0) 00146 <span class="keywordflow">continue</span>; <span class="comment">// another thread finished waiting first, so do nothing</span> 00147 SetEvent(thread.stopWaiting); 00148 <span class="keywordflow">if</span> (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size())) 00149 { 00150 assert(!<span class="stringliteral">"error in WaitingThread"</span>); <span class="comment">// break here so we can see which thread has an error</span> 00151 *thread.error = ::GetLastError(); 00152 } 00153 } 00154 00155 <span class="keywordflow">return</span> S_OK; <span class="comment">// return a value here to avoid compiler warning</span> 00156 } 00157 00158 <span class="keywordtype">void</span> WaitObjectContainer::CreateThreads(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> count) 00159 { 00160 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> currentCount = m_threads.size(); 00161 <span class="keywordflow">if</span> (currentCount == 0) 00162 { 00163 m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL); 00164 m_stopWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL); 00165 } 00166 00167 <span class="keywordflow">if</span> (currentCount < count) 00168 { 00169 m_threads.resize(count); 00170 <span class="keywordflow">for</span> (<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=currentCount; i<count; i++) 00171 { 00172 m_threads[i] = <span class="keyword">new</span> WaitingThreadData; 00173 WaitingThreadData &thread = *m_threads[i]; 00174 thread.terminate = <span class="keyword">false</span>; 00175 thread.startWaiting = m_startWaiting; 00176 thread.stopWaiting = m_stopWaiting; 00177 thread.waitingToWait = <span class="keyword">false</span>; 00178 thread.threadHandle = CreateThread(NULL, 0, &WaitingThread, &thread, 0, &thread.threadId); 00179 } 00180 } 00181 } 00182 00183 <span class="keywordtype">bool</span> WaitObjectContainer::Wait(<span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> milliseconds) 00184 { 00185 <span class="keywordflow">if</span> (m_noWait || m_handles.empty()) 00186 { 00187 <span class="preprocessor">#if CRYPTOPP_DETECT_NO_WAIT</span> 00188 <span class="preprocessor"></span> <span class="keywordflow">if</span> (-1 == m_lastResult) 00189 m_sameResultCount++; 00190 <span class="keywordflow">else</span> 00191 { 00192 m_lastResult = -1; 00193 m_sameResultCount = 0; 00194 } 00195 <span class="preprocessor">#endif</span> 00196 <span class="preprocessor"></span> <span class="keywordflow">return</span> <span class="keyword">true</span>; 00197 } 00198 00199 <span class="keywordflow">if</span> (m_handles.size() > MAXIMUM_WAIT_OBJECTS) 00200 { 00201 <span class="comment">// too many wait objects for a single WaitForMultipleObjects call, so use multiple threads</span> 00202 <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1; 00203 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> nThreads = (m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD; 00204 <span class="keywordflow">if</span> (nThreads > MAXIMUM_WAIT_OBJECTS) <span class="comment">// still too many wait objects, maybe implement recursive threading later?</span> 00205 <span class="keywordflow">throw</span> Err(<span class="stringliteral">"WaitObjectContainer: number of wait objects exceeds limit"</span>); 00206 CreateThreads(nThreads); 00207 DWORD error = S_OK; 00208 00209 <span class="keywordflow">for</span> (<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=0; i<m_threads.size(); i++) 00210 { 00211 WaitingThreadData &thread = *m_threads[i]; 00212 <span class="keywordflow">while</span> (!thread.waitingToWait) <span class="comment">// spin until thread is in the initial "waiting to wait" state</span> 00213 Sleep(0); 00214 <span class="keywordflow">if</span> (i<nThreads) 00215 { 00216 thread.waitHandles = &m_handles[i*WAIT_OBJECTS_PER_THREAD]; 00217 thread.count = STDMIN(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD); 00218 thread.error = &error; 00219 } 00220 <span class="keywordflow">else</span> 00221 thread.count = 0; 00222 } 00223 00224 ResetEvent(m_stopWaiting); 00225 PulseEvent(m_startWaiting); 00226 00227 DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds); 00228 <span class="keywordflow">if</span> (result == WAIT_OBJECT_0) 00229 { 00230 <span class="keywordflow">if</span> (error == S_OK) 00231 <span class="keywordflow">return</span> <span class="keyword">true</span>; 00232 <span class="keywordflow">else</span> 00233 <span class="keywordflow">throw</span> Err(<span class="stringliteral">"WaitObjectContainer: WaitForMultipleObjects failed with error "</span> + IntToString(error)); 00234 } 00235 SetEvent(m_stopWaiting); 00236 <span class="keywordflow">if</span> (result == WAIT_TIMEOUT) 00237 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00238 <span class="keywordflow">else</span> 00239 <span class="keywordflow">throw</span> Err(<span class="stringliteral">"WaitObjectContainer: WaitForSingleObject failed with error "</span> + IntToString(::GetLastError())); 00240 } 00241 <span class="keywordflow">else</span> 00242 { 00243 <span class="preprocessor">#if TRACE_WAIT</span> 00244 <span class="preprocessor"></span> <span class="keyword">static</span> <a class="code" href="class_timer.html">Timer</a> t(Timer::MICROSECONDS); 00245 <span class="keyword">static</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> lastTime = 0; 00246 <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> timeBeforeWait = t.ElapsedTime(); 00247 <span class="preprocessor">#endif</span> 00248 <span class="preprocessor"></span> DWORD result = ::WaitForMultipleObjects(m_handles.size(), &m_handles[0], FALSE, milliseconds); 00249 <span class="preprocessor">#if TRACE_WAIT</span> 00250 <span class="preprocessor"></span> <span class="keywordflow">if</span> (milliseconds > 0) 00251 { 00252 <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> timeAfterWait = t.ElapsedTime(); 00253 OutputDebugString((<span class="stringliteral">"Handles "</span> + IntToString(m_handles.size()) + <span class="stringliteral">", Woke up by "</span> + IntToString(result-WAIT_OBJECT_0) + <span class="stringliteral">", Busied for "</span> + IntToString(timeBeforeWait-lastTime) + <span class="stringliteral">" us, Waited for "</span> + IntToString(timeAfterWait-timeBeforeWait) + <span class="stringliteral">" us, max "</span> + IntToString(milliseconds) + <span class="stringliteral">"ms\n"</span>).c_str()); 00254 lastTime = timeAfterWait; 00255 } 00256 <span class="preprocessor">#endif</span> 00257 <span class="preprocessor"></span> <span class="keywordflow">if</span> (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size()) 00258 { 00259 <span class="preprocessor">#if CRYPTOPP_DETECT_NO_WAIT</span> 00260 <span class="preprocessor"></span> <span class="keywordflow">if</span> (result == m_lastResult) 00261 m_sameResultCount++; 00262 <span class="keywordflow">else</span> 00263 { 00264 m_lastResult = result; 00265 m_sameResultCount = 0; 00266 } 00267 <span class="preprocessor">#endif</span> 00268 <span class="preprocessor"></span> <span class="keywordflow">return</span> <span class="keyword">true</span>; 00269 } 00270 <span class="keywordflow">else</span> <span class="keywordflow">if</span> (result == WAIT_TIMEOUT) 00271 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00272 <span class="keywordflow">else</span> 00273 <span class="keywordflow">throw</span> Err(<span class="stringliteral">"WaitObjectContainer: WaitForMultipleObjects failed with error "</span> + IntToString(::GetLastError())); 00274 } 00275 } 00276 00277 <span class="preprocessor">#else</span> 00278 <span class="preprocessor"></span> 00279 <span class="keywordtype">void</span> WaitObjectContainer::AddReadFd(<span class="keywordtype">int</span> fd) 00280 { 00281 FD_SET(fd, &m_readfds); 00282 m_maxFd = STDMAX(m_maxFd, fd); 00283 } 00284 00285 <span class="keywordtype">void</span> WaitObjectContainer::AddWriteFd(<span class="keywordtype">int</span> fd) 00286 { 00287 FD_SET(fd, &m_writefds); 00288 m_maxFd = STDMAX(m_maxFd, fd); 00289 } 00290 00291 <span class="keywordtype">bool</span> WaitObjectContainer::Wait(<span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> milliseconds) 00292 { 00293 <span class="keywordflow">if</span> (m_noWait || m_maxFd == 0) 00294 <span class="keywordflow">return</span> <span class="keyword">true</span>; 00295 00296 timeval tv, *timeout; 00297 00298 <span class="keywordflow">if</span> (milliseconds == <a class="code" href="cryptlib_8h.html#a0">INFINITE_TIME</a>) 00299 timeout = NULL; 00300 <span class="keywordflow">else</span> 00301 { 00302 tv.tv_sec = milliseconds / 1000; 00303 tv.tv_usec = (milliseconds % 1000) * 1000; 00304 timeout = &tv; 00305 } 00306 00307 <span class="keywordtype">int</span> result = select(m_maxFd+1, &m_readfds, &m_writefds, NULL, timeout); 00308 00309 <span class="keywordflow">if</span> (result > 0) 00310 <span class="keywordflow">return</span> <span class="keyword">true</span>; 00311 <span class="keywordflow">else</span> <span class="keywordflow">if</span> (result == 0) 00312 <span class="keywordflow">return</span> <span class="keyword">false</span>; 00313 <span class="keywordflow">else</span> 00314 <span class="keywordflow">throw</span> Err(<span class="stringliteral">"WaitObjectContainer: select failed with error "</span> + errno); 00315 } 00316 00317 <span class="preprocessor">#endif</span> 00318 <span class="preprocessor"></span> 00319 <span class="comment">// ********************************************************</span> 00320 <a name="l00321"></a><a class="code" href="class_waitable.html#_zlib_decompressora19">00321</a> <span class="keywordtype">bool</span> <a class="code" href="class_waitable.html#_zlib_decompressora19">Waitable::Wait</a>(<span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> milliseconds) 00322 { 00323 <a class="code" href="class_wait_object_container.html">WaitObjectContainer</a> container; 00324 <a class="code" href="class_waitable.html#_waitablea1">GetWaitObjects</a>(container); 00325 <span class="keywordflow">return</span> container.<a class="code" href="class_wait_object_container.html#_wait_object_containera3">Wait</a>(milliseconds); 00326 } 00327 00328 NAMESPACE_END 00329 00330 <span class="preprocessor">#endif</span> </div></pre><hr size="1"><address style="align: right;"><small>Generated on Sun Nov 7 08:23:59 2004 for Crypto++ by <a href="http://www.doxygen.org/index.html"> <img src="doxygen.png" alt="doxygen" align="middle" border=0 ></a> 1.3.7 </small></address> </body> </html>