Main Page   Reference Manual   Namespace List   Compound List   Namespace Members   Compound Members   File Members  

libcwd/private_threading.h

Go to the documentation of this file.
00001 // $Header$
00002 //
00003 // Copyright (C) 2001 - 2004, by
00004 //
00005 // Carlo Wood, Run on IRC <carlo@alinoe.com>
00006 // RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
00007 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
00008 //
00009 // This file may be distributed under the terms of the Q Public License
00010 // version 1.0 as appearing in the file LICENSE.QPL included in the
00011 // packaging of this file.
00012 // 
00013 
00018 #ifndef LIBCWD_PRIVATE_THREADING_H
00019 #define LIBCWD_PRIVATE_THREADING_H
00020 
00021 #define LIBCWD_DEBUGDEBUGRWLOCK 0
00022 
00023 #if LIBCWD_DEBUGDEBUGRWLOCK
00024 #define LIBCWD_NO_INTERNAL_STRING
00025 #include <raw_write.h>
00026 #undef LIBCWD_NO_INTERNAL_STRING
00027 extern pthread_mutex_t LIBCWD_DEBUGDEBUGLOCK_CERR_mutex;
00028 extern unsigned int LIBCWD_DEBUGDEBUGLOCK_CERR_count;
00029 #define LIBCWD_DEBUGDEBUGRWLOCK_CERR(x) \
00030         do { \
00031           pthread_mutex_lock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
00032           FATALDEBUGDEBUG_CERR(x); \
00033           pthread_mutex_unlock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
00034         } while(0)
00035 #define LIBCWD_DEBUGDEBUGLOCK_CERR(x) \
00036         do { \
00037           if (instance != static_tsd_instance) \
00038           { \
00039             pthread_mutex_lock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
00040             ++LIBCWD_DEBUGDEBUGLOCK_CERR_count; \
00041             FATALDEBUGDEBUG_CERR("[" << LIBCWD_DEBUGDEBUGLOCK_CERR_count << "] " << pthread_self() << ": " << x); \
00042             pthread_mutex_unlock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
00043           } \
00044         } while(0)
00045 #else // !LIBCWD_DEBUGDEBUGRWLOCK
00046 #define LIBCWD_DEBUGDEBUGRWLOCK_CERR(x) do { } while(0)
00047 #define LIBCWD_DEBUGDEBUGLOCK_CERR(x) do { } while(0)
00048 #endif // !LIBCWD_DEBUGDEBUGRWLOCK
00049 
00050 #ifndef LIBCWD_PRIVATE_SET_ALLOC_CHECKING_H
00051 #include <libcwd/private_set_alloc_checking.h>
00052 #endif
00053 #ifndef LIBCWD_PRIVATE_STRUCT_TSD_H
00054 #include <libcwd/private_struct_TSD.h>
00055 #endif
00056 #ifndef LIBCWD_PRIVATE_MUTEX_INSTANCES_H
00057 #include <libcwd/private_mutex_instances.h>
00058 #endif
00059 #ifndef LIBCWD_CORE_DUMP_H
00060 #include <libcwd/core_dump.h>
00061 #endif
00062 #ifndef LIBCW_CSTRING
00063 #define LIBCW_CSTRING
00064 #include <cstring>                      // Needed for std::memset and std::memcpy.
00065 #endif
00066 
00067 #ifdef LIBCWD_HAVE_PTHREAD
00068 #ifdef __linux
00069 #ifndef _GNU_SOURCE
00070 #error "You need to use define _GNU_SOURCE in order to make use of the extensions of Linux Threads."
00071 #endif
00072 #endif
00073 #ifndef LIBCW_PTHREAD_H
00074 #define LIBCW_PTHREAD_H
00075 #include <pthread.h>
00076 #endif
00077 #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP)
00078 #define LIBCWD_USE_LINUXTHREADS 1
00079 #else
00080 #define LIBCWD_USE_POSIX_THREADS 1
00081 #endif
00082 #else
00083 #if LIBCWD_THREAD_SAFE
00084 #error Fatal error: thread support was not detected during configuration of libcwd (did you use --disable-threading?)! \
00085        How come you are trying to compile a threaded program now? \
00086        To fix this problem, either link with libcwd_r (install it), or when you are indeed compiling a \
00087        single threaded application, then get rid of the -D_REENTRANT and/or -D_THREAD_SAFE in your compile flags.
00088 #endif
00089 #endif // LIBCWD_HAVE_PTHREAD
00090 
00091 #ifndef LIBCWD_USE_LINUXTHREADS
00092 #define LIBCWD_USE_LINUXTHREADS 0
00093 #endif
00094 #ifndef LIBCWD_USE_POSIX_THREADS
00095 #define LIBCWD_USE_POSIX_THREADS 0
00096 #endif
00097 
00098 #if CWDEBUG_DEBUGT
00099 #define LibcwDebugThreads(x) do { x; } while(0)
00100 #else
00101 #define LibcwDebugThreads(x) do { } while(0)
00102 #endif
00103 
00104 #if CWDEBUG_DEBUGT || CWDEBUG_DEBUG
00105 #ifndef LIBCWD_PRIVATE_ASSERT_H
00106 #include <libcwd/private_assert.h>
00107 #endif
00108 #endif
00109 
00110 #if LIBCWD_THREAD_SAFE
00111 
00112 namespace libcwd {
00113 
00114 #if LIBCWD_DEBUGDEBUGRWLOCK
00115 inline
00116 _private_::raw_write_nt const&
00117 operator<<(_private_::raw_write_nt const& raw_write, pthread_mutex_t const& mutex)
00118 {
00119   raw_write << "(pthread_mutex_t&)" << (void*)&mutex <<
00120     " = { __m_reserved = " << mutex.__m_reserved <<
00121     ", __m_count = " << mutex.__m_count <<
00122     ", __m_owner = " << (void*)mutex.__m_owner <<
00123     ", __m_kind = " << mutex.__m_kind <<
00124     ", __m_lock = { __status = " << mutex.__m_lock.__status <<
00125                  ", __spinlock = " << mutex.__m_lock.__spinlock << " } }";
00126   return raw_write;
00127 }
00128 #endif
00129 
00130   namespace _private_ {
00131 
00132 extern void initialize_global_mutexes(void);
00133 extern bool WST_multi_threaded;
00134 
00135 #if CWDEBUG_DEBUGT
00136 extern void test_for_deadlock(size_t, struct TSD_st&, void const*);
00137 inline void test_for_deadlock(int instance, struct TSD_st& __libcwd_tsd, void const* from)
00138 {
00139   assert(instance < 0x10000);
00140   test_for_deadlock(static_cast<size_t>(instance), __libcwd_tsd, from);
00141 }
00142 inline void test_for_deadlock(void const* ptr, struct TSD_st& __libcwd_tsd, void const* from)
00143 {
00144   assert(reinterpret_cast<size_t>(ptr) >= 0x10000);
00145   test_for_deadlock(reinterpret_cast<size_t>(ptr), __libcwd_tsd, from);
00146 }
00147 #endif
00148 
00149 //===================================================================================================
00150 //
00151 // Mutex locking.
00152 //
00153 // template <int instance>       This class may not use system calls (it may not call malloc(3)).
00154 //   class mutex_tct;
00155 //
00156 // Usage.
00157 //
00158 // Global mutexes can be initialized once, before using the mutex.
00159 // mutex_tct<instance_id_const>::initialize();
00160 //
00161 // Static mutexes in functions (or templates) that can not globally
00162 // be initialized need to call `initialize()' prior to *each* use
00163 // (using -O2 this is at most a single test and nothing at all when
00164 // Linuxthreads are being used.
00165 //
00166 
00167 //========================================================================================================================================17"
00168 // class mutex_tct
00169 
00170 #if LIBCWD_USE_POSIX_THREADS || LIBCWD_USE_LINUXTHREADS
00171 // We have to use macros because pthread_cleanup_push and pthread_cleanup_pop
00172 // are macros with an unmatched '{' and '}' respectively.
00173 #define LIBCWD_DISABLE_CANCEL \
00174     { \
00175       LIBCWD_DISABLE_CANCEL_NO_BRACE
00176 #define LIBCWD_DISABLE_CANCEL_NO_BRACE \
00177       int __libcwd_oldstate; \
00178       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &__libcwd_oldstate); \
00179       LibcwDebugThreads( ++__libcwd_tsd.cancel_explicitely_disabled )
00180 #if CWDEBUG_ALLOC
00181 #define LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE \
00182       /* pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) will call, */ \
00183       /* and pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) can call,   */ \
00184       /* __pthread_do_exit() when the thread is cancelled in the meantime.   */ \
00185       /* This might free allocations that are allocated in userspace.        */ \
00186       LIBCWD_ASSERT( !__libcwd_tsd.internal || __libcwd_tsd.cancel_explicitely_disabled || __libcwd_tsd.cancel_explicitely_deferred )
00187 #else
00188 #define LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE
00189 #endif
00190 #define LIBCWD_ENABLE_CANCEL_NO_BRACE \
00191       LibcwDebugThreads(\
00192         LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_disabled > 0 ); \
00193         --__libcwd_tsd.cancel_explicitely_disabled; \
00194         LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE; \
00195       ); \
00196       pthread_setcancelstate(__libcwd_oldstate, NULL)
00197 #define LIBCWD_ENABLE_CANCEL \
00198       LIBCWD_ENABLE_CANCEL_NO_BRACE; \
00199     }
00200 
00201 #define LIBCWD_DEFER_CANCEL \
00202     { \
00203       LIBCWD_DEFER_CANCEL_NO_BRACE
00204 #define LIBCWD_DEFER_CANCEL_NO_BRACE \
00205       int __libcwd_oldtype; \
00206       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &__libcwd_oldtype); \
00207       LibcwDebugThreads( ++__libcwd_tsd.cancel_explicitely_deferred )
00208 #define LIBCWD_RESTORE_CANCEL_NO_BRACE \
00209       LibcwDebugThreads(\
00210         LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred > 0 ); \
00211         --__libcwd_tsd.cancel_explicitely_deferred; \
00212         LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE; \
00213       ); \
00214       pthread_setcanceltype(__libcwd_oldtype, NULL)
00215 #define LIBCWD_RESTORE_CANCEL \
00216       LIBCWD_RESTORE_CANCEL_NO_BRACE; \
00217     }
00218 
00219 #if LIBCWD_USE_LINUXTHREADS
00220 #define LIBCWD_DEFER_CLEANUP_PUSH(routine, arg) \
00221     pthread_cleanup_push_defer_np(reinterpret_cast<void(*)(void*)>(routine), reinterpret_cast<void*>(arg)); \
00222       LibcwDebugThreads( ++__libcwd_tsd.cancel_explicitely_deferred; ++__libcwd_tsd.cleanup_handler_installed )
00223 #if CWDEBUG_ALLOC
00224 #define LIBCWD_ASSERT_NONINTERNAL LIBCWD_ASSERT( !__libcwd_tsd.internal )
00225 #else
00226 #define LIBCWD_ASSERT_NONINTERNAL
00227 #endif
00228 #define LIBCWD_CLEANUP_POP_RESTORE(execute) \
00229       LibcwDebugThreads( --__libcwd_tsd.cleanup_handler_installed; \
00230             LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred > 0 ); \
00231             LIBCWD_ASSERT_NONINTERNAL; ); \
00232       pthread_cleanup_pop_restore_np(static_cast<int>(execute)); \
00233       LibcwDebugThreads( --__libcwd_tsd.cancel_explicitely_deferred; )
00234 #else // !LIBCWD_USE_LINUXTHREADS
00235 #define LIBCWD_DEFER_CLEANUP_PUSH(routine, arg) \
00236       LIBCWD_DEFER_CANCEL; \
00237       LibcwDebugThreads( ++__libcwd_tsd.cleanup_handler_installed ); \
00238       pthread_cleanup_push(reinterpret_cast<void(*)(void*)>(routine), reinterpret_cast<void*>(arg))
00239 #define LIBCWD_CLEANUP_POP_RESTORE(execute) \
00240       LibcwDebugThreads( --__libcwd_tsd.cleanup_handler_installed ); \
00241       pthread_cleanup_pop(static_cast<int>(execute)); \
00242       LIBCWD_RESTORE_CANCEL
00243 #endif // !LIBCWD_USE_LINUXTHREADS
00244 
00245 #define LIBCWD_PUSH_DEFER_TRYLOCK_MUTEX(instance, unlock_routine) \
00246       LIBCWD_DEFER_CLEANUP_PUSH(static_cast<void (*)(void)>(unlock_routine), &::libcwd::_private_::mutex_tct<(instance)>::S_mutex); \
00247       bool __libcwd_lock_successful = ::libcwd::_private_::mutex_tct<(instance)>::trylock()
00248 #define LIBCWD_DEFER_PUSH_LOCKMUTEX(instance, unlock_routine) \
00249       LIBCWD_DEFER_CLEANUP_PUSH(static_cast<void (*)(void)>(unlock_routine), &::libcwd::_private_::mutex_tct<(instance)>::S_mutex); \
00250       ::libcwd::_private_::mutex_tct<(instance)>::lock(); \
00251       bool const __libcwd_lock_successful = true
00252 #define LIBCWD_UNLOCKMUTEX_POP_RESTORE(instance) \
00253       LIBCWD_CLEANUP_POP_RESTORE(__libcwd_lock_successful)
00254 
00255 #define LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED \
00256     LibcwDebugThreads( \
00257         if (instance != static_tsd_instance) \
00258         { \
00259           /* When entering a critical area, make sure that we have explictely deferred cancellation of this */ \
00260           /* thread (or disabled that) because when cancellation would happen in the middle of the critical */ \
00261           /* area then the lock would stay locked.                                                          */ \
00262           LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred || __libcwd_tsd.cancel_explicitely_disabled ); \
00263         } )
00264 
00265 template <int instance>
00266   class mutex_tct {
00267   public:
00268     static pthread_mutex_t S_mutex;
00269 #if !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
00270   protected:
00271     static bool volatile S_initialized;
00272     static void S_initialize(void);
00273 #endif
00274   public:
00275     static void initialize(void)
00276 #if LIBCWD_USE_LINUXTHREADS && !CWDEBUG_DEBUGT
00277         { }
00278 #else
00279         {
00280           if (S_initialized)    // Check if the static `S_mutex' already has been initialized.
00281             return;             //   No need to lock: `S_initialized' is only set after it is
00282                                 //   really initialized.
00283           S_initialize();
00284         }
00285 #endif
00286   public:
00287     static bool trylock(void)
00288     {
00289       LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
00290 #if CWDEBUG_DEBUGT
00291       LIBCWD_TSD_DECLARATION;
00292 #endif
00293       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00294       LIBCWD_DEBUGDEBUGLOCK_CERR("Trying to lock mutex " << instance << " (" << (void*)&S_mutex << ") from " << __builtin_return_address(0) << " from " << __builtin_return_address(1));
00295       LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_mutex_trylock(" << S_mutex << ").");
00296       bool success = (pthread_mutex_trylock(&S_mutex) == 0);
00297       LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << success << ". Mutex now " << S_mutex << ".");
00298 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00299       if (success)
00300       {
00301 #if CWDEBUG_DEBUGT
00302         _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00303 #endif
00304         LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::trylock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
00305         instance_locked[instance] += 1;
00306 #if CWDEBUG_DEBUGT
00307         locked_by[instance] = pthread_self();
00308         locked_from[instance] = __builtin_return_address(0);
00309 #endif
00310       }
00311 #endif
00312       LibcwDebugThreads( if (success) { ++__libcwd_tsd.inside_critical_area; } );
00313       return success;
00314     }
00315     static void lock(void)
00316     {
00317       LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
00318 #if CWDEBUG_DEBUGT
00319       TSD_st* tsd_ptr = 0;
00320       if (instance != static_tsd_instance)
00321       {
00322         LIBCWD_TSD_DECLARATION;
00323         tsd_ptr = &__libcwd_tsd;
00324       }
00325       TSD_st& __libcwd_tsd(*tsd_ptr);
00326 #endif
00327       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00328       LibcwDebugThreads( if (instance != static_tsd_instance) { ++__libcwd_tsd.inside_critical_area; } );
00329       LIBCWD_DEBUGDEBUGLOCK_CERR("locking mutex " << instance << " (" << (void*)&S_mutex << ") from " << __builtin_return_address(0) << " from " << __builtin_return_address(1));
00330 #if CWDEBUG_DEBUGT
00331       if (instance != static_tsd_instance && !(instance >= 2 * reserved_instance_low && instance < 3 * reserved_instance_low))
00332       {
00333         __libcwd_tsd.waiting_for_lock = instance;
00334         LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_mutex_lock(" << S_mutex << ").");
00335         int res = pthread_mutex_lock(&S_mutex);
00336         LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << res << ". Mutex now " << S_mutex << ".");
00337         LIBCWD_ASSERT( res == 0 );
00338         __libcwd_tsd.waiting_for_lock = 0;
00339         _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00340       }
00341       else
00342       {
00343         LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_mutex_lock(" << S_mutex << ").");
00344         int res = pthread_mutex_lock(&S_mutex);
00345         LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << res << ". Mutex now " << S_mutex << ".");
00346         LIBCWD_ASSERT( res == 0 );
00347       }
00348 #else // !CWDEBUG_DEBUGT
00349       pthread_mutex_lock(&S_mutex);
00350 #endif // !CWDEBUG_DEBUGT
00351       LIBCWD_DEBUGDEBUGLOCK_CERR("Lock " << instance << " obtained (" << (void*)&S_mutex << ").");
00352 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00353       LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::lock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
00354       instance_locked[instance] += 1;
00355 #if CWDEBUG_DEBUGT
00356       if (locked_by[instance] != 0 && locked_by[instance] != pthread_self())
00357       {
00358         LIBCWD_DEBUGDEBUGLOCK_CERR("mutex " << instance << " (" << (void*)&S_mutex << ") is already set by another thread (" << locked_by[instance] << ")!");
00359         core_dump();
00360       }
00361       locked_by[instance] = pthread_self();
00362       locked_from[instance] = __builtin_return_address(0);
00363 #endif
00364 #endif
00365     }
00366     static void unlock(void)
00367     {
00368 #if CWDEBUG_DEBUGT
00369       TSD_st* tsd_ptr = 0;
00370       if (instance != static_tsd_instance)
00371       {
00372         LIBCWD_TSD_DECLARATION;
00373         tsd_ptr = &__libcwd_tsd;
00374       }
00375       TSD_st& __libcwd_tsd(*tsd_ptr);
00376 #endif
00377       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00378 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00379       LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::unlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; decrementing it.");
00380       LIBCWD_ASSERT( instance_locked[instance] > 0 );
00381 #if CWDEBUG_DEBUGT
00382       if (locked_by[instance] != pthread_self())
00383       {
00384         LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking instance " << instance << " (" << (void*)&S_mutex << ") failed: locked_by[" << instance << "] == " << locked_by[instance] << ".");
00385         core_dump();
00386       }
00387 #endif
00388       instance_locked[instance] -= 1;
00389 #if CWDEBUG_DEBUGT
00390       if (instance_locked[instance] == 0)
00391       {
00392         locked_by[instance] = 0;
00393         LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::unlock(): locked_by[" << instance << "] was reset.");
00394       }
00395       else LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::unlock(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
00396 #endif
00397 #endif
00398       LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking mutex " << instance << " (" << (void*)&S_mutex << ").");
00399       LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_mutex_unlock(" << S_mutex << ").");
00400 #if CWDEBUG_DEBUGT
00401       int res =
00402 #endif
00403       pthread_mutex_unlock(&S_mutex);
00404 #if CWDEBUG_DEBUGT
00405       LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << res << ". Mutex now " << S_mutex << ".");
00406       LIBCWD_ASSERT(res == 0);
00407 #endif
00408       LIBCWD_DEBUGDEBUGLOCK_CERR("Lock " << instance << " released (" << (void*)&S_mutex << ").");
00409       LibcwDebugThreads( if (instance != static_tsd_instance) { --__libcwd_tsd.inside_critical_area; } );
00410     }
00411     // This is used as cleanup handler with LIBCWD_DEFER_CLEANUP_PUSH.
00412     static void cleanup(void*);
00413   };
00414 
00415 #if !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
00416 template <int instance>
00417   bool volatile mutex_tct<instance>::S_initialized = false;
00418 
00419 template <int instance>
00420   void mutex_tct<instance>::S_initialize(void)
00421   {
00422     if (instance == mutex_initialization_instance)      // Specialization.
00423     {
00424 #if !LIBCWD_USE_LINUXTHREADS
00425       pthread_mutexattr_t mutex_attr;
00426       pthread_mutexattr_init(&mutex_attr);
00427 #if CWDEBUG_DEBUGT
00428       pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
00429 #else
00430       pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
00431 #endif
00432       pthread_mutex_init(&S_mutex, &mutex_attr);
00433       pthread_mutexattr_destroy(&mutex_attr);
00434 #endif // !LIBCWD_USE_LINUXTHREADS
00435       S_initialized = true;
00436     }
00437     else                                                // General case.
00438     {
00439       mutex_tct<mutex_initialization_instance>::initialize();
00440       /* LIBCWD_DEFER_PUSH_LOCKMUTEX(mutex_initialization_instance, mutex_tct<mutex_initialization_instance>::unlock); */
00441       if (!S_initialized)                                       // Check again now that we are locked.
00442       {
00443 #if !LIBCWD_USE_LINUXTHREADS
00444         pthread_mutexattr_t mutex_attr;
00445         pthread_mutexattr_init(&mutex_attr);
00446         if (instance < end_recursive_types)
00447           pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
00448         else
00449         {
00450 #if CWDEBUG_DEBUGT
00451           pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
00452 #else
00453           pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
00454 #endif
00455         }
00456         pthread_mutex_init(&S_mutex, &mutex_attr);
00457         pthread_mutexattr_destroy(&mutex_attr);
00458 #endif // !LIBCWD_USE_LINUXTHREADS
00459         S_initialized = true;
00460       }
00461       /* LIBCWD_UNLOCKMUTEX_POP_RESTORE(mutex_initialization_instance); */
00462     }
00463   }
00464 #endif // !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
00465 
00466 template <int instance>
00467   pthread_mutex_t mutex_tct<instance>::S_mutex
00468 #if LIBCWD_USE_LINUXTHREADS
00469       =
00470 #if CWDEBUG_DEBUGT
00471         PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
00472 #else
00473         PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
00474 #endif
00475 #else // !LIBCWD_USE_LINUXTHREADS
00476       ;
00477 #endif // !LIBCWD_USE_LINUXTHREADS
00478 
00479 template <int instance>
00480   void mutex_tct<instance>::cleanup(void*)
00481   {
00482     unlock();
00483   }
00484 
00485 //========================================================================================================================================17"
00486 // class cond_tct
00487 
00488 template <int instance>
00489   class cond_tct : public mutex_tct<instance> {
00490   private:
00491     static pthread_cond_t S_condition;
00492 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00493     static bool volatile S_initialized;
00494   private:
00495     static void S_initialize(void);
00496 #endif
00497   public:
00498     static void initialize(void)
00499 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00500         {
00501           if (S_initialized)
00502             return;
00503           S_initialize();
00504         }
00505 #else
00506         { }
00507 #endif
00508   public:
00509     void wait(void) {
00510 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00511       LIBCWD_DEBUGDEBUGLOCK_CERR("cond_tct::wait(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; decrementing it.");
00512       LIBCWD_ASSERT( instance_locked[instance] > 0 );
00513 #if CWDEBUG_DEBUGT
00514       if (locked_by[instance] != pthread_self())
00515       {
00516         LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking instance " << instance << " (" << (void*)&S_mutex << ") failed: locked_by[" << instance << "] == " << locked_by[instance] << ".");
00517         core_dump();
00518       }
00519 #endif
00520       instance_locked[instance] -= 1;
00521 #if CWDEBUG_DEBUGT
00522       if (instance_locked[instance] == 0)
00523       {
00524         locked_by[instance] = 0;
00525         LIBCWD_DEBUGDEBUGLOCK_CERR("cond_tct::wait(): locked_by[" << instance << "] was reset.");
00526       }
00527       else LIBCWD_DEBUGDEBUGLOCK_CERR("cond_tct::wait(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
00528 #endif
00529 #endif
00530       LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking mutex " << instance << " (" << (void*)&S_mutex << ").");
00531       LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_cond_wait(" << (void*)&S_condition << ", " << this->S_mutex << ").");
00532 #if CWDEBUG_DEBUGT
00533       int res =
00534 #endif
00535       pthread_cond_wait(&S_condition, &this->S_mutex);
00536 #if CWDEBUG_DEBUGT
00537       LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << res << ". Mutex now " << S_mutex << ".");
00538       LIBCWD_ASSERT(res == 0);
00539 #endif
00540       LIBCWD_DEBUGDEBUGLOCK_CERR("Lock " << instance << " obtained (" << (void*)&S_mutex << ").");
00541 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00542       LIBCWD_DEBUGDEBUGLOCK_CERR("cond_tct::wait(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
00543       instance_locked[instance] += 1;
00544 #if CWDEBUG_DEBUGT
00545       if (locked_by[instance] != 0 && locked_by[instance] != pthread_self())
00546       {
00547         LIBCWD_DEBUGDEBUGLOCK_CERR("mutex " << instance << " (" << (void*)&S_mutex << ") is already set by another thread (" << locked_by[instance] << ")!");
00548         core_dump();
00549       }
00550       locked_by[instance] = pthread_self();
00551       locked_from[instance] = __builtin_return_address(0);
00552 #endif
00553 #endif
00554     }
00555     void signal(void) { pthread_cond_signal(&S_condition); }
00556     void broadcast(void) { pthread_cond_broadcast(&S_condition); }
00557   };
00558 
00559 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00560 template <int instance>
00561   void cond_tct<instance>::S_initialize(void)
00562   {
00563 #if !LIBCWD_USE_LINUXTHREADS
00564     mutex_tct<mutex_initialization_instance>::initialize();
00565     LIBCWD_DEFER_PUSH_LOCKMUTEX(mutex_initialization_instance, mutex_tct<mutex_initialization_instance>::unlock);
00566     if (!S_initialized)                                 // Check again now that we are locked.
00567     {
00568       pthread_cond_init(&S_condition, NULL);
00569     }
00570     LIBCWD_UNLOCKMUTEX_POP_RESTORE(mutex_initialization_instance);
00571 #endif
00572     mutex_tct<instance>::S_initialize();
00573   }
00574 #endif // !LIBCWD_USE_LINUXTHREADS
00575 
00576 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00577 template <int instance>
00578   bool volatile cond_tct<instance>::S_initialized = false;
00579 #endif
00580 
00581 template <int instance>
00582   pthread_cond_t cond_tct<instance>::S_condition
00583 #if LIBCWD_USE_LINUXTHREADS
00584       = PTHREAD_COND_INITIALIZER;
00585 #else // !LIBCWD_USE_LINUXTHREADS
00586       ;
00587 #endif // !LIBCWD_USE_LINUXTHREADS
00588 
00589 #endif // LIBCWD_USE_POSIX_THREADS || LIBCWD_USE_LINUXTHREADS
00590 
00591 //========================================================================================================================================17"
00592 // class rwlock_tct
00593 
00594 //
00595 // template <int instance>      This class may not use system calls (it may not call malloc(3)).
00596 //   class rwlock_tct;
00597 //
00598 // Read/write mutex lock implementation.  Readers can set arbitrary number of locks, only locking
00599 // writers.  Writers lock readers and writers.
00600 //
00601 // Examples.
00602 //
00603 // rwlock_tct<instance_id_const>::initialize();
00604 // if (rwlock_tct<instance_id_const>::tryrdlock()) ...
00605 // if (rwlock_tct<instance_id_const>::trywrlock()) ...
00606 // rwlock_tct<instance_id_const>::rdlock();             // Readers lock.
00607 // rwlock_tct<instance_id_const>::rdunlock();
00608 // rwlock_tct<instance_id_const>::wrlock();             // Writers lock.
00609 // rwlock_tct<instance_id_const>::wrunlock();
00610 // rwlock_tct<instance_id_const>::rd2wrlock();          // Convert read lock into write lock.
00611 // rwlock_tct<instance_id_const>::wr2rdlock();          // Convert write lock into read lock.
00612 //
00613 
00614 template <int instance>
00615   class rwlock_tct {
00616   private:
00617     static int const readers_instance = instance + reserved_instance_low;
00618     static int const holders_instance = instance + 2 * reserved_instance_low;
00619     typedef cond_tct<holders_instance> cond_t;
00620     static cond_t S_no_holders_condition;
00621     static int S_holders_count;                         // Number of readers or -1 if a writer locked this object.
00622     static bool volatile S_writer_is_waiting;
00623     static pthread_t S_writer_id;
00624 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00625     static bool S_initialized;                          // Set when initialized.
00626 #endif
00627   public:
00628     static void initialize(void)
00629     {
00630 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00631       if (S_initialized)
00632         return;
00633       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling initialize() instance " << instance);
00634       mutex_tct<readers_instance>::initialize();
00635       S_no_holders_condition.initialize();
00636       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving initialize() instance " << instance);
00637       S_initialized = true;
00638 #endif
00639     }
00640     static bool tryrdlock(void)
00641     {
00642 #if CWDEBUG_DEBUGT
00643       LIBCWD_TSD_DECLARATION;
00644 #endif
00645       LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
00646       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00647       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::tryrdlock()");
00648       if (instance < end_recursive_types && pthread_equal(S_writer_id, pthread_self()))
00649       {
00650         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::tryrdlock() (skipped: thread has write lock)");
00651         return true;                                            // No error checking is done.
00652       }
00653       // Give a writer a higher priority (kinda fuzzy).
00654       if (S_writer_is_waiting || !S_no_holders_condition.trylock())
00655         return false;
00656       bool success = (S_holders_count != -1);
00657       if (success)
00658         ++S_holders_count;                              // Add one reader.
00659       S_no_holders_condition.unlock();
00660       LibcwDebugThreads(
00661           if (success)
00662           {
00663             ++__libcwd_tsd.inside_critical_area;
00664             _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00665             __libcwd_tsd.instance_rdlocked[instance] += 1;
00666             if (__libcwd_tsd.instance_rdlocked[instance] == 1)
00667             {
00668               __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
00669               __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
00670             }
00671             else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
00672             {
00673               __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
00674               __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
00675             }
00676             else
00677               core_dump();
00678           }
00679       );
00680       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::tryrdlock()");
00681       return success;
00682     }
00683     static bool trywrlock(void)
00684     {
00685       LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
00686 #if CWDEBUG_DEBUGT
00687       LIBCWD_TSD_DECLARATION;
00688 #endif
00689       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00690       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::trywrlock()");
00691       bool success;
00692       if ((success = mutex_tct<readers_instance>::trylock()))
00693       {
00694         S_writer_is_waiting = true;
00695         if ((success = S_no_holders_condition.trylock()))
00696         {
00697           if ((success = (S_holders_count == 0)))
00698           {
00699             S_holders_count = -1;                                               // Mark that we have a writer.
00700             if (instance < end_recursive_types)
00701               S_writer_id = pthread_self();
00702 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00703 #if CWDEBUG_DEBUGT
00704             _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00705 #endif
00706             LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::trywrlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
00707             instance_locked[instance] += 1;
00708 #if CWDEBUG_DEBUGT
00709             locked_by[instance] = pthread_self();
00710             locked_from[instance] = __builtin_return_address(0);
00711 #endif
00712 #endif
00713           }
00714           S_no_holders_condition.unlock();
00715         }
00716         S_writer_is_waiting = false;
00717         mutex_tct<readers_instance>::unlock();
00718       }
00719       LibcwDebugThreads( if (success) { ++__libcwd_tsd.inside_critical_area; } );
00720       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::trywrlock()");
00721       return success;
00722     }
00723     static void rdlock(bool high_priority = false)
00724     {
00725       LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
00726 #if CWDEBUG_DEBUGT
00727       LIBCWD_TSD_DECLARATION;
00728 #endif
00729       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00730       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::rdlock()");
00731       if (instance < end_recursive_types && pthread_equal(S_writer_id, pthread_self()))
00732       {
00733         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdlock() (skipped: thread has write lock)");
00734         return;                                         // No error checking is done.
00735       }
00736       // Give a writer a higher priority (kinda fuzzy).
00737       if (S_writer_is_waiting)                                          // If there is a writer interested,
00738       {
00739         if (!high_priority)
00740         {
00741           mutex_tct<readers_instance>::lock();                          // then give it precedence and wait here.
00742           mutex_tct<readers_instance>::unlock();
00743         }
00744       }
00745 #if CWDEBUG_DEBUGT
00746       __libcwd_tsd.waiting_for_rdlock = instance;
00747 #endif
00748       S_no_holders_condition.lock();
00749       while (S_holders_count == -1)                     // Writer locked it?
00750         S_no_holders_condition.wait();                  // Wait for writer to finish.
00751 #if CWDEBUG_DEBUGT
00752       __libcwd_tsd.waiting_for_rdlock = 0;
00753 #endif
00754       ++S_holders_count;                                // Add one reader.
00755       S_no_holders_condition.unlock();
00756       LibcwDebugThreads(
00757           ++__libcwd_tsd.inside_critical_area;
00758           // Thread A: rdlock<1> ... mutex<2>
00759           // Thread B: mutex<2>  ... rdlock<1>
00760           //                      ^--- current program counter.
00761           // can still lead to a deadlock when a third thread is trying to get the write lock
00762           // because trying to acquire a write lock immedeately blocks new read locks.
00763           // However, trying to acquire a write lock does not block high priority read locks,
00764           // therefore the following is allowed:
00765           // Thread A: rdlock<1> ... mutex<2>
00766           // Thread B: mutex<2>  ... high priority rdlock<1>
00767           // provided that the write lock wrlock<1> is never used in combination with mutex<2>.
00768           // In order to take this into account, we need to pass the information that this is
00769           // a read lock to the test function.
00770           _private_::test_for_deadlock(instance + (high_priority ? high_priority_read_lock_offset : read_lock_offset), __libcwd_tsd, __builtin_return_address(0));
00771           __libcwd_tsd.instance_rdlocked[instance] += 1;
00772           if (__libcwd_tsd.instance_rdlocked[instance] == 1)
00773           {
00774             __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
00775             __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
00776           }
00777           else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
00778           {
00779             __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
00780             __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
00781           }
00782           else
00783             core_dump();
00784       );
00785       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdlock()");
00786     }
00787     static void rdunlock(void)
00788     {
00789 #if CWDEBUG_DEBUGT
00790       LIBCWD_TSD_DECLARATION;
00791 #endif
00792       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00793       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::rdunlock()");
00794       if (instance < end_recursive_types && pthread_equal(S_writer_id, pthread_self()))
00795       {
00796         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdunlock() (skipped: thread has write lock)");
00797         return;                                         // No error checking is done.
00798       }
00799       LibcwDebugThreads( --__libcwd_tsd.inside_critical_area );
00800       S_no_holders_condition.lock();
00801       if (--S_holders_count == 0)                       // Was this the last reader?
00802         S_no_holders_condition.signal();                // Tell waiting threads.
00803       S_no_holders_condition.unlock();
00804       LibcwDebugThreads(
00805           if (__libcwd_tsd.instance_rdlocked[instance] == 2)
00806             __libcwd_tsd.rdlocked_by2[instance] = 0;
00807           else
00808             __libcwd_tsd.rdlocked_by1[instance] = 0;
00809           __libcwd_tsd.instance_rdlocked[instance] -= 1;
00810       );
00811       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdunlock()");
00812     }
00813     static void wrlock(void)
00814     {
00815       LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
00816 #if CWDEBUG_DEBUGT
00817       LIBCWD_TSD_DECLARATION;
00818 #endif
00819       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00820       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::wrlock()");
00821       mutex_tct<readers_instance>::lock();              // Block new readers,
00822       S_writer_is_waiting = true;                       // from this moment on.
00823 #if CWDEBUG_DEBUGT
00824       __libcwd_tsd.waiting_for_lock = instance;
00825 #endif
00826       S_no_holders_condition.lock();
00827       while (S_holders_count != 0)                      // Other readers or writers have this lock?
00828         S_no_holders_condition.wait();                  // Wait until all current holders are done.
00829 #if CWDEBUG_DEBUGT
00830       __libcwd_tsd.waiting_for_lock = 0;
00831 #endif
00832       S_writer_is_waiting = false;                      // Stop checking the lock for new readers.
00833       mutex_tct<readers_instance>::unlock();            // Release blocked readers.
00834       S_holders_count = -1;                             // Mark that we have a writer.
00835       S_no_holders_condition.unlock();
00836       if (instance < end_recursive_types)
00837         S_writer_id = pthread_self();
00838       LibcwDebugThreads( ++__libcwd_tsd.inside_critical_area );
00839 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00840 #if CWDEBUG_DEBUGT
00841       _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00842 #endif
00843       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wrlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
00844       instance_locked[instance] += 1;
00845 #if CWDEBUG_DEBUGT
00846       locked_by[instance] = pthread_self();
00847       locked_from[instance] = __builtin_return_address(0);
00848 #endif
00849 #endif
00850       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::wrlock()");
00851     }
00852     static void wrunlock(void)
00853     {
00854 #if CWDEBUG_DEBUGT
00855       LIBCWD_TSD_DECLARATION;
00856 #endif
00857       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00858 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00859       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wrunlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; decrementing it.");
00860 #if CWDEBUG_DEBUGT
00861       LIBCWD_ASSERT( instance_locked[instance] > 0 && locked_by[instance] == pthread_self() );
00862 #endif
00863       instance_locked[instance] -= 1;
00864 #endif
00865 #if CWDEBUG_DEBUGT
00866       if (instance > end_recursive_types || instance_locked[instance] == 0)
00867       {
00868         locked_by[instance] = 0;
00869         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::unlock(): locked_by[" << instance << "] was reset.");
00870       }
00871       else
00872       {
00873         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wrunlock(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
00874       }
00875 #endif
00876       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::wrunlock()");
00877       LibcwDebugThreads( --__libcwd_tsd.inside_critical_area) ;
00878       if (instance < end_recursive_types)
00879         S_writer_id = 0;
00880       S_no_holders_condition.lock();
00881       S_holders_count = 0;                              // We have no writer anymore.
00882       S_no_holders_condition.signal();                  // No readers and no writers left.
00883       S_no_holders_condition.unlock();
00884       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::wrunlock()");
00885     }
00886     static void rd2wrlock(void)
00887     {
00888 #if CWDEBUG_DEBUGT
00889       LIBCWD_TSD_DECLARATION;
00890 #endif
00891       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00892       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::rd2wrlock()");
00893 #if CWDEBUG_DEBUGT
00894       __libcwd_tsd.waiting_for_lock = instance;
00895 #endif
00896       S_no_holders_condition.lock();
00897       if (--S_holders_count > 0)
00898       {
00899         mutex_tct<readers_instance>::lock();    // Block new readers.
00900         S_writer_is_waiting = true;
00901         while (S_holders_count != 0)
00902           S_no_holders_condition.wait();
00903         S_writer_is_waiting = false;
00904         mutex_tct<readers_instance>::unlock();  // Release blocked readers.
00905       }
00906 #if CWDEBUG_DEBUGT
00907       __libcwd_tsd.waiting_for_lock = 0;
00908 #endif
00909       S_holders_count = -1;                     // We are a writer now.
00910       S_no_holders_condition.unlock();
00911       if (instance < end_recursive_types)
00912         S_writer_id = pthread_self();
00913 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00914 #if CWDEBUG_DEBUGT
00915       _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00916 #endif
00917       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::rd2wrlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
00918       instance_locked[instance] += 1;
00919 #if CWDEBUG_DEBUGT
00920       locked_by[instance] = pthread_self();
00921       locked_from[instance] = __builtin_return_address(0);
00922 #endif
00923 #endif
00924       LibcwDebugThreads(
00925           if (__libcwd_tsd.instance_rdlocked[instance] == 2)
00926             __libcwd_tsd.rdlocked_by2[instance] = 0;
00927           else
00928             __libcwd_tsd.rdlocked_by1[instance] = 0;
00929           __libcwd_tsd.instance_rdlocked[instance] -= 1;
00930       );
00931       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rd2wrlock()");
00932     }
00933     static void wr2rdlock(void)
00934     {
00935 #if CWDEBUG_DEBUGT
00936       LIBCWD_TSD_DECLARATION;
00937 #endif
00938       LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
00939 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
00940       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wr2rdlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; decrementing it.");
00941 #if CWDEBUG_DEBUGT
00942       LIBCWD_ASSERT( instance_locked[instance] > 0 && locked_by[instance] == pthread_self() );
00943 #endif
00944       instance_locked[instance] -= 1;
00945 #if CWDEBUG_DEBUGT
00946       if (instance > end_recursive_types || instance_locked[instance] == 0)
00947       {
00948         locked_by[instance] = 0;
00949         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wr2rdlock(): locked_by[" << instance << "] was reset.");
00950       }
00951       else
00952       {
00953         LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wr2rdlock(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
00954       }
00955 #endif
00956 #endif
00957       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::wr2rdlock()");
00958       if (instance < end_recursive_types)
00959         S_writer_id = 0;
00960       S_no_holders_condition.lock();
00961       S_holders_count = 1;                              // Turn writer into a reader (atomic operation).
00962       S_no_holders_condition.signal();
00963       S_no_holders_condition.unlock();
00964       LibcwDebugThreads(
00965           _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
00966           if (instance >= instance_rdlocked_size)
00967             core_dump();
00968           __libcwd_tsd.instance_rdlocked[instance] += 1;
00969           if (__libcwd_tsd.instance_rdlocked[instance] == 1)
00970           {
00971             __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
00972             __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
00973           }
00974           else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
00975           {
00976             __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
00977             __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
00978           }
00979           else
00980             core_dump();
00981       );
00982       LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::wr2rdlock()");
00983     }
00984     // This is used as cleanup handler with LIBCWD_DEFER_CLEANUP_PUSH.
00985     static void cleanup(void*);
00986   };
00987 
00988 template <int instance>
00989   int rwlock_tct<instance>::S_holders_count = 0;
00990 
00991 template <int instance>
00992   bool volatile rwlock_tct<instance>::S_writer_is_waiting = 0;
00993 
00994 template <int instance>
00995   pthread_t rwlock_tct<instance>::S_writer_id = 0;
00996 
00997 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
00998 template <int instance>
00999   bool rwlock_tct<instance>::S_initialized = 0;
01000 #endif
01001 
01002 template <int instance>
01003   typename  rwlock_tct<instance>::cond_t rwlock_tct<instance>::S_no_holders_condition;
01004 
01005 template <int instance>
01006   void rwlock_tct<instance>::cleanup(void*)
01007   {
01008     if (S_holders_count == -1)
01009       wrunlock();
01010     else
01011       rdunlock();
01012   }
01013 
01014 extern void fatal_cancellation(void*);
01015 
01016   } // namespace _private_
01017 } // namespace libcwd
01018 
01019 #else // !LIBCWD_THREAD_SAFE
01020 #define LIBCWD_DISABLE_CANCEL
01021 #define LIBCWD_DISABLE_CANCEL_NO_BRACE
01022 #define LIBCWD_ENABLE_CANCEL_NO_BRACE
01023 #define LIBCWD_ENABLE_CANCEL
01024 #define LIBCWD_DEFER_CANCEL
01025 #define LIBCWD_DEFER_CANCEL_NO_BRACE
01026 #define LIBCWD_RESTORE_CANCEL_NO_BRACE
01027 #define LIBCWD_RESTORE_CANCEL
01028 #define LIBCWD_DEFER_CLEANUP_PUSH(routine, arg)
01029 #define LIBCWD_CLEANUP_POP_RESTORE(execute)
01030 #define LIBCWD_PUSH_DEFER_TRYLOCK_MUTEX(instance, unlock_routine)
01031 #define LIBCWD_DEFER_PUSH_LOCKMUTEX(instance, unlock_routine)
01032 #define LIBCWD_UNLOCKMUTEX_POP_RESTORE(instance)
01033 #define LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED
01034 #endif // LIBCWD_THREAD_SAFE
01035 #endif // LIBCWD_PRIVATE_THREADING_H
01036 
Copyright © 2001 - 2004 Carlo Wood.  All rights reserved.