// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // Common C++. If you copy code from other releases into a copy of GNU // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // #include #include #include #include #include "private.h" #include #include #include #ifdef HAVE_GCC_CXX_BITS_ATOMIC using namespace __gnu_cxx; #endif #ifdef CCXX_NAMESPACES namespace ost { using namespace std; #endif bool Mutex::_debug = false; ThreadLock::ThreadLock() { #ifdef HAVE_PTHREAD_RWLOCK pthread_rwlockattr_t attr; pthread_rwlockattr_init(&attr); if(pthread_rwlock_init(&_lock, &attr)) { #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) throw(SyncException("Mutex constructor failure")); #endif #endif } #endif } ThreadLock::~ThreadLock() { #ifdef HAVE_PTHREAD_RWLOCK pthread_rwlock_destroy(&_lock); #endif } void ThreadLock::readLock(void) { #ifdef HAVE_PTHREAD_RWLOCK pthread_rwlock_rdlock(&_lock); #else mutex.enterMutex(); #endif } void ThreadLock::writeLock(void) { #ifdef HAVE_PTHREAD_RWLOCK pthread_rwlock_wrlock(&_lock); #else mutex.enterMutex(); #endif } void ThreadLock::unlock(void) { #ifdef HAVE_PTHREAD_RWLOCK pthread_rwlock_unlock(&_lock); #else mutex.leaveMutex(); #endif } bool ThreadLock::tryReadLock(void) { #ifdef HAVE_PTHREAD_RWLOCK if(pthread_rwlock_tryrdlock(&_lock)) return false; return true; #else return mutex.tryEnterMutex(); #endif } bool ThreadLock::tryWriteLock(void) { #ifdef HAVE_PTHREAD_RWLOCK if(pthread_rwlock_trywrlock(&_lock)) return false; return true; #else return mutex.tryEnterMutex(); #endif } #ifndef WIN32 Conditional::Conditional(const char *id) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutex_init(&_mutex, &attr); pthread_mutexattr_destroy(&attr); if(pthread_cond_init(&_cond, NULL) && Thread::getException() == Thread::throwObject) THROW(this); } Conditional::~Conditional() { pthread_cond_destroy(&_cond); pthread_mutex_destroy(&_mutex); } bool Conditional::tryEnterMutex(void) { if(pthread_mutex_trylock(&_mutex) != 0) return false; return true; } void Conditional::enterMutex(void) { pthread_mutex_lock(&_mutex); } void Conditional::leaveMutex(void) { pthread_mutex_unlock(&_mutex); } void Conditional::signal(bool broadcast) { if(broadcast) pthread_cond_broadcast(&_cond); else pthread_cond_signal(&_cond); } bool Conditional::wait(timeout_t timeout, bool locked) { struct timespec ts; int rc; if(!locked) enterMutex(); if(!timeout) { pthread_cond_wait(&_cond, &_mutex); if(!locked) leaveMutex(); return true; } getTimeout(&ts, timeout); rc = pthread_cond_timedwait(&_cond, &_mutex, &ts); if(!locked) leaveMutex(); if(rc == ETIMEDOUT) return false; return true; } #endif #ifndef WIN32 Mutex::Mutex(const char *name) { pthread_mutexattr_t _attr; pthread_mutexattr_init(&_attr); #ifdef PTHREAD_MUTEXTYPE_RECURSIVE pthread_mutexattr_settype(&_attr, PTHREAD_MUTEXTYPE_RECURSIVE); #endif pthread_mutex_init(&_mutex, &_attr); pthread_mutexattr_destroy(&_attr); #ifndef PTHREAD_MUTEXTYPE_RECURSIVE _level = 0; _tid = NULL; #endif _name = name; } Mutex::~Mutex() { pthread_mutex_destroy(&_mutex); } #ifdef PTHREAD_MUTEXTYPE_RECURSIVE bool Mutex::tryEnterMutex(void) { return (pthread_mutex_trylock(&_mutex) == 0) ? true : false; } void Mutex::enterMutex(void) { if(_debug && _name) slog.debug() << Thread::get()->getName() << ": entering " << _name << std::endl; pthread_mutex_lock(&_mutex); } void Mutex::leaveMutex(void) { pthread_mutex_unlock(&_mutex); if(_debug && _name) slog.debug() << Thread::get()->getName() << ": leaving" << _name << std::endl; } #else // !PTHREAD_MUTEXTYPE_RECURSIVE void Mutex::enterMutex(void) { if(_tid == Thread::get()) { ++_level; return; } if(_debug && _name) std::cerr << Thread::get()->getName() << ": entering" << _name << std::endl; pthread_mutex_lock(&_mutex); ++_level; _tid = Thread::get(); } void Mutex::leaveMutex(void) { if(_tid != Thread::get()) return; if(--_level > 0) return; _tid = NULL; _level = 0; pthread_mutex_unlock(&_mutex); if(_debug && _name) std::cerr << Thread::get()->getName() << ": leaving" << _name << std::endl; } bool Mutex::tryEnterMutex(void) { if(_tid == Thread::get()) { ++_level; return true; } if ( pthread_mutex_trylock(&_mutex) != 0 ) return false; _tid = Thread::get(); ++_level; return true; } #endif #else // WIN32 Mutex::Mutex(const char *name) #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX :_mutex(0) #endif // MUTEX_UNDERGROUND_WIN32_MUTEX { #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION #if _WIN32_WINNT >= 0x0403 if(!InitializeCriticalSectionAndSpinCount(&_criticalSection, 4000)) { THROW(this); } #elif _WIN32_WINNT >= 0x0400 // can rise STATUS_NO_MEMORY exception in low memory situations. InitializeCriticalSection(&_criticalSection); #else #error "Not supported Windows version" #endif #endif // MUTEX_UNDERGROUND_WIN32_CRITICALSECTION #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX _mutex = ::CreateMutex(NULL,FALSE,NULL); if(!_mutex) THROW(this); #endif // MUTEX_UNDERGROUND_WIN32_MUTEX _name = name; } void Mutex::enterMutex(void) { if(_debug && _name) slog.debug() << Thread::get()->getName() << ": entering " << _name << std::endl; #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION ::EnterCriticalSection(&_criticalSection); #endif // MUTEX_UNDERGROUND_WIN32_CRITICALSECTION #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX Thread::waitThread(_mutex, INFINITE); #endif // MUTEX_UNDERGROUND_WIN32_MUTEX } bool Mutex::tryEnterMutex(void) { #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION return (::TryEnterCriticalSection(&_criticalSection) == TRUE); #endif // MUTEX_UNDERGROUND_WIN32_CRITICALSECTION #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX return (Thread::waitThread(_mutex, 0) == WAIT_OBJECT_0); #endif // MUTEX_UNDERGROUND_WIN32_MUTEX } Mutex::~Mutex() { #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION ::DeleteCriticalSection(&_criticalSection); #endif // MUTEX_UNDERGROUND_WIN32_CRITICALSECTION #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX ::CloseHandle(_mutex); #endif // MUTEX_UNDERGROUND_WIN32_MUTEX } void Mutex::leaveMutex(void) { #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION ::LeaveCriticalSection(&_criticalSection); #endif // MUTEX_UNDERGROUND_WIN32_CRITICALSECTION #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX if (!ReleaseMutex(_mutex)) THROW(this); #endif // MUTEX_UNDERGROUND_WIN32_MUTEX if(_debug && _name) slog.debug() << Thread::get()->getName() << ": leaving" << _name << std::endl; } #endif // WIN32 MUTEX #ifdef WIN32 MutexCounter::MutexCounter(const char *id) : Mutex(id) { counter = 0; }; #endif MutexCounter::MutexCounter(int initial, const char *id) : Mutex(id) { counter = initial; } int operator++(MutexCounter &mc) { int rtn; mc.enterMutex(); rtn = mc.counter++; mc.leaveMutex(); return rtn; } // ??? why cannot be < 0 ??? int operator--(MutexCounter &mc) { int rtn = 0; mc.enterMutex(); if(mc.counter) { rtn = --mc.counter; if(!rtn) { mc.leaveMutex(); THROW(mc); } } mc.leaveMutex(); return rtn; } #ifndef CCXX_USE_WIN32_ATOMIC #ifdef HAVE_ATOMIC AtomicCounter::AtomicCounter() { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) counter = 0; #else atomic.counter = 0; #endif } AtomicCounter::AtomicCounter(int value) { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) counter = 0; #else atomic.counter = value; #endif } AtomicCounter::~AtomicCounter() {}; int AtomicCounter::operator++(void) { #ifdef HAVE_ATOMIC_AIX return fetch_and_add((atomic_p)&counter, 1); #elif defined(HAVE_GCC_BITS_ATOMIC) || defined(HAVE_GCC_CXX_BITS_ATOMIC) // Modified by JCE from 2v1.3.8 source, 30/Mar/2005 // BUG FIX: __exchange_and_add() does not seem to return updated __exchange_and_add(&counter, 1); return counter; // end modification by JCE #else atomic_inc(&atomic); return atomic_read(&atomic); #endif } int AtomicCounter::operator--(void) { #ifdef HAVE_ATOMIC_AIX return fetch_and_add((atomic_p)&counter, -1); #elif defined(HAVE_GCC_BITS_ATOMIC) || defined(HAVE_GCC_CXX_BITS_ATOMIC) // Modified by JCE from 2v1.3.8 source, 30/Mar/2005 // BUG FIX: __exchange_and_add() does not seem to return updated __exchange_and_add(&counter, -1); return counter; // end modification by JCE #else int chk = atomic_dec_and_test(&atomic); if(chk) return 0; chk = atomic_read(&atomic); if(!chk) ++chk; return chk; #endif } int AtomicCounter::operator+=(int change) { #ifdef HAVE_ATOMIC_AIX return fetch_and_add((atomic_p)&counter, change); #elif defined(HAVE_GCC_BITS_ATOMIC) || defined(HAVE_GCC_CXX_BITS_ATOMIC) // Modified by JCE from 2v1.3.8 source, 30/Mar/2005 // BUG FIX: __exchange_and_add() does not seem to return updated __exchange_and_add(&counter, change); return counter; // end modification by JCE #else atomic_add(change, &atomic); return atomic_read(&atomic); #endif } int AtomicCounter::operator-=(int change) { #ifdef HAVE_ATOMIC_AIX return fetch_and_add((atomic_p)&counter, -change); #elif defined(HAVE_GCC_BITS_ATOMIC) || defined(HAVE_GCC_CXX_BITS_ATOMIC) // Modified by JCE from 2v1.3.8 source, 30/Mar/2005 // BUG FIX: __exchange_and_add() does not seem to return updated __exchange_and_add(&counter, -change); return counter; // end modification by JCE #else atomic_sub(change, &atomic); return atomic_read(&atomic); #endif } int AtomicCounter::operator+(int change) { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) return counter + change; #else return atomic_read(&atomic) + change; #endif } int AtomicCounter::operator-(int change) { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) return counter - change; #else return atomic_read(&atomic) - change; #endif } int AtomicCounter::operator=(int value) { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) return counter = value; #else atomic_set(&atomic, value); return atomic_read(&atomic); #endif } bool AtomicCounter::operator!(void) { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) int value = counter; #else int value = atomic_read(&atomic); #endif if(value) return false; return true; } AtomicCounter::operator int() { #if defined(HAVE_ATOMIC_AIX) || defined(HAVE_GCC_BITS_ATOMIC) \ || defined(HAVE_GCC_CXX_BITS_ATOMIC) return counter; #else return atomic_read(&atomic); #endif } #else // !HAVE_ATOMIC AtomicCounter::AtomicCounter() { counter = 0; pthread_mutexattr_t _attr; pthread_mutexattr_init(&_attr); pthread_mutex_init(&_mutex, &_attr); pthread_mutexattr_destroy(&_attr); } AtomicCounter::AtomicCounter(int value) { counter = value; pthread_mutexattr_t _attr; pthread_mutexattr_init(&_attr); pthread_mutex_init(&_mutex, &_attr); pthread_mutexattr_destroy(&_attr); } AtomicCounter::~AtomicCounter() { pthread_mutex_destroy(&_mutex); } int AtomicCounter::operator++(void) { int value; pthread_mutex_lock(&_mutex); value = ++counter; pthread_mutex_unlock(&_mutex); return value; } int AtomicCounter::operator--(void) { int value; pthread_mutex_lock(&_mutex); value = --counter; pthread_mutex_unlock(&_mutex); return value; } int AtomicCounter::operator+=(int change) { int value; pthread_mutex_lock(&_mutex); counter += change; value = counter; pthread_mutex_unlock(&_mutex); return value; } int AtomicCounter::operator-=(int change) { int value; pthread_mutex_lock(&_mutex); counter -= change; value = counter; pthread_mutex_unlock(&_mutex); return value; } int AtomicCounter::operator+(int change) { int value; pthread_mutex_lock(&_mutex); value = counter + change; pthread_mutex_unlock(&_mutex); return value; } int AtomicCounter::operator-(int change) { int value; pthread_mutex_lock(&_mutex); value = counter - change; pthread_mutex_unlock(&_mutex); return value; } AtomicCounter::operator int() { int value; pthread_mutex_lock(&_mutex); value = counter; pthread_mutex_unlock(&_mutex); return value; } int AtomicCounter::operator=(int value) { int ret; pthread_mutex_lock(&_mutex); ret = counter; counter = value; pthread_mutex_unlock(&_mutex); return ret; } bool AtomicCounter::operator!(void) { int value; pthread_mutex_lock(&_mutex); value = counter; pthread_mutex_unlock(&_mutex); if(value) return false; return true; } #endif // HAVE_ATOMIC #else // WIN32 int AtomicCounter::operator+=(int change) { // FIXME: enhance with InterlockExchangeAdd while(--change>=0) InterlockedIncrement(&atomic); return atomic; } int AtomicCounter::operator-=(int change) { // FIXME: enhance with InterlockExchangeAdd while(--change>=0) InterlockedDecrement(&atomic); return atomic; } #endif // !WIN32 #ifdef CCXX_NAMESPACES } #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */