libcwd: The C++ Debugging Support Library - Reference Manual
Author: Carlo Wood
Description: C++ debugging support library with ostream debug output
Keywords: libcwd, debug output, debug facility, debug channel, object orientation, OO, C++, nested debug output, ostream, memory allocation, debugging, source file and line number

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