📄 switrdmonitor.cpp
字号:
/****************License************************************************ * * Copyright 2000-2003. ScanSoft, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.2 which is * included with this software. * * ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech, * SpeechWorks and the SpeechWorks logo are registered trademarks or * trademarks of SpeechWorks International, Inc. in the United States * and other countries. * ***********************************************************************/ #include "SWIutilInternal.h" #ifndef _WIN32 #include <sys/time.h> #include <errno.h> #define INFINITE (~0) #endif #include "SWItrdMonitor.hpp" #include <VXItrd.h> #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #else #include <pthread.h> #endif // ---------- Constants ---------- const int SWItrdMonitor::SUCCESS = 0; const int SWItrdMonitor::FAILURE = -1; const int SWItrdMonitor::NOT_OWNER = 1; // Static initialization for WIN32 #ifdef _WIN32 static void *createMutex(bool locked) { HANDLE *k = new HANDLE; *k = CreateMutex(NULL, locked ? TRUE : FALSE, NULL); return k; } static void deleteMutex(void *mutex) { HANDLE *k = (HANDLE *) mutex; CloseHandle(*k); delete k; } static int lockMutex(void* mutex) { int rc = SWItrdMonitor::SUCCESS; switch (WaitForSingleObject(*(static_cast<HANDLE *>(mutex)), INFINITE)) { case WAIT_FAILED: rc = SWItrdMonitor::FAILURE; break; case WAIT_ABANDONED: // should we log this? break; } return rc; } static int unlockMutex(void* mutex) { return ReleaseMutex(*(static_cast<HANDLE *>(mutex))) ? SWItrdMonitor::SUCCESS : SWItrdMonitor::FAILURE; } static int waitForEvent(void *mutex, void *event, unsigned long millisecs, bool *expiredF) { if (::unlockMutex(mutex) != SWItrdMonitor::SUCCESS) { return SWItrdMonitor::FAILURE; } int rc = SWItrdMonitor::SUCCESS; DWORD waitrc = WaitForSingleObject(*(static_cast<HANDLE *>(event)), millisecs); switch (waitrc) { case WAIT_OBJECT_0: if (expiredF != NULL) *expiredF = false; break; case WAIT_TIMEOUT: if (expiredF != NULL) *expiredF = true; break; case WAIT_FAILED: rc = SWItrdMonitor::FAILURE; break; case WAIT_ABANDONED: // should we log this? break; } ::lockMutex(mutex); return rc; } static int notifyEvent(void *event, bool broadcast) { SetEvent(*(static_cast<HANDLE *>(event))); return SWItrdMonitor::SUCCESS; } #else static void *createMutex(bool locked) { pthread_mutex_t *lock = new pthread_mutex_t; pthread_mutex_init(lock,NULL); if (locked) pthread_mutex_lock(lock); return lock; } static void deleteMutex(void *mutex) { pthread_mutex_t *lock = (pthread_mutex_t *) mutex; pthread_mutex_destroy(lock); delete lock; } static int lockMutex(void *mutex) { return pthread_mutex_lock(static_cast<pthread_mutex_t *>(mutex)) == 0 ? SWItrdMonitor::SUCCESS : SWItrdMonitor::FAILURE; } static int unlockMutex(void *mutex) { return pthread_mutex_unlock(static_cast<pthread_mutex_t *>(mutex)) == 0 ? SWItrdMonitor::SUCCESS : SWItrdMonitor::FAILURE; } static int waitForEvent(void *mutex, void *event, unsigned long millisecs, bool *expiredF) { int rc = SWItrdMonitor::SUCCESS; if (millisecs == INFINITE) { if (pthread_cond_wait(static_cast<pthread_cond_t *>(event), static_cast<pthread_mutex_t *>(mutex)) != 0) rc = SWItrdMonitor::FAILURE; } else { struct timeval now; struct timespec timeout; gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec + millisecs / 1000; unsigned long microsecs = now.tv_usec + (millisecs % 1000) * 1000; if (microsecs >= 1000000) { microsecs -= 1000000; timeout.tv_sec++; } timeout.tv_nsec = microsecs * 1000; rc = pthread_cond_timedwait(static_cast<pthread_cond_t *>(event), static_cast<pthread_mutex_t *>(mutex), &timeout); switch (rc) { case 0: if (expiredF != NULL) *expiredF = false; rc = SWItrdMonitor::SUCCESS; break; case ETIMEDOUT: if (expiredF != NULL) *expiredF = true; rc = SWItrdMonitor::SUCCESS; break; default: rc = SWItrdMonitor::FAILURE; } } return rc; } static int notifyEvent(void *event, bool broadcast) { pthread_cond_t *p = static_cast<pthread_cond_t *>(event); int rc; if (broadcast) rc = pthread_cond_broadcast(p); else rc = pthread_cond_signal(p); if (rc == 0) rc = SWItrdMonitor::SUCCESS; else rc = SWItrdMonitor::FAILURE; return rc; } #endif void* SWItrdMonitor::_globalLock = createMutex(false); SWItrdMonitor::HandleListItem * volatile SWItrdMonitor::_freeThreadList = NULL; SWItrdMonitor::HandleListItem * volatile SWItrdMonitor::_freeMutexList = NULL; // SWItrdMonitor::SWItrdMonitor // Refer to SWItrdMonitor.hpp for doc. SWItrdMonitor::SWItrdMonitor(Policy policy): _ownerThread((VXIthreadID) -1),_lockCount(0), _firstWaitingThread(NULL),_lastWaitingThread(NULL), _mutex(NULL), _policy(policy) { if (policy != POOLED) { _mutex = new HandleListItem; // We don't initialize the other fields as we don't really care _mutex->_handle = ::createMutex(false); } } // SWItrdMonitor::~SWItrdMonitor // Refer to SWItrdMonitor.hpp for doc. SWItrdMonitor::~SWItrdMonitor() { ::lockMutex(_globalLock); // If the list of waiting threads is not NULL, we unlock them and put them // back on the free list. This way, wait() will return with an error rather // than block indefinitely. if (_firstWaitingThread != NULL) { notifyAllHandles(); } if (_policy == POOLED) { // release the mutex if we have one, and put it back on the free list. if (_mutex != NULL) { ::unlockMutex(_mutex->_handle); _mutex->_next = _freeMutexList; _freeMutexList = _mutex; _mutex = NULL; } ::unlockMutex(_globalLock); } else { ::unlockMutex(_globalLock); ::deleteMutex(_mutex->_handle); delete _mutex; } } // lock // Refer to SWItrdMonitor.hpp for doc. int SWItrdMonitor::lock() { // body VXIthreadID threadId = VXItrdThreadGetID(); if (threadId == _ownerThread) { _lockCount++; return SUCCESS; } int rc = SUCCESS; if (_policy == POOLED) { if (::lockMutex(_globalLock) != SUCCESS) return FAILURE; bool newMutex = false; if (_mutex == NULL) { if (_freeMutexList == NULL) { _mutex = new HandleListItem; // We don't initialize the other fields as we don't really care _mutex->_handle = ::createMutex(true); newMutex = true; if (_mutex->_handle == NULL) { delete _mutex; _mutex = NULL; } } else { // Take a mutex from the free list. This actually is a stack of mutex // as it is. I don't think it causes a problem anyway. _mutex = _freeMutexList; _freeMutexList = _freeMutexList->_next; } _mutex->_count = 1; } else { _mutex->_count++; } rc = ::unlockMutex(_globalLock); if (rc != SUCCESS || _mutex == NULL) { return FAILURE; } if (!newMutex) { rc = ::lockMutex(_mutex->_handle); } } else { rc = ::lockMutex(_mutex->_handle); } if (rc == SUCCESS) { _ownerThread = threadId; _lockCount = 1; } return rc; } // unlock // Refer to SWItrdMonitor.hpp for doc. int SWItrdMonitor::unlock() { VXIthreadID threadId = VXItrdThreadGetID(); if (threadId != _ownerThread) { return NOT_OWNER; } int rc = SUCCESS; if (_policy == POOLED) { ::lockMutex(_globalLock); if (--_lockCount == 0) { _ownerThread = (VXIthreadID) -1; rc = ::unlockMutex(_mutex->_handle); if (--_mutex->_count == 0) { _mutex->_next = _freeMutexList; _freeMutexList = _mutex; _mutex = NULL; } } ::unlockMutex(_globalLock); } else { if (--_lockCount == 0) { _ownerThread = (VXIthreadID) -1; rc = ::unlockMutex(_mutex->_handle); } } return rc; } // wait // Refer to SWItrdMonitor.hpp for doc. int SWItrdMonitor::wait() { return wait(INFINITE,NULL); } // wait // Refer to SWItrdMonitor.hpp for doc. int SWItrdMonitor::wait(unsigned long millisecs, bool *expiredF) { // body VXIthreadID threadId = VXItrdThreadGetID(); if (threadId != _ownerThread) { return NOT_OWNER; } int count = _lockCount; _ownerThread = (VXIthreadID) -1; _lockCount = 0; HandleListItem *listItem = getHandle(); int rc = waitForEvent(_mutex->_handle, listItem->_handle, millisecs, expiredF); resetHandle(listItem); if (rc == SUCCESS) { _ownerThread = threadId; _lockCount = count; } return rc; } // notify // Refer to SWItrdMonitor.hpp for doc. int SWItrdMonitor::notify() { // body VXIthreadID threadId = VXItrdThreadGetID(); if (threadId != _ownerThread) { return NOT_OWNER; } int rc = SUCCESS; ::lockMutex(_globalLock); if (_firstWaitingThread != NULL) { #ifdef _WIN32 rc = ::notifyEvent(_firstWaitingThread->_handle, false); // Remove the handle from the waiting threads list. HandleListItem *tmp = _firstWaitingThread; _firstWaitingThread = _firstWaitingThread->_next; tmp->_next = NULL; if (_firstWaitingThread == NULL) _lastWaitingThread = NULL; else _firstWaitingThread->_prev = NULL; #else rc = ::notifyEvent(_firstWaitingThread->_handle, false); #endif } ::unlockMutex(_globalLock); return rc; } // notifyAll // Refer to SWItrdMonitor.hpp for doc. int SWItrdMonitor::notifyAll() { // body VXIthreadID threadId = VXItrdThreadGetID(); if (threadId != _ownerThread) { return NOT_OWNER; } ::lockMutex(_globalLock); int rc = notifyAllHandles(); ::unlockMutex(_globalLock); return rc; } int SWItrdMonitor::notifyAllHandles() { int rc = SUCCESS; #ifdef _WIN32 while (_firstWaitingThread != NULL) { HandleListItem *tmp = _firstWaitingThread; _firstWaitingThread = _firstWaitingThread->_next; tmp->_next = tmp->_prev = NULL; if (notifyEvent(tmp->_handle, true) != SUCCESS) rc = FAILURE; } _lastWaitingThread = NULL; #else if (_firstWaitingThread != NULL) { rc = notifyEvent(_firstWaitingThread->_handle, true); } #endif return rc; } #ifdef _WIN32 SWItrdMonitor::HandleListItem *SWItrdMonitor::getHandle() { HandleListItem *handle = NULL; ::lockMutex(_globalLock); if (_freeThreadList == NULL) { handle = new HandleListItem; // No need to initialize _owner, _next and _prev at this point. They are // initialized below. HANDLE *k = new HANDLE; *k = CreateEvent(NULL, FALSE, FALSE, NULL); handle->_handle = k; } else { // Take the first NT event in the free list and make sure it is reset // Altough it should be. handle = _freeThreadList; _freeThreadList = handle->_next; ResetEvent(*(static_cast<HANDLE *>(handle->_handle))); } // Insert in list of pending notifications. if (_lastWaitingThread == NULL) { // empty list. _lastWaitingThread = _firstWaitingThread = handle; handle->_prev = handle->_next = NULL; } else { // add to the end of the list _lastWaitingThread->_next = handle; handle->_prev = _lastWaitingThread; handle->_next = NULL; _lastWaitingThread = handle; } ::unlockMutex(_globalLock); return handle; } void SWItrdMonitor::resetHandle(HandleListItem *handle) { ::lockMutex(_globalLock); ResetEvent(*(static_cast<HANDLE *>(handle->_handle))); // Remove from the pending list. if (handle == _firstWaitingThread) { // The handle is the first one on the pending list. _firstWaitingThread = handle->_next; if (handle == _lastWaitingThread) _lastWaitingThread = NULL; } else if (handle == _lastWaitingThread) { // The handle is the last one on the pending list, but not the first. _lastWaitingThread = handle->_prev; _lastWaitingThread->_next = NULL; } else if (handle->_prev != NULL && handle->_next != NULL) { // The handle is neither the first one, nor the last one. handle->_prev->_next = handle->_next; handle->_next->_prev = handle->_prev; } // Now put back in the free list handle->_next = _freeThreadList; handle->_prev = NULL; _freeThreadList = handle; ::unlockMutex(_globalLock); } #else SWItrdMonitor::HandleListItem *SWItrdMonitor::getHandle() { HandleListItem *handle = NULL; ::lockMutex(_globalLock); if (_firstWaitingThread != NULL) { handle = _firstWaitingThread; handle->_count++; } else { if (_freeThreadList == NULL) { handle = new HandleListItem; // No need to initialize _owner, _next and _prev at this point. They are // initialized below. pthread_cond_t *p = new pthread_cond_t; pthread_cond_init(p, NULL); handle->_handle = p; } else { // Take the first event in the free list. // Altough it should be. handle = _freeThreadList; _freeThreadList = handle->_next; } _lastWaitingThread = _firstWaitingThread = handle; handle->_prev = handle->_next = NULL; handle->_count = 1; } ::unlockMutex(_globalLock); return handle; } void SWItrdMonitor::resetHandle(HandleListItem *handle) { ::lockMutex(_globalLock); // Remove from the pending list if not already removed. if (--handle->_count == 0) { _firstWaitingThread = _lastWaitingThread = NULL; // Now put back in the free list handle->_next = _freeThreadList; handle->_prev = NULL; _freeThreadList = handle; } ::unlockMutex(_globalLock); } #endif // _WIN32
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -