6 #if CRYPTOPP_MSC_VERSION 7 # pragma warning(disable: 4189) 14 #ifdef SOCKETS_AVAILABLE 16 #ifdef USE_BERKELEY_STYLE_SOCKETS 18 #include <sys/types.h> 27 #ifdef USE_WINDOWS_STYLE_SOCKETS 28 return MAXIMUM_WAIT_OBJECTS * (MAXIMUM_WAIT_OBJECTS-1);
35 : m_tracer(tracer), m_eventTimer(
Timer::MILLISECONDS), m_lastResult(0)
36 , m_sameResultCount(0), m_noWaitTimer(
Timer::MILLISECONDS)
39 m_eventTimer.StartTimer();
42 void WaitObjectContainer::Clear()
44 #ifdef USE_WINDOWS_STYLE_SOCKETS 55 inline void WaitObjectContainer::SetLastResult(LastResultType result)
57 if (result == m_lastResult)
61 m_lastResult = result;
62 m_sameResultCount = 0;
66 void WaitObjectContainer::DetectNoWait(LastResultType result,
CallStack const& callStack)
68 if (result == m_lastResult && m_noWaitTimer.ElapsedTime() > 1000)
70 if (m_sameResultCount > m_noWaitTimer.ElapsedTime())
74 std::string desc =
"No wait loop detected - m_lastResult: ";
75 desc.append(
IntToString(m_lastResult)).append(
", call stack:");
76 for (
CallStack const* cs = &callStack; cs; cs = cs->Prev())
77 desc.append(
"\n- ").append(cs->Format());
78 m_tracer->TraceNoWaitLoop(desc);
80 try {
throw 0; }
catch (...) {}
83 m_noWaitTimer.StartTimer();
84 m_sameResultCount = 0;
88 void WaitObjectContainer::SetNoWait(
CallStack const& callStack)
90 DetectNoWait(LastResultType(LASTRESULT_NOWAIT),
CallStack(
"WaitObjectContainer::SetNoWait()", &callStack));
94 void WaitObjectContainer::ScheduleEvent(
double milliseconds,
CallStack const& callStack)
96 if (milliseconds <= 3)
97 DetectNoWait(LastResultType(LASTRESULT_SCHEDULED),
CallStack(
"WaitObjectContainer::ScheduleEvent()", &callStack));
98 double thisEventTime = m_eventTimer.ElapsedTimeAsDouble() + milliseconds;
99 if (!m_firstEventTime || thisEventTime < m_firstEventTime)
100 m_firstEventTime = thisEventTime;
103 #ifdef USE_WINDOWS_STYLE_SOCKETS 107 bool waitingToWait, terminate;
108 HANDLE startWaiting, stopWaiting;
109 const HANDLE *waitHandles;
116 WaitObjectContainer::~WaitObjectContainer()
120 if (!m_threads.empty())
122 HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS] = {0};
125 for (i=0; i<m_threads.size(); i++)
128 if(!m_threads[i])
continue;
131 while (!thread.waitingToWait)
133 thread.terminate =
true;
134 threadHandles[i] = thread.threadHandle;
137 BOOL bResult = PulseEvent(m_startWaiting);
138 assert(bResult != 0); CRYPTOPP_UNUSED(bResult);
141 DWORD dwResult = ::WaitForMultipleObjects((DWORD)m_threads.size(), threadHandles, TRUE, INFINITE);
142 assert((dwResult >= WAIT_OBJECT_0) && (dwResult < (DWORD)m_threads.size()));
144 for (i=0; i<m_threads.size(); i++)
147 if (!threadHandles[i])
continue;
149 bResult = CloseHandle(threadHandles[i]);
150 assert(bResult != 0);
153 bResult = CloseHandle(m_startWaiting);
154 assert(bResult != 0);
155 bResult = CloseHandle(m_stopWaiting);
156 assert(bResult != 0);
165 void WaitObjectContainer::AddHandle(HANDLE handle,
CallStack const& callStack)
167 DetectNoWait(m_handles.size(),
CallStack(
"WaitObjectContainer::AddHandle()", &callStack));
168 m_handles.push_back(handle);
171 DWORD WINAPI WaitingThread(LPVOID lParam)
175 std::vector<HANDLE> handles;
179 thread.waitingToWait =
true;
180 DWORD result = ::WaitForSingleObject(thread.startWaiting, INFINITE);
181 assert(result != WAIT_FAILED);
183 thread.waitingToWait =
false;
184 if (thread.terminate)
189 handles.resize(thread.count + 1);
190 handles[0] = thread.stopWaiting;
191 std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1);
193 result = ::WaitForMultipleObjects((DWORD)handles.size(), &handles[0], FALSE, INFINITE);
194 assert(result != WAIT_FAILED);
196 if (result == WAIT_OBJECT_0)
198 SetEvent(thread.stopWaiting);
199 if (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size()))
201 assert(!
"error in WaitingThread");
202 *thread.error = ::GetLastError();
209 void WaitObjectContainer::CreateThreads(
unsigned int count)
211 size_t currentCount = m_threads.size();
212 if (currentCount == 0)
214 m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
215 m_stopWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
218 if (currentCount < count)
220 m_threads.resize(count);
221 for (
size_t i=currentCount; i<count; i++)
224 if(!m_threads[i])
continue;
228 thread.terminate =
false;
229 thread.startWaiting = m_startWaiting;
230 thread.stopWaiting = m_stopWaiting;
231 thread.waitingToWait =
false;
232 thread.threadHandle = CreateThread(NULL, 0, &WaitingThread, &thread, 0, &thread.threadId);
237 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
239 if (m_noWait || (m_handles.empty() && !m_firstEventTime))
241 SetLastResult(LastResultType(LASTRESULT_NOWAIT));
245 bool timeoutIsScheduledEvent =
false;
247 if (m_firstEventTime)
249 double timeToFirstEvent =
SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
251 if (timeToFirstEvent <= milliseconds)
253 milliseconds = (
unsigned long)timeToFirstEvent;
254 timeoutIsScheduledEvent =
true;
257 if (m_handles.empty() || !milliseconds)
261 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
262 return timeoutIsScheduledEvent;
266 if (m_handles.size() > MAXIMUM_WAIT_OBJECTS)
269 static const unsigned int WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1;
270 unsigned int nThreads = (
unsigned int)((m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD);
271 if (nThreads > MAXIMUM_WAIT_OBJECTS)
272 throw Err(
"WaitObjectContainer: number of wait objects exceeds limit");
273 CreateThreads(nThreads);
276 for (
unsigned int i=0; i<m_threads.size(); i++)
279 if(!m_threads[i])
continue;
282 while (!thread.waitingToWait)
286 thread.waitHandles = &m_handles[i*WAIT_OBJECTS_PER_THREAD];
287 thread.count =
UnsignedMin(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD);
288 thread.error = &error;
294 ResetEvent(m_stopWaiting);
295 PulseEvent(m_startWaiting);
297 DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds);
298 assert(result != WAIT_FAILED);
300 if (result == WAIT_OBJECT_0)
305 throw Err(
"WaitObjectContainer: WaitForMultipleObjects in thread failed with error " +
IntToString(error));
307 SetEvent(m_stopWaiting);
308 if (result == WAIT_TIMEOUT)
310 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
311 return timeoutIsScheduledEvent;
314 throw Err(
"WaitObjectContainer: WaitForSingleObject failed with error " +
IntToString(::GetLastError()));
319 static Timer t(Timer::MICROSECONDS);
320 static unsigned long lastTime = 0;
321 unsigned long timeBeforeWait = t.ElapsedTime();
323 DWORD result = ::WaitForMultipleObjects((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds);
325 if (milliseconds > 0)
327 unsigned long timeAfterWait = t.ElapsedTime();
328 OutputDebugString((
"Handles " +
IntToString(m_handles.size()) +
", Woke up by " +
IntToString(result-WAIT_OBJECT_0) +
", Busied for " +
IntToString(timeBeforeWait-lastTime) +
" us, Waited for " +
IntToString(timeAfterWait-timeBeforeWait) +
" us, max " +
IntToString(milliseconds) +
"ms\n").c_str());
329 lastTime = timeAfterWait;
332 if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
334 if (result == m_lastResult)
338 m_lastResult = result;
339 m_sameResultCount = 0;
343 else if (result == WAIT_TIMEOUT)
345 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
346 return timeoutIsScheduledEvent;
349 throw Err(
"WaitObjectContainer: WaitForMultipleObjects failed with error " +
IntToString(::GetLastError()));
353 #else // #ifdef USE_WINDOWS_STYLE_SOCKETS 355 void WaitObjectContainer::AddReadFd(
int fd,
CallStack const& callStack)
357 CRYPTOPP_UNUSED(callStack);
358 FD_SET(fd, &m_readfds);
359 m_maxFd =
STDMAX(m_maxFd, fd);
362 void WaitObjectContainer::AddWriteFd(
int fd,
CallStack const& callStack)
364 CRYPTOPP_UNUSED(callStack);
365 FD_SET(fd, &m_writefds);
366 m_maxFd =
STDMAX(m_maxFd, fd);
369 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
371 if (m_noWait || (!m_maxFd && !m_firstEventTime))
374 bool timeoutIsScheduledEvent =
false;
376 if (m_firstEventTime)
378 double timeToFirstEvent =
SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
379 if (timeToFirstEvent <= milliseconds)
381 milliseconds = (
unsigned long)timeToFirstEvent;
382 timeoutIsScheduledEvent =
true;
386 timeval tv, *timeout;
392 tv.tv_sec = milliseconds / 1000;
393 tv.tv_usec = (milliseconds % 1000) * 1000;
397 int result = select(m_maxFd+1, &m_readfds, &m_writefds, NULL, timeout);
401 else if (result == 0)
402 return timeoutIsScheduledEvent;
404 throw Err(
"WaitObjectContainer: select failed with error " +
IntToString(errno));
411 std::string CallStack::Format()
const 416 std::string CallStackWithNr::Format()
const 418 return std::string(m_info) +
" / nr: " +
IntToString(m_nr);
421 std::string CallStackWithStr::Format()
const 423 return std::string(m_info) +
" / " + std::string(m_z);
429 GetWaitObjects(container, callStack);
430 return container.Wait(milliseconds);
Base class for all exceptions thrown by Crypto++.
container of wait objects
Utility functions for the Crypto++ library.
Classes for automatic resource management.
Library configuration file.
Pointer that overloads operator→
T1 SaturatingSubtract(const T1 &a, const T2 &b)
Performs a saturating subtract clamped at 0.
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be neagtive and incorrectly promoted.
const unsigned long INFINITE_TIME
Represents infinite time.
bool Wait(unsigned long milliseconds, CallStack const &callStack)
wait on this object
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Crypto++ library namespace.