7 #ifdef SOCKETS_AVAILABLE
9 #ifdef USE_BERKELEY_STYLE_SOCKETS
11 #include <sys/types.h>
16 NAMESPACE_BEGIN(CryptoPP)
20 #ifdef USE_WINDOWS_STYLE_SOCKETS
21 return MAXIMUM_WAIT_OBJECTS * (MAXIMUM_WAIT_OBJECTS-1);
28 : m_tracer(tracer), m_eventTimer(
Timer::MILLISECONDS)
29 , m_sameResultCount(0), m_noWaitTimer(
Timer::MILLISECONDS)
32 m_eventTimer.StartTimer();
35 void WaitObjectContainer::Clear()
37 #ifdef USE_WINDOWS_STYLE_SOCKETS
48 inline void WaitObjectContainer::SetLastResult(LastResultType result)
50 if (result == m_lastResult)
54 m_lastResult = result;
55 m_sameResultCount = 0;
59 void WaitObjectContainer::DetectNoWait(LastResultType result,
CallStack const& callStack)
61 if (result == m_lastResult && m_noWaitTimer.ElapsedTime() > 1000)
63 if (m_sameResultCount > m_noWaitTimer.ElapsedTime())
67 std::string desc =
"No wait loop detected - m_lastResult: ";
68 desc.append(IntToString(m_lastResult)).append(
", call stack:");
69 for (
CallStack const* cs = &callStack; cs; cs = cs->Prev())
70 desc.append(
"\n- ").append(cs->Format());
71 m_tracer->TraceNoWaitLoop(desc);
73 try {
throw 0; }
catch (...) {}
76 m_noWaitTimer.StartTimer();
77 m_sameResultCount = 0;
81 void WaitObjectContainer::SetNoWait(
CallStack const& callStack)
83 DetectNoWait(LASTRESULT_NOWAIT,
CallStack(
"WaitObjectContainer::SetNoWait()", &callStack));
87 void WaitObjectContainer::ScheduleEvent(
double milliseconds,
CallStack const& callStack)
89 if (milliseconds <= 3)
90 DetectNoWait(LASTRESULT_SCHEDULED,
CallStack(
"WaitObjectContainer::ScheduleEvent()", &callStack));
91 double thisEventTime = m_eventTimer.ElapsedTimeAsDouble() + milliseconds;
92 if (!m_firstEventTime || thisEventTime < m_firstEventTime)
93 m_firstEventTime = thisEventTime;
96 #ifdef USE_WINDOWS_STYLE_SOCKETS
100 bool waitingToWait, terminate;
101 HANDLE startWaiting, stopWaiting;
102 const HANDLE *waitHandles;
109 WaitObjectContainer::~WaitObjectContainer()
113 if (!m_threads.empty())
115 HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS];
117 for (i=0; i<m_threads.size(); i++)
120 while (!thread.waitingToWait)
122 thread.terminate =
true;
123 threadHandles[i] = thread.threadHandle;
125 PulseEvent(m_startWaiting);
126 ::WaitForMultipleObjects((DWORD)m_threads.size(), threadHandles, TRUE, INFINITE);
127 for (i=0; i<m_threads.size(); i++)
128 CloseHandle(threadHandles[i]);
129 CloseHandle(m_startWaiting);
130 CloseHandle(m_stopWaiting);
139 void WaitObjectContainer::AddHandle(HANDLE handle,
CallStack const& callStack)
141 DetectNoWait(m_handles.size(),
CallStack(
"WaitObjectContainer::AddHandle()", &callStack));
142 m_handles.push_back(handle);
145 DWORD WINAPI WaitingThread(LPVOID lParam)
149 std::vector<HANDLE> handles;
153 thread.waitingToWait =
true;
154 ::WaitForSingleObject(thread.startWaiting, INFINITE);
155 thread.waitingToWait =
false;
157 if (thread.terminate)
162 handles.resize(thread.count + 1);
163 handles[0] = thread.stopWaiting;
164 std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1);
166 DWORD result = ::WaitForMultipleObjects((DWORD)handles.size(), &handles[0], FALSE, INFINITE);
168 if (result == WAIT_OBJECT_0)
170 SetEvent(thread.stopWaiting);
171 if (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size()))
173 assert(!
"error in WaitingThread");
174 *thread.error = ::GetLastError();
181 void WaitObjectContainer::CreateThreads(
unsigned int count)
183 size_t currentCount = m_threads.size();
184 if (currentCount == 0)
186 m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
187 m_stopWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
190 if (currentCount < count)
192 m_threads.resize(count);
193 for (
size_t i=currentCount; i<count; i++)
197 thread.terminate =
false;
198 thread.startWaiting = m_startWaiting;
199 thread.stopWaiting = m_stopWaiting;
200 thread.waitingToWait =
false;
201 thread.threadHandle = CreateThread(NULL, 0, &WaitingThread, &thread, 0, &thread.threadId);
206 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
208 if (m_noWait || (m_handles.empty() && !m_firstEventTime))
210 SetLastResult(LASTRESULT_NOWAIT);
214 bool timeoutIsScheduledEvent =
false;
216 if (m_firstEventTime)
218 double timeToFirstEvent = SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
220 if (timeToFirstEvent <= milliseconds)
222 milliseconds = (
unsigned long)timeToFirstEvent;
223 timeoutIsScheduledEvent =
true;
226 if (m_handles.empty() || !milliseconds)
230 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
231 return timeoutIsScheduledEvent;
235 if (m_handles.size() > MAXIMUM_WAIT_OBJECTS)
238 static const unsigned int WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1;
239 unsigned int nThreads = (
unsigned int)((m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD);
240 if (nThreads > MAXIMUM_WAIT_OBJECTS)
241 throw Err(
"WaitObjectContainer: number of wait objects exceeds limit");
242 CreateThreads(nThreads);
245 for (
unsigned int i=0; i<m_threads.size(); i++)
248 while (!thread.waitingToWait)
252 thread.waitHandles = &m_handles[i*WAIT_OBJECTS_PER_THREAD];
253 thread.count = UnsignedMin(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD);
254 thread.error = &error;
260 ResetEvent(m_stopWaiting);
261 PulseEvent(m_startWaiting);
263 DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds);
264 if (result == WAIT_OBJECT_0)
269 throw Err(
"WaitObjectContainer: WaitForMultipleObjects in thread failed with error " + IntToString(error));
271 SetEvent(m_stopWaiting);
272 if (result == WAIT_TIMEOUT)
274 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
275 return timeoutIsScheduledEvent;
278 throw Err(
"WaitObjectContainer: WaitForSingleObject failed with error " + IntToString(::GetLastError()));
283 static Timer t(Timer::MICROSECONDS);
284 static unsigned long lastTime = 0;
285 unsigned long timeBeforeWait = t.ElapsedTime();
287 DWORD result = ::WaitForMultipleObjects((DWORD)m_handles.size(), &m_handles[0], FALSE, milliseconds);
289 if (milliseconds > 0)
291 unsigned long timeAfterWait = t.ElapsedTime();
292 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());
293 lastTime = timeAfterWait;
296 if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
298 if (result == m_lastResult)
302 m_lastResult = result;
303 m_sameResultCount = 0;
307 else if (result == WAIT_TIMEOUT)
309 SetLastResult(timeoutIsScheduledEvent ? LASTRESULT_SCHEDULED : LASTRESULT_TIMEOUT);
310 return timeoutIsScheduledEvent;
313 throw Err(
"WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError()));
317 #else // #ifdef USE_WINDOWS_STYLE_SOCKETS
319 void WaitObjectContainer::AddReadFd(
int fd,
CallStack const& callStack)
321 FD_SET(fd, &m_readfds);
322 m_maxFd = STDMAX(m_maxFd, fd);
325 void WaitObjectContainer::AddWriteFd(
int fd,
CallStack const& callStack)
327 FD_SET(fd, &m_writefds);
328 m_maxFd = STDMAX(m_maxFd, fd);
331 bool WaitObjectContainer::Wait(
unsigned long milliseconds)
333 if (m_noWait || (!m_maxFd && !m_firstEventTime))
336 bool timeoutIsScheduledEvent =
false;
338 if (m_firstEventTime)
340 double timeToFirstEvent = SaturatingSubtract(m_firstEventTime, m_eventTimer.ElapsedTimeAsDouble());
341 if (timeToFirstEvent <= milliseconds)
343 milliseconds = (
unsigned long)timeToFirstEvent;
344 timeoutIsScheduledEvent =
true;
348 timeval tv, *timeout;
354 tv.tv_sec = milliseconds / 1000;
355 tv.tv_usec = (milliseconds % 1000) * 1000;
359 int result = select(m_maxFd+1, &m_readfds, &m_writefds, NULL, timeout);
363 else if (result == 0)
364 return timeoutIsScheduledEvent;
366 throw Err(
"WaitObjectContainer: select failed with error " + errno);
373 std::string CallStack::Format()
const
378 std::string CallStackWithNr::Format()
const
380 return std::string(m_info) +
" / nr: " + IntToString(m_nr);
383 std::string CallStackWithStr::Format()
const
385 return std::string(m_info) +
" / " + std::string(m_z);
392 return container.Wait(milliseconds);
container of wait objects
virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const &callStack)=0
put wait objects into container
const unsigned long INFINITE_TIME
used to represent infinite time
bool Wait(unsigned long milliseconds, CallStack const &callStack)
wait on this object