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