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

private_threading.h

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