6 #if CRYPTOPP_MSC_VERSION 7 # pragma warning(disable: 4189) 10 #if !defined(NO_OS_DEPENDENCE) && (defined(SOCKETS_AVAILABLE) || defined(WINDOWS_PIPES_AVAILABLE)) 17 #if defined(CRYPTOPP_WIN32_AVAILABLE) 18 # if ((WINVER >= 0x0602 ) || (_WIN32_WINNT >= 0x0602 )) 19 # include <synchapi.h> 20 # include <ioapiset.h> 21 # define USE_WINDOWS8_API 25 #ifdef USE_BERKELEY_STYLE_SOCKETS 27 #include <sys/types.h> 32 #if defined(CRYPTOPP_MSAN) 33 # include <sanitizer/msan_interface.h> 38 unsigned int WaitObjectContainer::MaxWaitObjects()
40 #ifdef USE_WINDOWS_STYLE_SOCKETS 41 return MAXIMUM_WAIT_OBJECTS * (MAXIMUM_WAIT_OBJECTS-1);
48 : m_tracer(tracer), m_eventTimer(
Timer::MILLISECONDS), m_lastResult(0)
49 , m_sameResultCount(0), m_noWaitTimer(
Timer::MILLISECONDS)
52 m_eventTimer.StartTimer();
55 void WaitObjectContainer::Clear()
57 #ifdef USE_WINDOWS_STYLE_SOCKETS 64 __msan_unpoison(&m_readfds,
sizeof(m_readfds));
65 __msan_unpoison(&m_writefds,
sizeof(m_writefds));
72 inline void WaitObjectContainer::SetLastResult(LastResultType result)
74 if (result == m_lastResult)
78 m_lastResult = result;
79 m_sameResultCount = 0;
83 void WaitObjectContainer::DetectNoWait(LastResultType result,
CallStack const& callStack)
85 if (result == m_lastResult && m_noWaitTimer.ElapsedTime() > 1000)
87 if (m_sameResultCount > m_noWaitTimer.ElapsedTime())
91 std::string desc =
"No wait loop detected - m_lastResult: ";
92 desc.append(
IntToString(m_lastResult)).append(
", call stack:");
93 for (
CallStack const* cs = &callStack; cs; cs = cs->Prev())
94 desc.append(
"\n- ").append(cs->Format());
95 m_tracer->TraceNoWaitLoop(desc);
97 try {
throw 0; }
catch (...) {}
100 m_noWaitTimer.StartTimer();
101 m_sameResultCount = 0;
105 void WaitObjectContainer::SetNoWait(
CallStack const& callStack)
107 DetectNoWait(LastResultType(LASTRESULT_NOWAIT),
CallStack(
"WaitObjectContainer::SetNoWait()", &callStack));
111 void WaitObjectContainer::ScheduleEvent(
double milliseconds,
CallStack const& callStack)
113 if (milliseconds <= 3)
114 DetectNoWait(LastResultType(LASTRESULT_SCHEDULED),
CallStack(
"WaitObjectContainer::ScheduleEvent()", &callStack));
115 double thisEventTime = m_eventTimer.ElapsedTimeAsDouble() + milliseconds;
116 if (!m_firstEventTime || thisEventTime < m_firstEventTime)
117 m_firstEventTime = thisEventTime;
120 #ifdef USE_WINDOWS_STYLE_SOCKETS 124 bool waitingToWait, terminate;
125 HANDLE startWaiting, stopWaiting;
126 const HANDLE *waitHandles;
133 WaitObjectContainer::~WaitObjectContainer()
137 if (!m_threads.empty())
139 HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS] = {0};
142 for (i=0; i<m_threads.size(); i++)
145 if(!m_threads[i])
continue;
148 while (!thread.waitingToWait)
150 thread.terminate =
true;
151 threadHandles[i] = thread.threadHandle;
154 BOOL bResult = PulseEvent(m_startWaiting);
155 assert(bResult != 0); CRYPTOPP_UNUSED(bResult);
158 #if defined(USE_WINDOWS8_API) 159 DWORD dwResult = ::WaitForMultipleObjectsEx((DWORD)m_threads.size(), threadHandles, TRUE, INFINITE, FALSE);
160 assert((dwResult >= WAIT_OBJECT_0) && (dwResult < (DWORD)m_threads.size()));
162 DWORD dwResult = ::WaitForMultipleObjects((DWORD)m_threads.size(), threadHandles, TRUE, INFINITE);
163 assert((dwResult >= WAIT_OBJECT_0) && (dwResult < (DWORD)m_threads.size()));
166 for (i=0; i<m_threads.size(); i++)
169 if (!threadHandles[i])
continue;
171 bResult = CloseHandle(threadHandles[i]);
172 assert(bResult != 0);
175 bResult = CloseHandle(m_startWaiting);
176 assert(bResult != 0);
177 bResult = CloseHandle(m_stopWaiting);
178 assert(bResult != 0);
187 void WaitObjectContainer::AddHandle(HANDLE handle,
CallStack const& callStack)
189 DetectNoWait(m_handles.size(),
CallStack(
"WaitObjectContainer::AddHandle()", &callStack));
190 m_handles.push_back(handle);
193 DWORD WINAPI WaitingThread(LPVOID lParam)
197 std::vector<HANDLE> handles;
201 thread.waitingToWait =
true;
202 #if defined(USE_WINDOWS8_API) 203 DWORD result = ::WaitForSingleObjectEx(thread.startWaiting, INFINITE, FALSE);
204 assert(result != WAIT_FAILED);
206 DWORD result = ::WaitForSingleObject(thread.startWaiting, INFINITE);
207 assert(result != WAIT_FAILED);
210 thread.waitingToWait =
false;
211 if (thread.terminate)
216 handles.resize(thread.count + 1);
217 handles[0] = thread.stopWaiting;
218 std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1);
220 #if defined(USE_WINDOWS8_API) 221 result = ::WaitForMultipleObjectsEx((DWORD)handles.size(), &handles[0], FALSE, INFINITE, FALSE);
222 assert(result != WAIT_FAILED);
224 result = ::WaitForMultipleObjects((DWORD)handles.size(), &handles[0], FALSE, INFINITE);
225 assert(result != WAIT_FAILED);
228 if (result == WAIT_OBJECT_0)
230 SetEvent(thread.stopWaiting);
231 if (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size()))
233 assert(!
"error in WaitingThread");
234 *thread.error = ::GetLastError();
241 void WaitObjectContainer::CreateThreads(
unsigned int count)
243 size_t currentCount = m_threads.size();
244 if (currentCount == 0)
246 m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
247 m_stopWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
250 if (currentCount < count)
252 m_threads.resize(count);
253 for (
size_t i=currentCount; i<count; i++)
256 if(!m_threads[i])
continue;
260 thread.terminate =
false;
261 thread.startWaiting = m_startWaiting;
262 thread.stopWaiting = m_stopWaiting;
263 thread.waitingToWait =
false;
264 thread.threadHandle = CreateThread(NULL, 0, &WaitingThread, &thread, 0, &thread.threadId);
269 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
271 if (m_noWait || (m_handles.empty() && !m_firstEventTime))
273 SetLastResult(LastResultType(LASTRESULT_NOWAIT));
277 bool timeoutIsScheduledEvent =
false;
279 if (m_firstEventTime)
281 double timeToFirstEvent =
SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
283 if (timeToFirstEvent <= milliseconds)
285 milliseconds = (
unsigned long)timeToFirstEvent;
286 timeoutIsScheduledEvent =
true;
289 if (m_handles.empty() || !milliseconds)
293 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
294 return timeoutIsScheduledEvent;
298 if (m_handles.size() > MAXIMUM_WAIT_OBJECTS)
301 static const unsigned int WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1;
302 unsigned int nThreads = (
unsigned int)((m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD);
303 if (nThreads > MAXIMUM_WAIT_OBJECTS)
304 throw Err(
"WaitObjectContainer: number of wait objects exceeds limit");
305 CreateThreads(nThreads);
308 for (
unsigned int i=0; i<m_threads.size(); i++)
311 if(!m_threads[i])
continue;
314 while (!thread.waitingToWait)
318 thread.waitHandles = &m_handles[i*WAIT_OBJECTS_PER_THREAD];
319 thread.count =
UnsignedMin(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD);
320 thread.error = &error;
326 ResetEvent(m_stopWaiting);
327 PulseEvent(m_startWaiting);
329 #if defined(USE_WINDOWS8_API) 330 DWORD result = ::WaitForSingleObjectEx(m_stopWaiting, milliseconds, FALSE);
331 assert(result != WAIT_FAILED);
333 DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds);
334 assert(result != WAIT_FAILED);
337 if (result == WAIT_OBJECT_0)
342 throw Err(
"WaitObjectContainer: WaitForMultipleObjects in thread failed with error " +
IntToString(error));
344 SetEvent(m_stopWaiting);
345 if (result == WAIT_TIMEOUT)
347 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
348 return timeoutIsScheduledEvent;
351 throw Err(
"WaitObjectContainer: WaitForSingleObject failed with error " +
IntToString(::GetLastError()));
356 static Timer t(Timer::MICROSECONDS);
357 static unsigned long lastTime = 0;
358 unsigned long timeBeforeWait = t.ElapsedTime();
360 #if defined(USE_WINDOWS8_API) 361 DWORD result = ::WaitForMultipleObjectsEx((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds, FALSE);
362 assert(result != WAIT_FAILED);
364 DWORD result = ::WaitForMultipleObjects((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds);
365 assert(result != WAIT_FAILED);
368 if (milliseconds > 0)
370 unsigned long timeAfterWait = t.ElapsedTime();
371 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());
372 lastTime = timeAfterWait;
375 if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
377 if (result == m_lastResult)
381 m_lastResult = result;
382 m_sameResultCount = 0;
386 else if (result == WAIT_TIMEOUT)
388 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
389 return timeoutIsScheduledEvent;
392 throw Err(
"WaitObjectContainer: WaitForMultipleObjects failed with error " +
IntToString(::GetLastError()));
396 #else // #ifdef USE_WINDOWS_STYLE_SOCKETS 398 void WaitObjectContainer::AddReadFd(
int fd,
CallStack const& callStack)
400 CRYPTOPP_UNUSED(callStack);
401 FD_SET(fd, &m_readfds);
402 m_maxFd =
STDMAX(m_maxFd, fd);
405 void WaitObjectContainer::AddWriteFd(
int fd,
CallStack const& callStack)
407 CRYPTOPP_UNUSED(callStack);
408 FD_SET(fd, &m_writefds);
409 m_maxFd =
STDMAX(m_maxFd, fd);
412 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
414 if (m_noWait || (!m_maxFd && !m_firstEventTime))
417 bool timeoutIsScheduledEvent =
false;
419 if (m_firstEventTime)
421 double timeToFirstEvent =
SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
422 if (timeToFirstEvent <= milliseconds)
424 milliseconds = (
unsigned long)timeToFirstEvent;
425 timeoutIsScheduledEvent =
true;
429 timeval tv, *timeout;
435 tv.tv_sec = milliseconds / 1000;
436 tv.tv_usec = (milliseconds % 1000) * 1000;
440 int result = select(m_maxFd+1, &m_readfds, &m_writefds, NULL, timeout);
444 else if (result == 0)
445 return timeoutIsScheduledEvent;
447 throw Err(
"WaitObjectContainer: select failed with error " +
IntToString(errno));
454 std::string CallStack::Format()
const 459 std::string CallStackWithNr::Format()
const 461 return std::string(m_info) +
" / nr: " +
IntToString(m_nr);
464 std::string CallStackWithStr::Format()
const 466 return std::string(m_info) +
" / " + std::string(m_z);
472 GetWaitObjects(container, callStack);
473 return container.Wait(milliseconds);
Base class for all exceptions thrown by the library.
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.