18 #ifndef LIBCWD_PRIVATE_THREADING_H
19 #define LIBCWD_PRIVATE_THREADING_H
21 #define LIBCWD_DEBUGDEBUGRWLOCK 0
23 #if LIBCWD_DEBUGDEBUGRWLOCK
24 #define LIBCWD_NO_INTERNAL_STRING
25 #include <raw_write.h>
26 #undef LIBCWD_NO_INTERNAL_STRING
27 extern pthread_mutex_t LIBCWD_DEBUGDEBUGLOCK_CERR_mutex;
28 extern unsigned int LIBCWD_DEBUGDEBUGLOCK_CERR_count;
29 #define LIBCWD_DEBUGDEBUGRWLOCK_CERR(x) \
31 pthread_mutex_lock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
32 FATALDEBUGDEBUG_CERR(x); \
33 pthread_mutex_unlock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
35 #define LIBCWD_DEBUGDEBUGLOCK_CERR(x) \
37 if (instance != static_tsd_instance) \
39 pthread_mutex_lock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
40 ++LIBCWD_DEBUGDEBUGLOCK_CERR_count; \
41 FATALDEBUGDEBUG_CERR("[" << LIBCWD_DEBUGDEBUGLOCK_CERR_count << "] " << pthread_self() << ": " << x); \
42 pthread_mutex_unlock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
45 #else // !LIBCWD_DEBUGDEBUGRWLOCK
46 #define LIBCWD_DEBUGDEBUGRWLOCK_CERR(x) do { } while(0)
47 #define LIBCWD_DEBUGDEBUGLOCK_CERR(x) do { } while(0)
48 #endif // !LIBCWD_DEBUGDEBUGRWLOCK
50 #ifndef LIBCWD_PRIVATE_SET_ALLOC_CHECKING_H
53 #ifndef LIBCWD_PRIVATE_STRUCT_TSD_H
56 #ifndef LIBCWD_PRIVATE_MUTEX_INSTANCES_H
59 #ifndef LIBCWD_CORE_DUMP_H
67 #ifdef LIBCWD_HAVE_PTHREAD
70 #error "You need to use define _GNU_SOURCE in order to make use of the extensions of Linux Threads."
73 #ifndef LIBCW_PTHREAD_H
74 #define LIBCW_PTHREAD_H
77 #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP)
78 #define LIBCWD_USE_LINUXTHREADS 1
80 #define LIBCWD_USE_POSIX_THREADS 1
83 #if LIBCWD_THREAD_SAFE
84 #error Fatal error: thread support was not detected during configuration of libcwd (did you use --disable-threading?)! \
85 How come you are trying to compile a threaded program now? \
86 To fix this problem, either link with libcwd_r (install it), or when you are indeed compiling a \
87 single threaded application, then get rid of the -D_REENTRANT and/or -D_THREAD_SAFE in your compile flags.
89 #endif // LIBCWD_HAVE_PTHREAD
91 #ifndef LIBCWD_USE_LINUXTHREADS
92 #define LIBCWD_USE_LINUXTHREADS 0
94 #ifndef LIBCWD_USE_POSIX_THREADS
95 #define LIBCWD_USE_POSIX_THREADS 0
99 #define LibcwDebugThreads(x) do { x; } while(0)
101 #define LibcwDebugThreads(x) do { } while(0)
104 #if CWDEBUG_DEBUGT || CWDEBUG_DEBUG
105 #ifndef LIBCWD_PRIVATE_ASSERT_H
110 #if LIBCWD_THREAD_SAFE
114 #if LIBCWD_DEBUGDEBUGRWLOCK
116 _private_::raw_write_nt
const&
117 operator<<(_private_::raw_write_nt
const& raw_write, pthread_mutex_t
const& mutex)
119 raw_write <<
"(pthread_mutex_t&)" << (
void*)&mutex <<
120 " = { __m_reserved = " << mutex.__m_reserved <<
121 ", __m_count = " << mutex.__m_count <<
122 ", __m_owner = " << (
void*)mutex.__m_owner <<
123 ", __m_kind = " << mutex.__m_kind <<
124 ", __m_lock = { __status = " << mutex.__m_lock.__status <<
125 ", __spinlock = " << mutex.__m_lock.__spinlock <<
" } }";
130 namespace _private_ {
132 extern void initialize_global_mutexes(
void);
133 extern bool WST_multi_threaded;
136 extern void test_for_deadlock(
size_t,
struct TSD_st&,
void const*);
137 inline void test_for_deadlock(
int instance,
struct TSD_st& __libcwd_tsd,
void const* from)
139 assert(instance < 0x10000);
140 test_for_deadlock(static_cast<size_t>(instance), __libcwd_tsd, from);
142 inline void test_for_deadlock(
void const* ptr,
struct TSD_st& __libcwd_tsd,
void const* from)
144 assert(reinterpret_cast<size_t>(ptr) >= 0x10000);
145 test_for_deadlock(reinterpret_cast<size_t>(ptr), __libcwd_tsd, from);
170 #if LIBCWD_USE_POSIX_THREADS || LIBCWD_USE_LINUXTHREADS
173 #define LIBCWD_DISABLE_CANCEL \
175 LIBCWD_DISABLE_CANCEL_NO_BRACE
176 #define LIBCWD_DISABLE_CANCEL_NO_BRACE \
177 int __libcwd_oldstate; \
178 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &__libcwd_oldstate); \
179 LibcwDebugThreads( ++__libcwd_tsd.cancel_explicitely_disabled )
181 #define LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE \
186 LIBCWD_ASSERT( !__libcwd_tsd.internal || __libcwd_tsd.cancel_explicitely_disabled || __libcwd_tsd.cancel_explicitely_deferred )
188 #define LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE
190 #define LIBCWD_ENABLE_CANCEL_NO_BRACE \
192 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_disabled > 0 ); \
193 --__libcwd_tsd.cancel_explicitely_disabled; \
194 LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE; \
196 pthread_setcancelstate(__libcwd_oldstate, NULL)
197 #define LIBCWD_ENABLE_CANCEL \
198 LIBCWD_ENABLE_CANCEL_NO_BRACE; \
201 #define LIBCWD_DEFER_CANCEL \
203 LIBCWD_DEFER_CANCEL_NO_BRACE
204 #define LIBCWD_DEFER_CANCEL_NO_BRACE \
205 int __libcwd_oldtype; \
206 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &__libcwd_oldtype); \
207 LibcwDebugThreads( ++__libcwd_tsd.cancel_explicitely_deferred )
208 #define LIBCWD_RESTORE_CANCEL_NO_BRACE \
210 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred > 0 ); \
211 --__libcwd_tsd.cancel_explicitely_deferred; \
212 LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE; \
214 pthread_setcanceltype(__libcwd_oldtype, NULL)
215 #define LIBCWD_RESTORE_CANCEL \
216 LIBCWD_RESTORE_CANCEL_NO_BRACE; \
219 #if LIBCWD_USE_LINUXTHREADS
220 #define LIBCWD_DEFER_CLEANUP_PUSH(routine, arg) \
221 pthread_cleanup_push_defer_np(reinterpret_cast<void(*)(void*)>(routine), reinterpret_cast<void*>(arg)); \
222 LibcwDebugThreads( ++__libcwd_tsd.cancel_explicitely_deferred; ++__libcwd_tsd.cleanup_handler_installed )
224 #define LIBCWD_ASSERT_NONINTERNAL LIBCWD_ASSERT( !__libcwd_tsd.internal )
226 #define LIBCWD_ASSERT_NONINTERNAL
228 #define LIBCWD_CLEANUP_POP_RESTORE(execute) \
229 LibcwDebugThreads( --__libcwd_tsd.cleanup_handler_installed; \
230 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred > 0 ); \
231 LIBCWD_ASSERT_NONINTERNAL; ); \
232 pthread_cleanup_pop_restore_np(static_cast<int>(execute)); \
233 LibcwDebugThreads( --__libcwd_tsd.cancel_explicitely_deferred; )
234 #else // !LIBCWD_USE_LINUXTHREADS
235 #define LIBCWD_DEFER_CLEANUP_PUSH(routine, arg) \
236 LIBCWD_DEFER_CANCEL; \
237 LibcwDebugThreads( ++__libcwd_tsd.cleanup_handler_installed ); \
238 pthread_cleanup_push(reinterpret_cast<void(*)(void*)>(routine), reinterpret_cast<void*>(arg))
239 #define LIBCWD_CLEANUP_POP_RESTORE(execute) \
240 LibcwDebugThreads( --__libcwd_tsd.cleanup_handler_installed ); \
241 pthread_cleanup_pop(static_cast<int>(execute)); \
242 LIBCWD_RESTORE_CANCEL
243 #endif // !LIBCWD_USE_LINUXTHREADS
245 #define LIBCWD_PUSH_DEFER_TRYLOCK_MUTEX(instance, unlock_routine) \
246 LIBCWD_DEFER_CLEANUP_PUSH(static_cast<void (*)(void)>(unlock_routine), &::libcwd::_private_::mutex_tct<(instance)>::S_mutex); \
247 bool __libcwd_lock_successful = ::libcwd::_private_::mutex_tct<(instance)>::trylock()
248 #define LIBCWD_DEFER_PUSH_LOCKMUTEX(instance, unlock_routine) \
249 LIBCWD_DEFER_CLEANUP_PUSH(static_cast<void (*)(void)>(unlock_routine), &::libcwd::_private_::mutex_tct<(instance)>::S_mutex); \
250 ::libcwd::_private_::mutex_tct<(instance)>::lock(); \
251 bool const __libcwd_lock_successful = true
252 #define LIBCWD_UNLOCKMUTEX_POP_RESTORE(instance) \
253 LIBCWD_CLEANUP_POP_RESTORE(__libcwd_lock_successful)
255 #define LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED \
257 if (instance != static_tsd_instance) \
262 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred || __libcwd_tsd.cancel_explicitely_disabled ); \
265 template <
int instance>
268 static pthread_mutex_t S_mutex;
269 #if !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
271 static bool volatile S_initialized;
272 static void S_initialize(
void);
275 static void initialize(
void)
276 #if LIBCWD_USE_LINUXTHREADS && !CWDEBUG_DEBUGT
287 static bool trylock(
void)
289 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
291 LIBCWD_TSD_DECLARATION;
293 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
294 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Trying to lock mutex " << instance <<
" (" << (
void*)&S_mutex <<
") from " << __builtin_return_address(0) <<
" from " << __builtin_return_address(1));
295 LIBCWD_DEBUGDEBUGLOCK_CERR(
"pthread_mutex_trylock(" << S_mutex <<
").");
296 bool success = (pthread_mutex_trylock(&S_mutex) == 0);
297 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Result = " << success <<
". Mutex now " << S_mutex <<
".");
298 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
302 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
304 LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex_tct::trylock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; incrementing it.");
305 instance_locked[instance] += 1;
307 locked_by[instance] = pthread_self();
308 locked_from[instance] = __builtin_return_address(0);
312 LibcwDebugThreads(
if (success) { ++__libcwd_tsd.inside_critical_area; } );
315 static void lock(
void)
317 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
320 if (instance != static_tsd_instance)
322 LIBCWD_TSD_DECLARATION;
323 tsd_ptr = &__libcwd_tsd;
325 TSD_st& __libcwd_tsd(*tsd_ptr);
327 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
328 LibcwDebugThreads(
if (instance != static_tsd_instance) { ++__libcwd_tsd.inside_critical_area; } );
329 LIBCWD_DEBUGDEBUGLOCK_CERR(
"locking mutex " << instance <<
" (" << (
void*)&S_mutex <<
") from " << __builtin_return_address(0) <<
" from " << __builtin_return_address(1));
331 if (instance != static_tsd_instance && !(instance >= 2 * reserved_instance_low && instance < 3 * reserved_instance_low))
333 __libcwd_tsd.waiting_for_lock = instance;
334 LIBCWD_DEBUGDEBUGLOCK_CERR(
"pthread_mutex_lock(" << S_mutex <<
").");
335 int res = pthread_mutex_lock(&S_mutex);
336 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Result = " << res <<
". Mutex now " << S_mutex <<
".");
337 LIBCWD_ASSERT( res == 0 );
338 __libcwd_tsd.waiting_for_lock = 0;
339 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
343 LIBCWD_DEBUGDEBUGLOCK_CERR(
"pthread_mutex_lock(" << S_mutex <<
").");
344 int res = pthread_mutex_lock(&S_mutex);
345 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Result = " << res <<
". Mutex now " << S_mutex <<
".");
346 LIBCWD_ASSERT( res == 0 );
348 #else // !CWDEBUG_DEBUGT
349 pthread_mutex_lock(&S_mutex);
350 #endif // !CWDEBUG_DEBUGT
351 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Lock " << instance <<
" obtained (" << (
void*)&S_mutex <<
").");
352 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
353 LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex_tct::lock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; incrementing it.");
354 instance_locked[instance] += 1;
356 if (locked_by[instance] != 0 && locked_by[instance] != pthread_self())
358 LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex " << instance <<
" (" << (
void*)&S_mutex <<
") is already set by another thread (" << locked_by[instance] <<
")!");
361 locked_by[instance] = pthread_self();
362 locked_from[instance] = __builtin_return_address(0);
366 static void unlock(
void)
370 if (instance != static_tsd_instance)
372 LIBCWD_TSD_DECLARATION;
373 tsd_ptr = &__libcwd_tsd;
375 TSD_st& __libcwd_tsd(*tsd_ptr);
377 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
378 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
379 LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex_tct::unlock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; decrementing it.");
380 LIBCWD_ASSERT( instance_locked[instance] > 0 );
382 if (locked_by[instance] != pthread_self())
384 LIBCWD_DEBUGDEBUGLOCK_CERR(
"unlocking instance " << instance <<
" (" << (
void*)&S_mutex <<
") failed: locked_by[" << instance <<
"] == " << locked_by[instance] <<
".");
388 instance_locked[instance] -= 1;
390 if (instance_locked[instance] == 0)
392 locked_by[instance] = 0;
393 LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex_tct::unlock(): locked_by[" << instance <<
"] was reset.");
395 else LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex_tct::unlock(): locked_by[" << instance <<
"] was not reset, it still is " << locked_by[instance] <<
".");
398 LIBCWD_DEBUGDEBUGLOCK_CERR(
"unlocking mutex " << instance <<
" (" << (
void*)&S_mutex <<
").");
399 LIBCWD_DEBUGDEBUGLOCK_CERR(
"pthread_mutex_unlock(" << S_mutex <<
").");
403 pthread_mutex_unlock(&S_mutex);
405 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Result = " << res <<
". Mutex now " << S_mutex <<
".");
406 LIBCWD_ASSERT(res == 0);
408 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Lock " << instance <<
" released (" << (
void*)&S_mutex <<
").");
409 LibcwDebugThreads(
if (instance != static_tsd_instance) { --__libcwd_tsd.inside_critical_area; } );
412 static void cleanup(
void*);
415 #if !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
416 template <
int instance>
417 bool volatile mutex_tct<instance>::S_initialized =
false;
419 template <
int instance>
420 void mutex_tct<instance>::S_initialize(
void)
422 if (instance == mutex_initialization_instance)
424 #if !LIBCWD_USE_LINUXTHREADS
425 pthread_mutexattr_t mutex_attr;
426 pthread_mutexattr_init(&mutex_attr);
428 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
430 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
432 pthread_mutex_init(&S_mutex, &mutex_attr);
433 pthread_mutexattr_destroy(&mutex_attr);
434 #endif // !LIBCWD_USE_LINUXTHREADS
435 S_initialized =
true;
439 mutex_tct<mutex_initialization_instance>::initialize();
443 #if !LIBCWD_USE_LINUXTHREADS
444 pthread_mutexattr_t mutex_attr;
445 pthread_mutexattr_init(&mutex_attr);
446 if (instance < end_recursive_types)
447 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
451 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
453 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
456 pthread_mutex_init(&S_mutex, &mutex_attr);
457 pthread_mutexattr_destroy(&mutex_attr);
458 #endif // !LIBCWD_USE_LINUXTHREADS
459 S_initialized =
true;
464 #endif // !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
466 template <
int instance>
467 pthread_mutex_t mutex_tct<instance>::S_mutex
468 #if LIBCWD_USE_LINUXTHREADS
471 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
473 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
475 #else // !LIBCWD_USE_LINUXTHREADS
477 #endif // !LIBCWD_USE_LINUXTHREADS
479 template <
int instance>
480 void mutex_tct<instance>::cleanup(
void*)
488 template <
int instance>
489 class cond_tct :
public mutex_tct<instance> {
491 static pthread_cond_t S_condition;
492 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
493 static bool volatile S_initialized;
495 static void S_initialize(
void);
498 static void initialize(
void)
499 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
510 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
511 LIBCWD_DEBUGDEBUGLOCK_CERR(
"cond_tct::wait(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; decrementing it.");
512 LIBCWD_ASSERT( instance_locked[instance] > 0 );
514 if (locked_by[instance] != pthread_self())
516 LIBCWD_DEBUGDEBUGLOCK_CERR(
"unlocking instance " << instance <<
" (" << (
void*)&S_mutex <<
") failed: locked_by[" << instance <<
"] == " << locked_by[instance] <<
".");
520 instance_locked[instance] -= 1;
522 if (instance_locked[instance] == 0)
524 locked_by[instance] = 0;
525 LIBCWD_DEBUGDEBUGLOCK_CERR(
"cond_tct::wait(): locked_by[" << instance <<
"] was reset.");
527 else LIBCWD_DEBUGDEBUGLOCK_CERR(
"cond_tct::wait(): locked_by[" << instance <<
"] was not reset, it still is " << locked_by[instance] <<
".");
530 LIBCWD_DEBUGDEBUGLOCK_CERR(
"unlocking mutex " << instance <<
" (" << (
void*)&S_mutex <<
").");
531 LIBCWD_DEBUGDEBUGLOCK_CERR(
"pthread_cond_wait(" << (
void*)&S_condition <<
", " << this->S_mutex <<
").");
535 pthread_cond_wait(&S_condition, &this->S_mutex);
537 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Result = " << res <<
". Mutex now " << S_mutex <<
".");
538 LIBCWD_ASSERT(res == 0);
540 LIBCWD_DEBUGDEBUGLOCK_CERR(
"Lock " << instance <<
" obtained (" << (
void*)&S_mutex <<
").");
541 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
542 LIBCWD_DEBUGDEBUGLOCK_CERR(
"cond_tct::wait(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; incrementing it.");
543 instance_locked[instance] += 1;
545 if (locked_by[instance] != 0 && locked_by[instance] != pthread_self())
547 LIBCWD_DEBUGDEBUGLOCK_CERR(
"mutex " << instance <<
" (" << (
void*)&S_mutex <<
") is already set by another thread (" << locked_by[instance] <<
")!");
550 locked_by[instance] = pthread_self();
551 locked_from[instance] = __builtin_return_address(0);
555 void signal(
void) { pthread_cond_signal(&S_condition); }
556 void broadcast(
void) { pthread_cond_broadcast(&S_condition); }
559 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
560 template <
int instance>
561 void cond_tct<instance>::S_initialize(
void)
563 #if !LIBCWD_USE_LINUXTHREADS
564 mutex_tct<mutex_initialization_instance>::initialize();
565 LIBCWD_DEFER_PUSH_LOCKMUTEX(mutex_initialization_instance, mutex_tct<mutex_initialization_instance>::unlock);
568 pthread_cond_init(&S_condition, NULL);
570 LIBCWD_UNLOCKMUTEX_POP_RESTORE(mutex_initialization_instance);
572 mutex_tct<instance>::S_initialize();
574 #endif // !LIBCWD_USE_LINUXTHREADS
576 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
577 template <
int instance>
578 bool volatile cond_tct<instance>::S_initialized =
false;
581 template <
int instance>
582 pthread_cond_t cond_tct<instance>::S_condition
583 #if LIBCWD_USE_LINUXTHREADS
584 = PTHREAD_COND_INITIALIZER;
585 #else // !LIBCWD_USE_LINUXTHREADS
587 #endif // !LIBCWD_USE_LINUXTHREADS
589 #endif // LIBCWD_USE_POSIX_THREADS || LIBCWD_USE_LINUXTHREADS
614 template <
int instance>
617 static int const readers_instance = instance + reserved_instance_low;
618 static int const holders_instance = instance + 2 * reserved_instance_low;
619 typedef cond_tct<holders_instance> cond_t;
620 static cond_t S_no_holders_condition;
621 static int S_holders_count;
622 static bool volatile S_writer_is_waiting;
623 static pthread_t S_writer_id;
624 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
625 static bool S_initialized;
628 static void initialize(
void)
630 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
633 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling initialize() instance " << instance);
634 mutex_tct<readers_instance>::initialize();
635 S_no_holders_condition.initialize();
636 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving initialize() instance " << instance);
637 S_initialized =
true;
640 static bool tryrdlock(
void)
643 LIBCWD_TSD_DECLARATION;
645 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
646 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
647 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::tryrdlock()");
648 if (instance < end_recursive_types && pthread_equal(S_writer_id, pthread_self()))
650 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::tryrdlock() (skipped: thread has write lock)");
654 if (S_writer_is_waiting || !S_no_holders_condition.trylock())
656 bool success = (S_holders_count != -1);
659 S_no_holders_condition.unlock();
663 ++__libcwd_tsd.inside_critical_area;
664 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
665 __libcwd_tsd.instance_rdlocked[instance] += 1;
666 if (__libcwd_tsd.instance_rdlocked[instance] == 1)
668 __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
669 __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
671 else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
673 __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
674 __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
680 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::tryrdlock()");
683 static bool trywrlock(
void)
685 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
687 LIBCWD_TSD_DECLARATION;
689 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
690 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::trywrlock()");
692 if ((success = mutex_tct<readers_instance>::trylock()))
694 S_writer_is_waiting =
true;
695 if ((success = S_no_holders_condition.trylock()))
697 if ((success = (S_holders_count == 0)))
699 S_holders_count = -1;
700 if (instance < end_recursive_types)
701 S_writer_id = pthread_self();
702 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
704 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
706 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::trywrlock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; incrementing it.");
707 instance_locked[instance] += 1;
709 locked_by[instance] = pthread_self();
710 locked_from[instance] = __builtin_return_address(0);
714 S_no_holders_condition.unlock();
716 S_writer_is_waiting =
false;
717 mutex_tct<readers_instance>::unlock();
719 LibcwDebugThreads(
if (success) { ++__libcwd_tsd.inside_critical_area; } );
720 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::trywrlock()");
723 static void rdlock(
bool high_priority =
false)
725 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
727 LIBCWD_TSD_DECLARATION;
729 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
730 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::rdlock()");
731 if (instance < end_recursive_types && pthread_equal(S_writer_id, pthread_self()))
733 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::rdlock() (skipped: thread has write lock)");
737 if (S_writer_is_waiting)
741 mutex_tct<readers_instance>::lock();
742 mutex_tct<readers_instance>::unlock();
746 __libcwd_tsd.waiting_for_rdlock = instance;
748 S_no_holders_condition.lock();
749 while (S_holders_count == -1)
750 S_no_holders_condition.wait();
752 __libcwd_tsd.waiting_for_rdlock = 0;
755 S_no_holders_condition.unlock();
757 ++__libcwd_tsd.inside_critical_area;
770 _private_::test_for_deadlock(instance + (high_priority ? high_priority_read_lock_offset : read_lock_offset), __libcwd_tsd, __builtin_return_address(0));
771 __libcwd_tsd.instance_rdlocked[instance] += 1;
772 if (__libcwd_tsd.instance_rdlocked[instance] == 1)
774 __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
775 __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
777 else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
779 __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
780 __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
785 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::rdlock()");
787 static void rdunlock(
void)
790 LIBCWD_TSD_DECLARATION;
792 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
793 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::rdunlock()");
794 if (instance < end_recursive_types && pthread_equal(S_writer_id, pthread_self()))
796 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::rdunlock() (skipped: thread has write lock)");
799 LibcwDebugThreads( --__libcwd_tsd.inside_critical_area );
800 S_no_holders_condition.lock();
801 if (--S_holders_count == 0)
802 S_no_holders_condition.signal();
803 S_no_holders_condition.unlock();
805 if (__libcwd_tsd.instance_rdlocked[instance] == 2)
806 __libcwd_tsd.rdlocked_by2[instance] = 0;
808 __libcwd_tsd.rdlocked_by1[instance] = 0;
809 __libcwd_tsd.instance_rdlocked[instance] -= 1;
811 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::rdunlock()");
813 static void wrlock(
void)
815 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
817 LIBCWD_TSD_DECLARATION;
819 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
820 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::wrlock()");
821 mutex_tct<readers_instance>::lock();
822 S_writer_is_waiting =
true;
824 __libcwd_tsd.waiting_for_lock = instance;
826 S_no_holders_condition.lock();
827 while (S_holders_count != 0)
828 S_no_holders_condition.wait();
830 __libcwd_tsd.waiting_for_lock = 0;
832 S_writer_is_waiting =
false;
833 mutex_tct<readers_instance>::unlock();
834 S_holders_count = -1;
835 S_no_holders_condition.unlock();
836 if (instance < end_recursive_types)
837 S_writer_id = pthread_self();
838 LibcwDebugThreads( ++__libcwd_tsd.inside_critical_area );
839 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
841 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
843 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::wrlock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; incrementing it.");
844 instance_locked[instance] += 1;
846 locked_by[instance] = pthread_self();
847 locked_from[instance] = __builtin_return_address(0);
850 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::wrlock()");
852 static void wrunlock(
void)
855 LIBCWD_TSD_DECLARATION;
857 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
858 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
859 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::wrunlock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; decrementing it.");
861 LIBCWD_ASSERT( instance_locked[instance] > 0 && locked_by[instance] == pthread_self() );
863 instance_locked[instance] -= 1;
866 if (instance > end_recursive_types || instance_locked[instance] == 0)
868 locked_by[instance] = 0;
869 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::unlock(): locked_by[" << instance <<
"] was reset.");
873 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::wrunlock(): locked_by[" << instance <<
"] was not reset, it still is " << locked_by[instance] <<
".");
876 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::wrunlock()");
877 LibcwDebugThreads( --__libcwd_tsd.inside_critical_area) ;
878 if (instance < end_recursive_types)
880 S_no_holders_condition.lock();
882 S_no_holders_condition.signal();
883 S_no_holders_condition.unlock();
884 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::wrunlock()");
886 static void rd2wrlock(
void)
889 LIBCWD_TSD_DECLARATION;
891 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
892 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::rd2wrlock()");
894 __libcwd_tsd.waiting_for_lock = instance;
896 S_no_holders_condition.lock();
897 if (--S_holders_count > 0)
899 mutex_tct<readers_instance>::lock();
900 S_writer_is_waiting =
true;
901 while (S_holders_count != 0)
902 S_no_holders_condition.wait();
903 S_writer_is_waiting =
false;
904 mutex_tct<readers_instance>::unlock();
907 __libcwd_tsd.waiting_for_lock = 0;
909 S_holders_count = -1;
910 S_no_holders_condition.unlock();
911 if (instance < end_recursive_types)
912 S_writer_id = pthread_self();
913 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
915 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
917 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::rd2wrlock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; incrementing it.");
918 instance_locked[instance] += 1;
920 locked_by[instance] = pthread_self();
921 locked_from[instance] = __builtin_return_address(0);
925 if (__libcwd_tsd.instance_rdlocked[instance] == 2)
926 __libcwd_tsd.rdlocked_by2[instance] = 0;
928 __libcwd_tsd.rdlocked_by1[instance] = 0;
929 __libcwd_tsd.instance_rdlocked[instance] -= 1;
931 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::rd2wrlock()");
933 static void wr2rdlock(
void)
936 LIBCWD_TSD_DECLARATION;
938 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
939 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
940 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::wr2rdlock(): instance_locked[" << instance <<
"] == " << instance_locked[instance] <<
"; decrementing it.");
942 LIBCWD_ASSERT( instance_locked[instance] > 0 && locked_by[instance] == pthread_self() );
944 instance_locked[instance] -= 1;
946 if (instance > end_recursive_types || instance_locked[instance] == 0)
948 locked_by[instance] = 0;
949 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::wr2rdlock(): locked_by[" << instance <<
"] was reset.");
953 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": rwlock_tct::wr2rdlock(): locked_by[" << instance <<
"] was not reset, it still is " << locked_by[instance] <<
".");
957 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Calling rwlock_tct<" << instance <<
">::wr2rdlock()");
958 if (instance < end_recursive_types)
960 S_no_holders_condition.lock();
962 S_no_holders_condition.signal();
963 S_no_holders_condition.unlock();
965 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
966 if (instance >= instance_rdlocked_size)
968 __libcwd_tsd.instance_rdlocked[instance] += 1;
969 if (__libcwd_tsd.instance_rdlocked[instance] == 1)
971 __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
972 __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
974 else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
976 __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
977 __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
982 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() <<
": Leaving rwlock_tct<" << instance <<
">::wr2rdlock()");
985 static void cleanup(
void*);
988 template <
int instance>
989 int rwlock_tct<instance>::S_holders_count = 0;
991 template <
int instance>
992 bool volatile rwlock_tct<instance>::S_writer_is_waiting = 0;
994 template <
int instance>
995 pthread_t rwlock_tct<instance>::S_writer_id = 0;
997 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
998 template <
int instance>
999 bool rwlock_tct<instance>::S_initialized = 0;
1002 template <
int instance>
1003 typename rwlock_tct<instance>::cond_t rwlock_tct<instance>::S_no_holders_condition;
1005 template <
int instance>
1006 void rwlock_tct<instance>::cleanup(
void*)
1008 if (S_holders_count == -1)
1014 extern void fatal_cancellation(
void*);
1019 #else // !LIBCWD_THREAD_SAFE
1020 #define LIBCWD_DISABLE_CANCEL
1021 #define LIBCWD_DISABLE_CANCEL_NO_BRACE
1022 #define LIBCWD_ENABLE_CANCEL_NO_BRACE
1023 #define LIBCWD_ENABLE_CANCEL
1024 #define LIBCWD_DEFER_CANCEL
1025 #define LIBCWD_DEFER_CANCEL_NO_BRACE
1026 #define LIBCWD_RESTORE_CANCEL_NO_BRACE
1027 #define LIBCWD_RESTORE_CANCEL
1028 #define LIBCWD_DEFER_CLEANUP_PUSH(routine, arg)
1029 #define LIBCWD_CLEANUP_POP_RESTORE(execute)
1030 #define LIBCWD_PUSH_DEFER_TRYLOCK_MUTEX(instance, unlock_routine)
1031 #define LIBCWD_DEFER_PUSH_LOCKMUTEX(instance, unlock_routine)
1032 #define LIBCWD_UNLOCKMUTEX_POP_RESTORE(instance)
1033 #define LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED
1034 #endif // LIBCWD_THREAD_SAFE
1035 #endif // LIBCWD_PRIVATE_THREADING_H
std::ostream & operator<<(std::ostream &os, memblk_types_nt memblk_type)
Allow writing a memblk_types_nt directly to an ostream.
Definition: debugmalloc.cc:675
void core_dump(void)
Dump core of current thread.
Definition: debug.cc:805