diff options
author | weidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0> | 2003-03-20 01:24:12 +0000 |
---|---|---|
committer | weidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0> | 2003-03-20 01:24:12 +0000 |
commit | d23a489940499bd6c634a1cb0a9875f094f8a850 (patch) | |
tree | f85b3bed971083e90e5f3dbb84539ea4ba0359e9 /wait.cpp | |
parent | b3517523a738277cfe22428bd757833e69abb66e (diff) | |
download | cryptopp-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.cpp | 151 |
1 files changed, 144 insertions, 7 deletions
@@ -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 |