00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #if defined(_MSC_VER) && !defined(_MT)
00016 # error multithreading compile option is required
00017 #endif
00018
00019 #include "CArchMultithreadWindows.h"
00020 #include "CArch.h"
00021 #include "XArch.h"
00022 #include <process.h>
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 class CArchThreadImpl {
00039 public:
00040 CArchThreadImpl();
00041 ~CArchThreadImpl();
00042
00043 public:
00044 int m_refCount;
00045 HANDLE m_thread;
00046 DWORD m_id;
00047 IArchMultithread::ThreadFunc m_func;
00048 void* m_userData;
00049 HANDLE m_cancel;
00050 bool m_cancelling;
00051 HANDLE m_exit;
00052 void* m_result;
00053 void* m_networkData;
00054 };
00055
00056 CArchThreadImpl::CArchThreadImpl() :
00057 m_refCount(1),
00058 m_thread(NULL),
00059 m_id(0),
00060 m_func(NULL),
00061 m_userData(NULL),
00062 m_cancelling(false),
00063 m_result(NULL),
00064 m_networkData(NULL)
00065 {
00066 m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
00067 m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
00068 }
00069
00070 CArchThreadImpl::~CArchThreadImpl()
00071 {
00072 CloseHandle(m_exit);
00073 CloseHandle(m_cancel);
00074 }
00075
00076
00077
00078
00079
00080
00081 CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
00082
00083 CArchMultithreadWindows::CArchMultithreadWindows()
00084 {
00085 assert(s_instance == NULL);
00086 s_instance = this;
00087
00088
00089 for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
00090 m_signalFunc[i] = NULL;
00091 m_signalUserData[i] = NULL;
00092 }
00093
00094
00095 m_threadMutex = newMutex();
00096
00097
00098
00099 m_mainThread = new CArchThreadImpl;
00100 m_mainThread->m_thread = NULL;
00101 m_mainThread->m_id = GetCurrentThreadId();
00102 insert(m_mainThread);
00103 }
00104
00105 CArchMultithreadWindows::~CArchMultithreadWindows()
00106 {
00107 s_instance = NULL;
00108
00109
00110 for (CThreadList::iterator index = m_threadList.begin();
00111 index != m_threadList.end(); ++index) {
00112 delete *index;
00113 }
00114
00115
00116 delete m_threadMutex;
00117 }
00118
00119 void
00120 CArchMultithreadWindows::setNetworkDataForCurrentThread(void* data)
00121 {
00122 lockMutex(m_threadMutex);
00123 CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
00124 thread->m_networkData = data;
00125 unlockMutex(m_threadMutex);
00126 }
00127
00128 void*
00129 CArchMultithreadWindows::getNetworkDataForThread(CArchThread thread)
00130 {
00131 lockMutex(m_threadMutex);
00132 void* data = thread->m_networkData;
00133 unlockMutex(m_threadMutex);
00134 return data;
00135 }
00136
00137 HANDLE
00138 CArchMultithreadWindows::getCancelEventForCurrentThread()
00139 {
00140 lockMutex(m_threadMutex);
00141 CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
00142 unlockMutex(m_threadMutex);
00143 return thread->m_cancel;
00144 }
00145
00146 CArchMultithreadWindows*
00147 CArchMultithreadWindows::getInstance()
00148 {
00149 return s_instance;
00150 }
00151
00152 CArchCond
00153 CArchMultithreadWindows::newCondVar()
00154 {
00155 CArchCondImpl* cond = new CArchCondImpl;
00156 cond->m_events[CArchCondImpl::kSignal] = CreateEvent(NULL,
00157 FALSE, FALSE, NULL);
00158 cond->m_events[CArchCondImpl::kBroadcast] = CreateEvent(NULL,
00159 TRUE, FALSE, NULL);
00160 cond->m_waitCountMutex = newMutex();
00161 cond->m_waitCount = 0;
00162 return cond;
00163 }
00164
00165 void
00166 CArchMultithreadWindows::closeCondVar(CArchCond cond)
00167 {
00168 CloseHandle(cond->m_events[CArchCondImpl::kSignal]);
00169 CloseHandle(cond->m_events[CArchCondImpl::kBroadcast]);
00170 closeMutex(cond->m_waitCountMutex);
00171 delete cond;
00172 }
00173
00174 void
00175 CArchMultithreadWindows::signalCondVar(CArchCond cond)
00176 {
00177
00178 lockMutex(cond->m_waitCountMutex);
00179 const bool hasWaiter = (cond->m_waitCount > 0);
00180 unlockMutex(cond->m_waitCountMutex);
00181
00182
00183 if (hasWaiter) {
00184 SetEvent(cond->m_events[CArchCondImpl::kSignal]);
00185 }
00186 }
00187
00188 void
00189 CArchMultithreadWindows::broadcastCondVar(CArchCond cond)
00190 {
00191
00192 lockMutex(cond->m_waitCountMutex);
00193 const bool hasWaiter = (cond->m_waitCount > 0);
00194 unlockMutex(cond->m_waitCountMutex);
00195
00196
00197 if (hasWaiter) {
00198 SetEvent(cond->m_events[CArchCondImpl::kBroadcast]);
00199 }
00200 }
00201
00202 bool
00203 CArchMultithreadWindows::waitCondVar(CArchCond cond,
00204 CArchMutex mutex, double timeout)
00205 {
00206
00207 const DWORD winTimeout = (timeout < 0.0) ? INFINITE :
00208 static_cast<DWORD>(1000.0 * timeout);
00209
00210
00211
00212 HANDLE handles[4];
00213 handles[0] = cond->m_events[CArchCondImpl::kSignal];
00214 handles[1] = cond->m_events[CArchCondImpl::kBroadcast];
00215 handles[2] = getCancelEventForCurrentThread();
00216
00217
00218 lockMutex(cond->m_waitCountMutex);
00219 ++cond->m_waitCount;
00220 unlockMutex(cond->m_waitCountMutex);
00221
00222
00223
00224
00225
00226
00227 unlockMutex(mutex);
00228
00229
00230 DWORD result = WaitForMultipleObjects(3, handles, FALSE, winTimeout);
00231
00232
00233 if (result != WAIT_OBJECT_0 + 2 &&
00234 WaitForSingleObject(handles[2], 0) == WAIT_OBJECT_0) {
00235 result = WAIT_OBJECT_0 + 2;
00236 }
00237
00238
00239 lockMutex(cond->m_waitCountMutex);
00240 --cond->m_waitCount;
00241 const bool last = (result == WAIT_OBJECT_0 + 1 && cond->m_waitCount == 0);
00242 unlockMutex(cond->m_waitCountMutex);
00243
00244
00245 if (last) {
00246 ResetEvent(cond->m_events[CArchCondImpl::kBroadcast]);
00247 }
00248
00249
00250 lockMutex(mutex);
00251
00252
00253 if (result == WAIT_OBJECT_0 + 2) {
00254 ARCH->testCancelThread();
00255 }
00256
00257
00258 return (result == WAIT_OBJECT_0 + 0 ||
00259 result == WAIT_OBJECT_0 + 1);
00260 }
00261
00262 CArchMutex
00263 CArchMultithreadWindows::newMutex()
00264 {
00265 CArchMutexImpl* mutex = new CArchMutexImpl;
00266 InitializeCriticalSection(&mutex->m_mutex);
00267 return mutex;
00268 }
00269
00270 void
00271 CArchMultithreadWindows::closeMutex(CArchMutex mutex)
00272 {
00273 DeleteCriticalSection(&mutex->m_mutex);
00274 delete mutex;
00275 }
00276
00277 void
00278 CArchMultithreadWindows::lockMutex(CArchMutex mutex)
00279 {
00280 EnterCriticalSection(&mutex->m_mutex);
00281 }
00282
00283 void
00284 CArchMultithreadWindows::unlockMutex(CArchMutex mutex)
00285 {
00286 LeaveCriticalSection(&mutex->m_mutex);
00287 }
00288
00289 CArchThread
00290 CArchMultithreadWindows::newThread(ThreadFunc func, void* data)
00291 {
00292 lockMutex(m_threadMutex);
00293
00294
00295 CArchThreadImpl* thread = new CArchThreadImpl;
00296 thread->m_func = func;
00297 thread->m_userData = data;
00298
00299
00300 unsigned int id;
00301 thread->m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
00302 threadFunc, (void*)thread, 0, &id));
00303 thread->m_id = static_cast<DWORD>(id);
00304
00305
00306 if (thread->m_thread == 0) {
00307
00308 delete thread;
00309 thread = NULL;
00310 }
00311 else {
00312
00313 insert(thread);
00314
00315
00316 refThread(thread);
00317 }
00318
00319
00320 unlockMutex(m_threadMutex);
00321
00322 return thread;
00323 }
00324
00325 CArchThread
00326 CArchMultithreadWindows::newCurrentThread()
00327 {
00328 lockMutex(m_threadMutex);
00329 CArchThreadImpl* thread = find(GetCurrentThreadId());
00330 unlockMutex(m_threadMutex);
00331 assert(thread != NULL);
00332 return thread;
00333 }
00334
00335 void
00336 CArchMultithreadWindows::closeThread(CArchThread thread)
00337 {
00338 assert(thread != NULL);
00339
00340
00341 if (--thread->m_refCount == 0) {
00342
00343 if (thread->m_thread != NULL) {
00344 CloseHandle(thread->m_thread);
00345 }
00346
00347
00348 lockMutex(m_threadMutex);
00349 assert(findNoRefOrCreate(thread->m_id) == thread);
00350 erase(thread);
00351 unlockMutex(m_threadMutex);
00352
00353
00354 delete thread;
00355 }
00356 }
00357
00358 CArchThread
00359 CArchMultithreadWindows::copyThread(CArchThread thread)
00360 {
00361 refThread(thread);
00362 return thread;
00363 }
00364
00365 void
00366 CArchMultithreadWindows::cancelThread(CArchThread thread)
00367 {
00368 assert(thread != NULL);
00369
00370
00371 SetEvent(thread->m_cancel);
00372 }
00373
00374 void
00375 CArchMultithreadWindows::setPriorityOfThread(CArchThread thread, int n)
00376 {
00377 struct CPriorityInfo {
00378 public:
00379 DWORD m_class;
00380 int m_level;
00381 };
00382 static const CPriorityInfo s_pClass[] = {
00383 { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_IDLE },
00384 { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
00385 { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
00386 { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
00387 { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
00388 { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
00389 { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
00390 { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
00391 { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
00392 { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
00393 { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
00394 { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
00395 { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
00396 { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
00397 { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
00398 { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
00399 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_IDLE },
00400 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
00401 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
00402 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
00403 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
00404 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
00405 { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL}
00406 };
00407 #if defined(_DEBUG)
00408
00409 static const size_t s_pMax = 13;
00410 #else
00411 static const size_t s_pMax = sizeof(s_pClass) / sizeof(s_pClass[0]) - 1;
00412 #endif
00413 static const size_t s_pBase = 8;
00414
00415 assert(thread != NULL);
00416
00417 size_t index;
00418 if (n > 0 && s_pBase < (size_t)n) {
00419
00420 index = 0;
00421 }
00422 else {
00423 index = (size_t)((int)s_pBase - n);
00424 if (index > s_pMax) {
00425
00426 index = s_pMax;
00427 }
00428 }
00429 SetPriorityClass(GetCurrentProcess(), s_pClass[index].m_class);
00430 SetThreadPriority(thread->m_thread, s_pClass[index].m_level);
00431 }
00432
00433 void
00434 CArchMultithreadWindows::testCancelThread()
00435 {
00436
00437 lockMutex(m_threadMutex);
00438 CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
00439 unlockMutex(m_threadMutex);
00440
00441
00442 testCancelThreadImpl(thread);
00443 }
00444
00445 bool
00446 CArchMultithreadWindows::wait(CArchThread target, double timeout)
00447 {
00448 assert(target != NULL);
00449
00450 lockMutex(m_threadMutex);
00451
00452
00453 CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
00454
00455
00456 if (target == self) {
00457 unlockMutex(m_threadMutex);
00458 return false;
00459 }
00460
00461
00462 refThread(target);
00463
00464 unlockMutex(m_threadMutex);
00465
00466
00467 DWORD t;
00468 if (timeout < 0.0) {
00469 t = INFINITE;
00470 }
00471 else {
00472 t = (DWORD)(1000.0 * timeout);
00473 }
00474
00475
00476
00477 HANDLE handles[2];
00478 handles[0] = target->m_exit;
00479 handles[1] = self->m_cancel;
00480 DWORD result = WaitForMultipleObjects(2, handles, FALSE, t);
00481
00482
00483 if (result != WAIT_OBJECT_0 + 1 &&
00484 WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) {
00485 result = WAIT_OBJECT_0 + 1;
00486 }
00487
00488
00489 closeThread(target);
00490
00491
00492 switch (result) {
00493 case WAIT_OBJECT_0 + 0:
00494
00495 return true;
00496
00497 case WAIT_OBJECT_0 + 1:
00498
00499 testCancelThreadImpl(self);
00500
00501 default:
00502
00503 return false;
00504 }
00505 }
00506
00507 bool
00508 CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
00509 {
00510 return (thread1 == thread2);
00511 }
00512
00513 bool
00514 CArchMultithreadWindows::isExitedThread(CArchThread thread)
00515 {
00516
00517 return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0);
00518 }
00519
00520 void*
00521 CArchMultithreadWindows::getResultOfThread(CArchThread thread)
00522 {
00523 lockMutex(m_threadMutex);
00524 void* result = thread->m_result;
00525 unlockMutex(m_threadMutex);
00526 return result;
00527 }
00528
00529 IArchMultithread::ThreadID
00530 CArchMultithreadWindows::getIDOfThread(CArchThread thread)
00531 {
00532 return static_cast<ThreadID>(thread->m_id);
00533 }
00534
00535 void
00536 CArchMultithreadWindows::setSignalHandler(
00537 ESignal signal, SignalFunc func, void* userData)
00538 {
00539 lockMutex(m_threadMutex);
00540 m_signalFunc[signal] = func;
00541 m_signalUserData[signal] = userData;
00542 unlockMutex(m_threadMutex);
00543 }
00544
00545 void
00546 CArchMultithreadWindows::raiseSignal(ESignal signal)
00547 {
00548 lockMutex(m_threadMutex);
00549 if (m_signalFunc[signal] != NULL) {
00550 m_signalFunc[signal](signal, m_signalUserData[signal]);
00551 ARCH->unblockPollSocket(m_mainThread);
00552 }
00553 else if (signal == kINTERRUPT || signal == kTERMINATE) {
00554 ARCH->cancelThread(m_mainThread);
00555 }
00556 unlockMutex(m_threadMutex);
00557 }
00558
00559 CArchThreadImpl*
00560 CArchMultithreadWindows::find(DWORD id)
00561 {
00562 CArchThreadImpl* impl = findNoRef(id);
00563 if (impl != NULL) {
00564 refThread(impl);
00565 }
00566 return impl;
00567 }
00568
00569 CArchThreadImpl*
00570 CArchMultithreadWindows::findNoRef(DWORD id)
00571 {
00572 CArchThreadImpl* impl = findNoRefOrCreate(id);
00573 if (impl == NULL) {
00574
00575
00576
00577
00578 impl = new CArchThreadImpl;
00579 impl->m_thread = NULL;
00580 impl->m_id = GetCurrentThreadId();
00581 insert(impl);
00582 }
00583 return impl;
00584 }
00585
00586 CArchThreadImpl*
00587 CArchMultithreadWindows::findNoRefOrCreate(DWORD id)
00588 {
00589
00590 for (CThreadList::const_iterator index = m_threadList.begin();
00591 index != m_threadList.end(); ++index) {
00592 if ((*index)->m_id == id) {
00593 return *index;
00594 }
00595 }
00596 return NULL;
00597 }
00598
00599 void
00600 CArchMultithreadWindows::insert(CArchThreadImpl* thread)
00601 {
00602 assert(thread != NULL);
00603
00604
00605 assert(findNoRefOrCreate(thread->m_id) == NULL);
00606
00607
00608 m_threadList.push_back(thread);
00609 }
00610
00611 void
00612 CArchMultithreadWindows::erase(CArchThreadImpl* thread)
00613 {
00614 for (CThreadList::iterator index = m_threadList.begin();
00615 index != m_threadList.end(); ++index) {
00616 if (*index == thread) {
00617 m_threadList.erase(index);
00618 break;
00619 }
00620 }
00621 }
00622
00623 void
00624 CArchMultithreadWindows::refThread(CArchThreadImpl* thread)
00625 {
00626 assert(thread != NULL);
00627 assert(findNoRefOrCreate(thread->m_id) != NULL);
00628 ++thread->m_refCount;
00629 }
00630
00631 void
00632 CArchMultithreadWindows::testCancelThreadImpl(CArchThreadImpl* thread)
00633 {
00634 assert(thread != NULL);
00635
00636
00637 const DWORD result = WaitForSingleObject(thread->m_cancel, 0);
00638 if (result != WAIT_OBJECT_0) {
00639 return;
00640 }
00641
00642
00643 lockMutex(m_threadMutex);
00644 bool cancel = !thread->m_cancelling;
00645 thread->m_cancelling = true;
00646 ResetEvent(thread->m_cancel);
00647 unlockMutex(m_threadMutex);
00648
00649
00650 if (cancel) {
00651 throw XThreadCancel();
00652 }
00653 }
00654
00655 unsigned int __stdcall
00656 CArchMultithreadWindows::threadFunc(void* vrep)
00657 {
00658
00659 CArchThreadImpl* thread = reinterpret_cast<CArchThreadImpl*>(vrep);
00660
00661
00662 s_instance->doThreadFunc(thread);
00663
00664
00665 return 0;
00666 }
00667
00668 void
00669 CArchMultithreadWindows::doThreadFunc(CArchThread thread)
00670 {
00671
00672 lockMutex(m_threadMutex);
00673 unlockMutex(m_threadMutex);
00674
00675 void* result = NULL;
00676 try {
00677
00678 result = (*thread->m_func)(thread->m_userData);
00679 }
00680
00681 catch (XThreadCancel&) {
00682
00683 }
00684 catch (...) {
00685
00686 SetEvent(thread->m_exit);
00687 closeThread(thread);
00688 throw;
00689 }
00690
00691
00692 lockMutex(m_threadMutex);
00693 thread->m_result = result;
00694 unlockMutex(m_threadMutex);
00695 SetEvent(thread->m_exit);
00696
00697
00698 closeThread(thread);
00699 }