/** -*- C++ -*- ** ** KAI C++ Compiler ** ** Copyright (C) 1996-2001 Intel Corp. All rights reserved. ** ** Based on code from Modena Software Inc. with portions rewritten. **/ /** ** Lib++ : The Modena C++ Standard Library, ** Version 2.4, October 1997 ** ** Copyright (c) 1995-1997 Modena Software Inc. **/ #ifndef __KAI_MUTEX #define __KAI_MUTEX // This header defines several flavors of mutex: // simple_mutex: possibly non-recursive mutex // recursive_mutex: recursive mutex // static_mutex: mutex that must be initialized quite early. #include #include namespace __kai { class null_mutex { public: inline int remove() const { return 0; } inline int acquire(int = 0) const { return 0; } inline int release() const { return 0; } }; #define msipl_thread_self() pthread_self() typedef pthread_t msipl_thread_t; extern "C" long msipl_thread_unique_id( msipl_thread_t thread = msipl_thread_self() ); #if MSIPL_pthread_t_IS_CMA_struct || ( defined(__hpux) && !defined(__hpux_11) ) # define PTHREAD_ATTR_NULL cma_c_null # define MSIPL_THREAD_T_NULL cma_c_null # define __KAI_TID_T long # define __KAI_TID_NIL 0 # define __KAI_THREAD_ID msipl_thread_unique_id() #else # define PTHREAD_ATTR_NULL NULL # define MSIPL_THREAD_T_NULL 0 # define __KAI_TID_T msipl_thread_t # define __KAI_TID_NIL MSIPL_THREAD_T_NULL # define __KAI_THREAD_ID msipl_thread_self() #endif typedef pthread_mutex_t msipl_mutex_t; #ifdef PTHREAD_MUTEX_INITIALIZER # define msipl_mutex_init_val PTHREAD_MUTEX_INITIALIZER #endif #define msipl_mutex_init(m) pthread_mutex_init(m,PTHREAD_ATTR_NULL) #define msipl_mutex_destroy(m) pthread_mutex_destroy(m) #define msipl_mutex_trylock(m) pthread_mutex_trylock(m) #define msipl_mutex_lock(m) pthread_mutex_lock(m) #define msipl_mutex_unlock(m) pthread_mutex_unlock(m) enum lock_type { KAI_READ_LOCK, KAI_WRITE_LOCK }; // A simple_mutex does not necessarily allow recursive locking. class simple_mutex { protected: typedef msipl_mutex_t mutex_type; public: simple_mutex() {msipl_mutex_init(&_lock);} ~simple_mutex() {msipl_mutex_destroy(&_lock);} // These functions return 0 on success. inline int try_lock(lock_type lt = KAI_WRITE_LOCK) { return msipl_mutex_trylock(&_lock); } inline int acquire(lock_type lt = KAI_WRITE_LOCK) { return msipl_mutex_lock(&_lock); } inline int release() { return msipl_mutex_unlock(&_lock); } private: msipl_mutex_t _lock; }; #ifdef PTHREAD_MUTEX_INITIALIZER // Class simple_mutex_as_aggregate *must have same layout as class simple_mutex class simple_mutex_as_aggregate { public: msipl_mutex_t _lock; }; #define msipl_simple_mutex_init_val {PTHREAD_MUTEX_INITIALIZER} #endif /* PTHREAD_MUTEX_INITIALIZER */ // Now a mutex that will (portably) allow recursive locking. // On some platforms this could be implemented directly using pthread mutex attributes. // Unfortunately the illusion of providing separate read and write locks is completely bogus. class recursive_mutex { public: recursive_mutex() : count(0), tid(__KAI_TID_NIL) { } ~recursive_mutex() {} inline int try_lock(lock_type lt = KAI_WRITE_LOCK); inline int acquire(lock_type lt = KAI_WRITE_LOCK); inline int release() { // Can pre-emptively release locks held by other threads! if( --count ) { return 0; } else { tid = __KAI_TID_NIL; return _lock.release(); } } private: simple_mutex _lock; volatile __KAI_TID_T tid; unsigned int count; }; inline int recursive_mutex::try_lock(lock_type) { int ret; __KAI_TID_T tmpid = __KAI_THREAD_ID; if( tid==tmpid ) { ++count; ret = 0; } else if( (ret = _lock.try_lock()) == 0) { count = 1; tid = tmpid; } return ret; } inline int recursive_mutex::acquire(lock_type) { int ret; __KAI_TID_T tmpid = __KAI_THREAD_ID; if ( tid == tmpid ) { ++count; ret = 0; } else if ((ret = _lock.acquire()) == 0) { count = 1; tid = tmpid; } return ret; } // For shared static objects, we need a shared static mutex that // can be initialized early enough that other static object constructors // can use the shared objects it protects. // On older pthreads systems static_mutex::initialize() has to be // explicitly invoked pthread_once() for each static_mutex. // The parameter makes it possible to have several. // ... And we need these to be nestable. // Note that the illusion of separate READ and WRITE locks // is (once again) completely bogus... enum static_lock_id { string_static_lock_id=1, locale_static_lock_id=2, iostream_static_lock_id=3 }; template class static_mutex { static msipl_mutex_t _lock; public: # ifndef PTHREAD_MUTEX_INITIALIZER // Do not introduce a constructor or destructor (even empty ones) for this class. // Otherwise compilation of kai_thread_lib.C (in libKCC-eh-ts) fails. // Especially don't try to initialize _lock at runtime using a constructor. // Static constructor ordering is non-standard. // Use msipl_thread_once() to cause a single execution of // static_mutex::initialize() for each _before_ the first acquistion. inline void initialize() { count=0; tid=__KAI_TID_NIL; msipl_mutex_init(&_lock); } inline void finalize() { msipl_mutex_destroy(&_lock); } # endif // These functions will return 0 on success. inline int try_lock(lock_type lt = KAI_WRITE_LOCK); inline int acquire(lock_type lt = KAI_WRITE_LOCK); inline int release() { return --count ? 0 : (tid=__KAI_TID_NIL, msipl_mutex_unlock(&_lock)); } // Note that "release" can (preemptively) release locks held by other threads! private: static volatile __KAI_TID_T tid; static unsigned int count; }; #ifdef msipl_mutex_init_val template msipl_mutex_t static_mutex::_lock = msipl_mutex_init_val; #else template msipl_mutex_t static_mutex::_lock; #endif template volatile __KAI_TID_T static_mutex::tid = __KAI_TID_NIL; template unsigned int static_mutex::count = 0; template inline int static_mutex::try_lock(lock_type) { int ret; __KAI_TID_T tmpid = __KAI_THREAD_ID; if ( tid == tmpid ) { ++count; ret = 0; } else if ((ret = msipl_mutex_trylock(&_lock)) == 0) { count = 1; tid = tmpid; } return ret; } template inline int static_mutex::acquire(lock_type) { int ret; __KAI_TID_T tmpid = __KAI_THREAD_ID; if ( tid == tmpid ) { ++count; ret = 0; } else if ((ret = msipl_mutex_lock(&_lock)) == 0) { count = 1; tid = tmpid; } return ret; } template class mutex_block { MUTEX& _lock; public: // Implicit lock acquisition inline mutex_block(MUTEX& m, lock_type type=KAI_WRITE_LOCK) : _lock(m) { _lock.acquire(type); } inline mutex_block(const MUTEX& m, lock_type type=KAI_WRITE_LOCK) : _lock((MUTEX&)m) { _lock.acquire(type); } // Implicit lock release inline ~mutex_block() { _lock.release(); } // Explicit lock release inline int release() { return _lock.release(); } // Explicit lock acquisition inline int acquire(lock_type type=KAI_WRITE_LOCK) { return _lock.acquire(type); } }; template class mutex_arith { volatile TYPE _count; MUTEX _lock; public: // Initialize _count to 0. mutex_arith(){ _count=0; } // Initialize _count to i. mutex_arith(TYPE i){ _count = i; } TYPE operator++(){ mutex_block _mutex(_lock); return ++_count; } TYPE operator++(int){ mutex_block _mutex(_lock); return _count++; } TYPE operator+=(const TYPE i){ mutex_block _mutex(_lock); return _count += i; } TYPE operator--(){ mutex_block _mutex(_lock); return --_count; } TYPE operator--(int){ mutex_block _mutex(_lock); return _count--; } TYPE operator-=(const TYPE i){ mutex_block _mutex(_lock); return _count -= i; } // Compare _count with i. bool operator==(const TYPE i){ mutex_block _mutex(_lock); return _count==i; } bool operator!=(const TYPE i){ mutex_block _mutex(_lock); return _count!=i; } bool operator>=(const TYPE i){ mutex_block _mutex(_lock); return _count>=i; } bool operator<=(const TYPE i){ mutex_block _mutex(_lock); return _count<=i; } bool operator>(const TYPE i){ mutex_block _mutex(_lock); return _count>i; } bool operator<(const TYPE i){ mutex_block _mutex(_lock); return _count _mutex(_lock); _count = i; } // Return count_. operator TYPE(){ mutex_block _mutex(_lock); return _count; } }; extern recursive_mutex *error_mutex; } /*namespace __kai*/ #endif /* __KAI_MUTEX */