8 #if CRYPTOPP_MSC_VERSION 9 # pragma warning(disable: 4189) 10 # pragma warning(disable: 4589) 13 #if !defined(NO_OS_DEPENDENCE) && (defined(SOCKETS_AVAILABLE) || defined(WINDOWS_PIPES_AVAILABLE)) 20 #if defined(CRYPTOPP_WIN32_AVAILABLE) 21 # if ((WINVER >= 0x0602 ) || (_WIN32_WINNT >= 0x0602 )) 22 # include <synchapi.h> 23 # include <ioapiset.h> 24 # define USE_WINDOWS8_API 28 #ifdef USE_BERKELEY_STYLE_SOCKETS 30 #include <sys/types.h> 35 #if defined(CRYPTOPP_MSAN) 36 # include <sanitizer/msan_interface.h> 41 unsigned int WaitObjectContainer::MaxWaitObjects()
43 #ifdef USE_WINDOWS_STYLE_SOCKETS 44 return MAXIMUM_WAIT_OBJECTS * (MAXIMUM_WAIT_OBJECTS-1);
52 #ifdef USE_WINDOWS_STYLE_SOCKETS
53 m_startWaiting(0), m_stopWaiting(0),
55 m_firstEventTime(0.0f), m_eventTimer(
Timer::MILLISECONDS), m_lastResult(0),
56 m_sameResultCount(0), m_noWaitTimer(
Timer::MILLISECONDS)
59 m_eventTimer.StartTimer();
62 void WaitObjectContainer::Clear()
64 #ifdef USE_WINDOWS_STYLE_SOCKETS 71 __msan_unpoison(&m_readfds,
sizeof(m_readfds));
72 __msan_unpoison(&m_writefds,
sizeof(m_writefds));
79 inline void WaitObjectContainer::SetLastResult(LastResultType result)
81 if (result == m_lastResult)
85 m_lastResult = result;
86 m_sameResultCount = 0;
90 void WaitObjectContainer::DetectNoWait(LastResultType result,
CallStack const& callStack)
92 if (result == m_lastResult && m_noWaitTimer.ElapsedTime() > 1000)
94 if (m_sameResultCount > m_noWaitTimer.ElapsedTime())
98 std::string desc =
"No wait loop detected - m_lastResult: ";
99 desc.append(
IntToString(m_lastResult)).append(
", call stack:");
100 for (
CallStack const* cs = &callStack; cs; cs = cs->Prev())
101 desc.append(
"\n- ").append(cs->Format());
102 m_tracer->TraceNoWaitLoop(desc);
104 try {
throw 0; }
catch (...) {}
107 m_noWaitTimer.StartTimer();
108 m_sameResultCount = 0;
112 void WaitObjectContainer::SetNoWait(
CallStack const& callStack)
114 DetectNoWait(LastResultType(LASTRESULT_NOWAIT),
CallStack(
"WaitObjectContainer::SetNoWait()", &callStack));
118 void WaitObjectContainer::ScheduleEvent(
double milliseconds,
CallStack const& callStack)
120 if (milliseconds <= 3)
121 DetectNoWait(LastResultType(LASTRESULT_SCHEDULED),
CallStack(
"WaitObjectContainer::ScheduleEvent()", &callStack));
122 double thisEventTime = m_eventTimer.ElapsedTimeAsDouble() + milliseconds;
123 if (!m_firstEventTime || thisEventTime < m_firstEventTime)
124 m_firstEventTime = thisEventTime;
127 #ifdef USE_WINDOWS_STYLE_SOCKETS 131 bool waitingToWait, terminate;
132 HANDLE startWaiting, stopWaiting;
133 const HANDLE *waitHandles;
140 WaitObjectContainer::~WaitObjectContainer()
144 if (!m_threads.empty())
146 HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS] = {0};
149 for (i=0; i<m_threads.size(); i++)
152 if(!m_threads[i])
continue;
155 while (!thread.waitingToWait)
157 thread.terminate =
true;
158 threadHandles[i] = thread.threadHandle;
161 BOOL bResult = PulseEvent(m_startWaiting);
165 #if defined(USE_WINDOWS8_API) 166 DWORD dwResult = ::WaitForMultipleObjectsEx((DWORD)m_threads.size(), threadHandles, TRUE, INFINITE, FALSE);
169 DWORD dwResult = ::WaitForMultipleObjects((DWORD)m_threads.size(), threadHandles, TRUE, INFINITE);
170 CRYPTOPP_UNUSED(dwResult);
174 for (i=0; i<m_threads.size(); i++)
177 if (!threadHandles[i])
continue;
179 bResult = CloseHandle(threadHandles[i]);
183 bResult = CloseHandle(m_startWaiting);
185 bResult = CloseHandle(m_stopWaiting);
195 void WaitObjectContainer::AddHandle(HANDLE handle,
CallStack const& callStack)
197 DetectNoWait(m_handles.size(),
CallStack(
"WaitObjectContainer::AddHandle()", &callStack));
198 m_handles.push_back(handle);
201 DWORD WINAPI WaitingThread(LPVOID lParam)
205 std::vector<HANDLE> handles;
209 thread.waitingToWait =
true;
210 #if defined(USE_WINDOWS8_API) 211 DWORD result = ::WaitForSingleObjectEx(thread.startWaiting, INFINITE, FALSE);
214 DWORD result = ::WaitForSingleObject(thread.startWaiting, INFINITE);
218 thread.waitingToWait =
false;
219 if (thread.terminate)
224 handles.resize(thread.count + 1);
225 handles[0] = thread.stopWaiting;
226 std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1);
228 #if defined(USE_WINDOWS8_API) 229 result = ::WaitForMultipleObjectsEx((DWORD)handles.size(), &handles[0], FALSE, INFINITE, FALSE);
232 result = ::WaitForMultipleObjects((DWORD)handles.size(), &handles[0], FALSE, INFINITE);
236 if (result == WAIT_OBJECT_0)
238 SetEvent(thread.stopWaiting);
239 if (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size()))
242 *thread.error = ::GetLastError();
249 void WaitObjectContainer::CreateThreads(
unsigned int count)
251 size_t currentCount = m_threads.size();
252 if (currentCount == 0)
254 m_startWaiting = ::CreateEvent(NULLPTR, TRUE, FALSE, NULLPTR);
255 m_stopWaiting = ::CreateEvent(NULLPTR, TRUE, FALSE, NULLPTR);
258 if (currentCount < count)
260 m_threads.resize(count);
261 for (
size_t i=currentCount; i<count; i++)
264 if(!m_threads[i])
continue;
268 thread.terminate =
false;
269 thread.startWaiting = m_startWaiting;
270 thread.stopWaiting = m_stopWaiting;
271 thread.waitingToWait =
false;
272 thread.threadHandle = CreateThread(NULLPTR, 0, &WaitingThread, &thread, 0, &thread.threadId);
277 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
279 if (m_noWait || (m_handles.empty() && !m_firstEventTime))
281 SetLastResult(LastResultType(LASTRESULT_NOWAIT));
285 bool timeoutIsScheduledEvent =
false;
287 if (m_firstEventTime)
289 double timeToFirstEvent =
SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
291 if (timeToFirstEvent <= milliseconds)
293 milliseconds = (
unsigned long)timeToFirstEvent;
294 timeoutIsScheduledEvent =
true;
297 if (m_handles.empty() || !milliseconds)
301 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
302 return timeoutIsScheduledEvent;
306 if (m_handles.size() > MAXIMUM_WAIT_OBJECTS)
309 static const unsigned int WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1;
310 unsigned int nThreads = (
unsigned int)((m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD);
311 if (nThreads > MAXIMUM_WAIT_OBJECTS)
312 throw Err(
"WaitObjectContainer: number of wait objects exceeds limit");
313 CreateThreads(nThreads);
316 for (
unsigned int i=0; i<m_threads.size(); i++)
319 if(!m_threads[i])
continue;
322 while (!thread.waitingToWait)
326 thread.waitHandles = &m_handles[i*WAIT_OBJECTS_PER_THREAD];
327 thread.count =
UnsignedMin(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD);
328 thread.error = &error;
334 ResetEvent(m_stopWaiting);
335 PulseEvent(m_startWaiting);
337 #if defined(USE_WINDOWS8_API) 338 DWORD result = ::WaitForSingleObjectEx(m_stopWaiting, milliseconds, FALSE);
341 DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds);
345 if (result == WAIT_OBJECT_0)
350 throw Err(
"WaitObjectContainer: WaitForMultipleObjects in thread failed with error " +
IntToString(error));
352 SetEvent(m_stopWaiting);
353 if (result == WAIT_TIMEOUT)
355 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
356 return timeoutIsScheduledEvent;
359 throw Err(
"WaitObjectContainer: WaitForSingleObject failed with error " +
IntToString(::GetLastError()));
364 static Timer t(Timer::MICROSECONDS);
365 static unsigned long lastTime = 0;
366 unsigned long timeBeforeWait = t.ElapsedTime();
368 #if defined(USE_WINDOWS8_API) 369 DWORD result = ::WaitForMultipleObjectsEx((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds, FALSE);
372 DWORD result = ::WaitForMultipleObjects((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds);
376 if (milliseconds > 0)
378 unsigned long timeAfterWait = t.ElapsedTime();
379 OutputDebugStringA((
"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());
380 lastTime = timeAfterWait;
383 if (result < WAIT_OBJECT_0 + m_handles.size())
385 if (result == m_lastResult)
389 m_lastResult = result;
390 m_sameResultCount = 0;
394 else if (result == WAIT_TIMEOUT)
396 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
397 return timeoutIsScheduledEvent;
400 throw Err(
"WaitObjectContainer: WaitForMultipleObjects failed with error " +
IntToString(::GetLastError()));
404 #else // #ifdef USE_WINDOWS_STYLE_SOCKETS 406 void WaitObjectContainer::AddReadFd(
int fd,
CallStack const& callStack)
408 CRYPTOPP_UNUSED(callStack);
409 FD_SET(fd, &m_readfds);
410 m_maxFd =
STDMAX(m_maxFd, fd);
413 void WaitObjectContainer::AddWriteFd(
int fd,
CallStack const& callStack)
415 CRYPTOPP_UNUSED(callStack);
416 FD_SET(fd, &m_writefds);
417 m_maxFd =
STDMAX(m_maxFd, fd);
420 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
422 if (m_noWait || (!m_maxFd && !m_firstEventTime))
425 bool timeoutIsScheduledEvent =
false;
427 if (m_firstEventTime)
429 double timeToFirstEvent =
SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
430 if (timeToFirstEvent <= milliseconds)
432 milliseconds = (
unsigned long)timeToFirstEvent;
433 timeoutIsScheduledEvent =
true;
437 timeval tv, *timeout;
443 tv.tv_sec = milliseconds / 1000;
444 tv.tv_usec = (milliseconds % 1000) * 1000;
448 int result = select(m_maxFd+1, &m_readfds, &m_writefds, NULLPTR, timeout);
452 else if (result == 0)
453 return timeoutIsScheduledEvent;
455 throw Err(
"WaitObjectContainer: select failed with error " +
IntToString(errno));
462 std::string CallStack::Format()
const 467 std::string CallStackWithNr::Format()
const 469 return std::string(m_info) +
" / nr: " +
IntToString(m_nr);
472 std::string CallStackWithStr::Format()
const 474 return std::string(m_info) +
" / " + std::string(m_z);
481 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 ->
virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const &callStack)=0
Retrieves waitable objects.
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.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
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.