summaryrefslogtreecommitdiff
path: root/wait.cpp
diff options
context:
space:
mode:
authorweidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0>2003-03-20 01:24:12 +0000
committerweidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0>2003-03-20 01:24:12 +0000
commitd23a489940499bd6c634a1cb0a9875f094f8a850 (patch)
treef85b3bed971083e90e5f3dbb84539ea4ba0359e9 /wait.cpp
parentb3517523a738277cfe22428bd757833e69abb66e (diff)
downloadcryptopp-d23a489940499bd6c634a1cb0a9875f094f8a850.tar.gz
various changes for 5.1
git-svn-id: svn://svn.code.sf.net/p/cryptopp/code/trunk/c5@38 57ff6487-cd31-0410-9ec3-f628ee90f5f0
Diffstat (limited to 'wait.cpp')
-rw-r--r--wait.cpp151
1 files changed, 144 insertions, 7 deletions
diff --git a/wait.cpp b/wait.cpp
index f7a0e36..c97d714 100644
--- a/wait.cpp
+++ b/wait.cpp
@@ -34,24 +34,161 @@ void WaitObjectContainer::Clear()
#ifdef USE_WINDOWS_STYLE_SOCKETS
+struct WaitingThreadData
+{
+ bool waitingToWait, terminate;
+ HANDLE startWaiting, stopWaiting;
+ const HANDLE *waitHandles;
+ unsigned int count;
+ HANDLE threadHandle;
+ DWORD threadId;
+ DWORD* error;
+};
+
+WaitObjectContainer::~WaitObjectContainer()
+{
+ if (!m_threads.empty())
+ {
+ HANDLE threadHandles[MAXIMUM_WAIT_OBJECTS];
+ unsigned int i;
+ for (i=0; i<m_threads.size(); i++)
+ {
+ WaitingThreadData &thread = *m_threads[i];
+ while (!thread.waitingToWait) // spin until thread is in the initial "waiting to wait" state
+ Sleep(0);
+ thread.terminate = true;
+ threadHandles[i] = thread.threadHandle;
+ }
+ PulseEvent(m_startWaiting);
+ ::WaitForMultipleObjects(m_threads.size(), threadHandles, TRUE, INFINITE);
+ for (i=0; i<m_threads.size(); i++)
+ CloseHandle(threadHandles[i]);
+ CloseHandle(m_startWaiting);
+ CloseHandle(m_stopWaiting);
+ }
+}
+
void WaitObjectContainer::AddHandle(HANDLE handle)
{
m_handles.push_back(handle);
}
+DWORD WINAPI WaitingThread(LPVOID lParam)
+{
+ std::auto_ptr<WaitingThreadData> pThread((WaitingThreadData *)lParam);
+ WaitingThreadData &thread = *pThread;
+ std::vector<HANDLE> handles;
+
+ while (true)
+ {
+ thread.waitingToWait = true;
+ ::WaitForSingleObject(thread.startWaiting, INFINITE);
+ thread.waitingToWait = false;
+
+ if (thread.terminate)
+ return S_OK;
+ if (!thread.count)
+ continue;
+
+ handles.resize(thread.count + 1);
+ handles[0] = thread.stopWaiting;
+ std::copy(thread.waitHandles, thread.waitHandles+thread.count, handles.begin()+1);
+
+ DWORD result = ::WaitForMultipleObjects(handles.size(), handles.begin(), FALSE, INFINITE);
+
+ if (result == WAIT_OBJECT_0)
+ continue; // another thread finished waiting first, so do nothing
+ SetEvent(thread.stopWaiting);
+ if (!(result > WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + handles.size()))
+ {
+ assert(!"error in WaitingThread"); // break here so we can see which thread has an error
+ *thread.error = ::GetLastError();
+ }
+ }
+}
+
+void WaitObjectContainer::CreateThreads(unsigned int count)
+{
+ unsigned int currentCount = m_threads.size();
+ if (currentCount == 0)
+ {
+ m_startWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_stopWaiting = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ }
+
+ if (currentCount < count)
+ {
+ m_threads.resize(count);
+ for (unsigned int i=currentCount; i<count; i++)
+ {
+ m_threads[i] = new WaitingThreadData;
+ WaitingThreadData &thread = *m_threads[i];
+ thread.terminate = false;
+ thread.startWaiting = m_startWaiting;
+ thread.stopWaiting = m_stopWaiting;
+ thread.waitingToWait = false;
+ thread.threadHandle = CreateThread(NULL, 0, &WaitingThread, &thread, 0, &thread.threadId);
+ }
+ }
+}
+
bool WaitObjectContainer::Wait(unsigned long milliseconds)
{
if (m_noWait || m_handles.empty())
return true;
- DWORD result = ::WaitForMultipleObjects(m_handles.size(), &m_handles[0], FALSE, milliseconds);
-
- if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
- return true;
- else if (result == WAIT_TIMEOUT)
- return false;
+ if (m_handles.size() > MAXIMUM_WAIT_OBJECTS)
+ {
+ // too many wait objects for a single WaitForMultipleObjects call, so use multiple threads
+ static const unsigned int WAIT_OBJECTS_PER_THREAD = MAXIMUM_WAIT_OBJECTS-1;
+ unsigned int nThreads = (m_handles.size() + WAIT_OBJECTS_PER_THREAD - 1) / WAIT_OBJECTS_PER_THREAD;
+ if (nThreads > MAXIMUM_WAIT_OBJECTS) // still too many wait objects, maybe implement recursive threading later?
+ throw Err("WaitObjectContainer: number of wait objects exceeds limit");
+ CreateThreads(nThreads);
+ DWORD error = S_OK;
+
+ for (unsigned int i=0; i<m_threads.size(); i++)
+ {
+ WaitingThreadData &thread = *m_threads[i];
+ while (!thread.waitingToWait) // spin until thread is in the initial "waiting to wait" state
+ Sleep(0);
+ if (i<nThreads)
+ {
+ thread.waitHandles = m_handles.begin() + i*WAIT_OBJECTS_PER_THREAD;
+ thread.count = STDMIN(WAIT_OBJECTS_PER_THREAD, m_handles.size() - i*WAIT_OBJECTS_PER_THREAD);
+ thread.error = &error;
+ }
+ else
+ thread.count = 0;
+ }
+
+ ResetEvent(m_stopWaiting);
+ PulseEvent(m_startWaiting);
+
+ DWORD result = ::WaitForSingleObject(m_stopWaiting, milliseconds);
+ if (result == WAIT_OBJECT_0)
+ {
+ if (error == S_OK)
+ return true;
+ else
+ throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(error));
+ }
+ SetEvent(m_stopWaiting);
+ if (result == WAIT_TIMEOUT)
+ return false;
+ else
+ throw Err("WaitObjectContainer: WaitForSingleObject failed with error " + IntToString(::GetLastError()));
+ }
else
- throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError()));
+ {
+ DWORD result = ::WaitForMultipleObjects(m_handles.size(), &m_handles[0], FALSE, milliseconds);
+ if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
+ return true;
+ else if (result == WAIT_TIMEOUT)
+ return false;
+ else
+ throw Err("WaitObjectContainer: WaitForMultipleObjects failed with error " + IntToString(::GetLastError()));
+ }
}
#else