1 // $Header$
2 //
3 // Copyright (C) 2001 - 2004, by
4 //
5 // Carlo Wood, Run on IRC <carlo@alinoe.com>
6 // RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
7 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
8 //
9 // This file may be distributed under the terms of the Q Public License
10 // version 1.0 as appearing in the file LICENSE.QPL included in the
11 // packaging of this file.
12 //
13
14 /** \file libcwd/private_threading.h
15 * Do not include this header file directly, instead include \ref preparation_step2 "debug.h".
16 */
17
18 #ifndef LIBCWD_PRIVATE_THREADING_H
19 #define LIBCWD_PRIVATE_THREADING_H
20
21 #define LIBCWD_DEBUGDEBUGRWLOCK 0
22
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) \
30 do { \
31 pthread_mutex_lock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
32 FATALDEBUGDEBUG_CERR(x); \
33 pthread_mutex_unlock(&LIBCWD_DEBUGDEBUGLOCK_CERR_mutex); \
34 } while(0)
35 #define LIBCWD_DEBUGDEBUGLOCK_CERR(x) \
36 do { \
37 if (instance != static_tsd_instance) \
38 { \
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); \
43 } \
44 } while(0)
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
49
50 #ifndef LIBCWD_PRIVATE_SET_ALLOC_CHECKING_H
51 #include <libcwd/private_set_alloc_checking.h>
52 #endif
53 #ifndef LIBCWD_PRIVATE_STRUCT_TSD_H
54 #include <libcwd/private_struct_TSD.h>
55 #endif
56 #ifndef LIBCWD_PRIVATE_MUTEX_INSTANCES_H
57 #include <libcwd/private_mutex_instances.h>
58 #endif
59 #ifndef LIBCWD_CORE_DUMP_H
60 #include <libcwd/core_dump.h>
61 #endif
62 #ifndef LIBCW_CSTRING
63 #define LIBCW_CSTRING
64 #include <cstring> // Needed for std::memset and std::memcpy.
65 #endif
66
67 #ifdef LIBCWD_HAVE_PTHREAD
68 #ifdef __linux
69 #ifndef _GNU_SOURCE
70 #error "You need to use define _GNU_SOURCE in order to make use of the extensions of Linux Threads."
71 #endif
72 #endif
73 #ifndef LIBCW_PTHREAD_H
74 #define LIBCW_PTHREAD_H
75 #include <pthread.h>
76 #endif
77 #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP)
78 #define LIBCWD_USE_LINUXTHREADS 1
79 #else
80 #define LIBCWD_USE_POSIX_THREADS 1
81 #endif
82 #else
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.
88 #endif
89 #endif // LIBCWD_HAVE_PTHREAD
90
91 #ifndef LIBCWD_USE_LINUXTHREADS
92 #define LIBCWD_USE_LINUXTHREADS 0
93 #endif
94 #ifndef LIBCWD_USE_POSIX_THREADS
95 #define LIBCWD_USE_POSIX_THREADS 0
96 #endif
97
98 #if CWDEBUG_DEBUGT
99 #define LibcwDebugThreads(x) do { x; } while(0)
100 #else
101 #define LibcwDebugThreads(x) do { } while(0)
102 #endif
103
104 #if CWDEBUG_DEBUGT || CWDEBUG_DEBUG
105 #ifndef LIBCWD_PRIVATE_ASSERT_H
106 #include <libcwd/private_assert.h>
107 #endif
108 #endif
109
110 #if LIBCWD_THREAD_SAFE
111
112 namespace libcwd {
113
114 #if LIBCWD_DEBUGDEBUGRWLOCK
115 inline
116 _private_::raw_write_nt const&
117 operator<<(_private_::raw_write_nt const& raw_write, pthread_mutex_t const& mutex)
118 {
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 << " } }";
126 return raw_write;
127 }
128 #endif
129
130 namespace _private_ {
131
132 extern void initialize_global_mutexes(void);
133 extern bool WST_multi_threaded;
134
135 #if CWDEBUG_DEBUGT
136 extern void test_for_deadlock(size_t, struct TSD_st&, void const*);
test_for_deadlock(int instance,struct TSD_st & __libcwd_tsd,void const * from)137 inline void test_for_deadlock(int instance, struct TSD_st& __libcwd_tsd, void const* from)
138 {
139 assert(instance < 0x10000);
140 test_for_deadlock(static_cast<size_t>(instance), __libcwd_tsd, from);
141 }
test_for_deadlock(void const * ptr,struct TSD_st & __libcwd_tsd,void const * from)142 inline void test_for_deadlock(void const* ptr, struct TSD_st& __libcwd_tsd, void const* from)
143 {
144 assert(reinterpret_cast<size_t>(ptr) >= 0x10000);
145 test_for_deadlock(reinterpret_cast<size_t>(ptr), __libcwd_tsd, from);
146 }
147 #endif
148
149 //===================================================================================================
150 //
151 // Mutex locking.
152 //
153 // template <int instance> This class may not use system calls (it may not call malloc(3)).
154 // class mutex_tct;
155 //
156 // Usage.
157 //
158 // Global mutexes can be initialized once, before using the mutex.
159 // mutex_tct<instance_id_const>::initialize();
160 //
161 // Static mutexes in functions (or templates) that can not globally
162 // be initialized need to call `initialize()' prior to *each* use
163 // (using -O2 this is at most a single test and nothing at all when
164 // Linuxthreads are being used.
165 //
166
167 //========================================================================================================================================17"
168 // class mutex_tct
169
170 #if LIBCWD_USE_POSIX_THREADS || LIBCWD_USE_LINUXTHREADS
171 // We have to use macros because pthread_cleanup_push and pthread_cleanup_pop
172 // are macros with an unmatched '{' and '}' respectively.
173 #define LIBCWD_DISABLE_CANCEL \
174 { \
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 )
180 #if CWDEBUG_ALLOC
181 #define LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE \
182 /* pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) will call, */ \
183 /* and pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) can call, */ \
184 /* __pthread_do_exit() when the thread is cancelled in the meantime. */ \
185 /* This might free allocations that are allocated in userspace. */ \
186 LIBCWD_ASSERT( !__libcwd_tsd.internal || __libcwd_tsd.cancel_explicitely_disabled || __libcwd_tsd.cancel_explicitely_deferred )
187 #else
188 #define LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE
189 #endif
190 #define LIBCWD_ENABLE_CANCEL_NO_BRACE \
191 LibcwDebugThreads(\
192 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_disabled > 0 ); \
193 --__libcwd_tsd.cancel_explicitely_disabled; \
194 LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE; \
195 ); \
196 pthread_setcancelstate(__libcwd_oldstate, NULL)
197 #define LIBCWD_ENABLE_CANCEL \
198 LIBCWD_ENABLE_CANCEL_NO_BRACE; \
199 }
200
201 #define LIBCWD_DEFER_CANCEL \
202 { \
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 \
209 LibcwDebugThreads(\
210 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred > 0 ); \
211 --__libcwd_tsd.cancel_explicitely_deferred; \
212 LIBCWD_ASSERT_USERSPACE_OR_DEFERED_BEFORE_SETCANCELSTATE; \
213 ); \
214 pthread_setcanceltype(__libcwd_oldtype, NULL)
215 #define LIBCWD_RESTORE_CANCEL \
216 LIBCWD_RESTORE_CANCEL_NO_BRACE; \
217 }
218
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 )
223 #if CWDEBUG_ALLOC
224 #define LIBCWD_ASSERT_NONINTERNAL LIBCWD_ASSERT( !__libcwd_tsd.internal )
225 #else
226 #define LIBCWD_ASSERT_NONINTERNAL
227 #endif
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
244
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)
254
255 #define LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED \
256 LibcwDebugThreads( \
257 if (instance != static_tsd_instance) \
258 { \
259 /* When entering a critical area, make sure that we have explictely deferred cancellation of this */ \
260 /* thread (or disabled that) because when cancellation would happen in the middle of the critical */ \
261 /* area then the lock would stay locked. */ \
262 LIBCWD_ASSERT( __libcwd_tsd.cancel_explicitely_deferred || __libcwd_tsd.cancel_explicitely_disabled ); \
263 } )
264
265 template <int instance>
266 class mutex_tct {
267 public:
268 static pthread_mutex_t S_mutex;
269 #if !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
270 protected:
271 static bool volatile S_initialized;
272 static void S_initialize(void);
273 #endif
274 public:
initialize(void)275 static void initialize(void)
276 #if LIBCWD_USE_LINUXTHREADS && !CWDEBUG_DEBUGT
277 { }
278 #else
279 {
280 if (S_initialized) // Check if the static `S_mutex' already has been initialized.
281 return; // No need to lock: `S_initialized' is only set after it is
282 // really initialized.
283 S_initialize();
284 }
285 #endif
286 public:
trylock(void)287 static bool trylock(void)
288 {
289 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
290 #if CWDEBUG_DEBUGT
291 LIBCWD_TSD_DECLARATION;
292 #endif
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
299 if (success)
300 {
301 #if CWDEBUG_DEBUGT
302 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
303 #endif
304 LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::trylock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
305 instance_locked[instance] += 1;
306 #if CWDEBUG_DEBUGT
307 locked_by[instance] = pthread_self();
308 locked_from[instance] = __builtin_return_address(0);
309 #endif
310 }
311 #endif
312 LibcwDebugThreads( if (success) { ++__libcwd_tsd.inside_critical_area; } );
313 return success;
314 }
lock(void)315 static void lock(void)
316 {
317 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
318 #if CWDEBUG_DEBUGT
319 TSD_st* tsd_ptr = 0;
320 if (instance != static_tsd_instance)
321 {
322 LIBCWD_TSD_DECLARATION;
323 tsd_ptr = &__libcwd_tsd;
324 }
325 TSD_st& __libcwd_tsd(*tsd_ptr);
326 #endif
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));
330 #if CWDEBUG_DEBUGT
331 if (instance != static_tsd_instance && !(instance >= 2 * reserved_instance_low && instance < 3 * reserved_instance_low))
332 {
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));
340 }
341 else
342 {
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 );
347 }
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;
355 #if CWDEBUG_DEBUGT
356 if (locked_by[instance] != 0 && locked_by[instance] != pthread_self())
357 {
358 LIBCWD_DEBUGDEBUGLOCK_CERR("mutex " << instance << " (" << (void*)&S_mutex << ") is already set by another thread (" << locked_by[instance] << ")!");
359 core_dump();
360 }
361 locked_by[instance] = pthread_self();
362 locked_from[instance] = __builtin_return_address(0);
363 #endif
364 #endif
365 }
unlock(void)366 static void unlock(void)
367 {
368 #if CWDEBUG_DEBUGT
369 TSD_st* tsd_ptr = 0;
370 if (instance != static_tsd_instance)
371 {
372 LIBCWD_TSD_DECLARATION;
373 tsd_ptr = &__libcwd_tsd;
374 }
375 TSD_st& __libcwd_tsd(*tsd_ptr);
376 #endif
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 );
381 #if CWDEBUG_DEBUGT
382 if (locked_by[instance] != pthread_self())
383 {
384 LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking instance " << instance << " (" << (void*)&S_mutex << ") failed: locked_by[" << instance << "] == " << locked_by[instance] << ".");
385 core_dump();
386 }
387 #endif
388 instance_locked[instance] -= 1;
389 #if CWDEBUG_DEBUGT
390 if (instance_locked[instance] == 0)
391 {
392 locked_by[instance] = 0;
393 LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::unlock(): locked_by[" << instance << "] was reset.");
394 }
395 else LIBCWD_DEBUGDEBUGLOCK_CERR("mutex_tct::unlock(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
396 #endif
397 #endif
398 LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking mutex " << instance << " (" << (void*)&S_mutex << ").");
399 LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_mutex_unlock(" << S_mutex << ").");
400 #if CWDEBUG_DEBUGT
401 int res =
402 #endif
403 pthread_mutex_unlock(&S_mutex);
404 #if CWDEBUG_DEBUGT
405 LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << res << ". Mutex now " << S_mutex << ".");
406 LIBCWD_ASSERT(res == 0);
407 #endif
408 LIBCWD_DEBUGDEBUGLOCK_CERR("Lock " << instance << " released (" << (void*)&S_mutex << ").");
409 LibcwDebugThreads( if (instance != static_tsd_instance) { --__libcwd_tsd.inside_critical_area; } );
410 }
411 // This is used as cleanup handler with LIBCWD_DEFER_CLEANUP_PUSH.
412 static void cleanup(void*);
413 };
414
415 #if !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
416 template <int instance>
417 bool volatile mutex_tct<instance>::S_initialized = false;
418
419 template <int instance>
S_initialize(void)420 void mutex_tct<instance>::S_initialize(void)
421 {
422 if (instance == mutex_initialization_instance) // Specialization.
423 {
424 #if !LIBCWD_USE_LINUXTHREADS
425 pthread_mutexattr_t mutex_attr;
426 pthread_mutexattr_init(&mutex_attr);
427 #if CWDEBUG_DEBUGT
428 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
429 #else
430 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
431 #endif
432 pthread_mutex_init(&S_mutex, &mutex_attr);
433 pthread_mutexattr_destroy(&mutex_attr);
434 #endif // !LIBCWD_USE_LINUXTHREADS
435 S_initialized = true;
436 }
437 else // General case.
438 {
439 mutex_tct<mutex_initialization_instance>::initialize();
440 /* LIBCWD_DEFER_PUSH_LOCKMUTEX(mutex_initialization_instance, mutex_tct<mutex_initialization_instance>::unlock); */
441 if (!S_initialized) // Check again now that we are locked.
442 {
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);
448 else
449 {
450 #if CWDEBUG_DEBUGT
451 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
452 #else
453 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL);
454 #endif
455 }
456 pthread_mutex_init(&S_mutex, &mutex_attr);
457 pthread_mutexattr_destroy(&mutex_attr);
458 #endif // !LIBCWD_USE_LINUXTHREADS
459 S_initialized = true;
460 }
461 /* LIBCWD_UNLOCKMUTEX_POP_RESTORE(mutex_initialization_instance); */
462 }
463 }
464 #endif // !LIBCWD_USE_LINUXTHREADS || CWDEBUG_DEBUGT
465
466 template <int instance>
467 pthread_mutex_t mutex_tct<instance>::S_mutex
468 #if LIBCWD_USE_LINUXTHREADS
469 =
470 #if CWDEBUG_DEBUGT
471 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
472 #else
473 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
474 #endif
475 #else // !LIBCWD_USE_LINUXTHREADS
476 ;
477 #endif // !LIBCWD_USE_LINUXTHREADS
478
479 template <int instance>
cleanup(void *)480 void mutex_tct<instance>::cleanup(void*)
481 {
482 unlock();
483 }
484
485 //========================================================================================================================================17"
486 // class cond_tct
487
488 template <int instance>
489 class cond_tct : public mutex_tct<instance> {
490 private:
491 static pthread_cond_t S_condition;
492 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
493 static bool volatile S_initialized;
494 private:
495 static void S_initialize(void);
496 #endif
497 public:
initialize(void)498 static void initialize(void)
499 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
500 {
501 if (S_initialized)
502 return;
503 S_initialize();
504 }
505 #else
506 { }
507 #endif
508 public:
wait(void)509 void wait(void) {
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 );
513 #if CWDEBUG_DEBUGT
514 if (locked_by[instance] != pthread_self())
515 {
516 LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking instance " << instance << " (" << (void*)&S_mutex << ") failed: locked_by[" << instance << "] == " << locked_by[instance] << ".");
517 core_dump();
518 }
519 #endif
520 instance_locked[instance] -= 1;
521 #if CWDEBUG_DEBUGT
522 if (instance_locked[instance] == 0)
523 {
524 locked_by[instance] = 0;
525 LIBCWD_DEBUGDEBUGLOCK_CERR("cond_tct::wait(): locked_by[" << instance << "] was reset.");
526 }
527 else LIBCWD_DEBUGDEBUGLOCK_CERR("cond_tct::wait(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
528 #endif
529 #endif
530 LIBCWD_DEBUGDEBUGLOCK_CERR("unlocking mutex " << instance << " (" << (void*)&S_mutex << ").");
531 LIBCWD_DEBUGDEBUGLOCK_CERR("pthread_cond_wait(" << (void*)&S_condition << ", " << this->S_mutex << ").");
532 #if CWDEBUG_DEBUGT
533 int res =
534 #endif
535 pthread_cond_wait(&S_condition, &this->S_mutex);
536 #if CWDEBUG_DEBUGT
537 LIBCWD_DEBUGDEBUGLOCK_CERR("Result = " << res << ". Mutex now " << S_mutex << ".");
538 LIBCWD_ASSERT(res == 0);
539 #endif
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;
544 #if CWDEBUG_DEBUGT
545 if (locked_by[instance] != 0 && locked_by[instance] != pthread_self())
546 {
547 LIBCWD_DEBUGDEBUGLOCK_CERR("mutex " << instance << " (" << (void*)&S_mutex << ") is already set by another thread (" << locked_by[instance] << ")!");
548 core_dump();
549 }
550 locked_by[instance] = pthread_self();
551 locked_from[instance] = __builtin_return_address(0);
552 #endif
553 #endif
554 }
signal(void)555 void signal(void) { pthread_cond_signal(&S_condition); }
broadcast(void)556 void broadcast(void) { pthread_cond_broadcast(&S_condition); }
557 };
558
559 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
560 template <int instance>
S_initialize(void)561 void cond_tct<instance>::S_initialize(void)
562 {
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);
566 if (!S_initialized) // Check again now that we are locked.
567 {
568 pthread_cond_init(&S_condition, NULL);
569 }
570 LIBCWD_UNLOCKMUTEX_POP_RESTORE(mutex_initialization_instance);
571 #endif
572 mutex_tct<instance>::S_initialize();
573 }
574 #endif // !LIBCWD_USE_LINUXTHREADS
575
576 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
577 template <int instance>
578 bool volatile cond_tct<instance>::S_initialized = false;
579 #endif
580
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
586 ;
587 #endif // !LIBCWD_USE_LINUXTHREADS
588
589 #endif // LIBCWD_USE_POSIX_THREADS || LIBCWD_USE_LINUXTHREADS
590
591 //========================================================================================================================================17"
592 // class rwlock_tct
593
594 //
595 // template <int instance> This class may not use system calls (it may not call malloc(3)).
596 // class rwlock_tct;
597 //
598 // Read/write mutex lock implementation. Readers can set arbitrary number of locks, only locking
599 // writers. Writers lock readers and writers.
600 //
601 // Examples.
602 //
603 // rwlock_tct<instance_id_const>::initialize();
604 // if (rwlock_tct<instance_id_const>::tryrdlock()) ...
605 // if (rwlock_tct<instance_id_const>::trywrlock()) ...
606 // rwlock_tct<instance_id_const>::rdlock(); // Readers lock.
607 // rwlock_tct<instance_id_const>::rdunlock();
608 // rwlock_tct<instance_id_const>::wrlock(); // Writers lock.
609 // rwlock_tct<instance_id_const>::wrunlock();
610 // rwlock_tct<instance_id_const>::rd2wrlock(); // Convert read lock into write lock.
611 // rwlock_tct<instance_id_const>::wr2rdlock(); // Convert write lock into read lock.
612 //
613
614 template <int instance>
615 class rwlock_tct {
616 private:
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; // Number of readers or -1 if a writer locked this object.
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; // Set when initialized.
626 #endif
627 public:
initialize(void)628 static void initialize(void)
629 {
630 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
631 if (S_initialized)
632 return;
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;
638 #endif
639 }
tryrdlock(void)640 static bool tryrdlock(void)
641 {
642 #if CWDEBUG_DEBUGT
643 LIBCWD_TSD_DECLARATION;
644 #endif
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()))
649 {
650 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::tryrdlock() (skipped: thread has write lock)");
651 return true; // No error checking is done.
652 }
653 // Give a writer a higher priority (kinda fuzzy).
654 if (S_writer_is_waiting || !S_no_holders_condition.trylock())
655 return false;
656 bool success = (S_holders_count != -1);
657 if (success)
658 ++S_holders_count; // Add one reader.
659 S_no_holders_condition.unlock();
660 LibcwDebugThreads(
661 if (success)
662 {
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)
667 {
668 __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
669 __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
670 }
671 else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
672 {
673 __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
674 __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
675 }
676 else
677 core_dump();
678 }
679 );
680 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::tryrdlock()");
681 return success;
682 }
trywrlock(void)683 static bool trywrlock(void)
684 {
685 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
686 #if CWDEBUG_DEBUGT
687 LIBCWD_TSD_DECLARATION;
688 #endif
689 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
690 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::trywrlock()");
691 bool success;
692 if ((success = mutex_tct<readers_instance>::trylock()))
693 {
694 S_writer_is_waiting = true;
695 if ((success = S_no_holders_condition.trylock()))
696 {
697 if ((success = (S_holders_count == 0)))
698 {
699 S_holders_count = -1; // Mark that we have a writer.
700 if (instance < end_recursive_types)
701 S_writer_id = pthread_self();
702 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
703 #if CWDEBUG_DEBUGT
704 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
705 #endif
706 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::trywrlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
707 instance_locked[instance] += 1;
708 #if CWDEBUG_DEBUGT
709 locked_by[instance] = pthread_self();
710 locked_from[instance] = __builtin_return_address(0);
711 #endif
712 #endif
713 }
714 S_no_holders_condition.unlock();
715 }
716 S_writer_is_waiting = false;
717 mutex_tct<readers_instance>::unlock();
718 }
719 LibcwDebugThreads( if (success) { ++__libcwd_tsd.inside_critical_area; } );
720 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::trywrlock()");
721 return success;
722 }
723 static void rdlock(bool high_priority = false)
724 {
725 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
726 #if CWDEBUG_DEBUGT
727 LIBCWD_TSD_DECLARATION;
728 #endif
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()))
732 {
733 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdlock() (skipped: thread has write lock)");
734 return; // No error checking is done.
735 }
736 // Give a writer a higher priority (kinda fuzzy).
737 if (S_writer_is_waiting) // If there is a writer interested,
738 {
739 if (!high_priority)
740 {
741 mutex_tct<readers_instance>::lock(); // then give it precedence and wait here.
742 mutex_tct<readers_instance>::unlock();
743 }
744 }
745 #if CWDEBUG_DEBUGT
746 __libcwd_tsd.waiting_for_rdlock = instance;
747 #endif
748 S_no_holders_condition.lock();
749 while (S_holders_count == -1) // Writer locked it?
750 S_no_holders_condition.wait(); // Wait for writer to finish.
751 #if CWDEBUG_DEBUGT
752 __libcwd_tsd.waiting_for_rdlock = 0;
753 #endif
754 ++S_holders_count; // Add one reader.
755 S_no_holders_condition.unlock();
756 LibcwDebugThreads(
757 ++__libcwd_tsd.inside_critical_area;
758 // Thread A: rdlock<1> ... mutex<2>
759 // Thread B: mutex<2> ... rdlock<1>
760 // ^--- current program counter.
761 // can still lead to a deadlock when a third thread is trying to get the write lock
762 // because trying to acquire a write lock immedeately blocks new read locks.
763 // However, trying to acquire a write lock does not block high priority read locks,
764 // therefore the following is allowed:
765 // Thread A: rdlock<1> ... mutex<2>
766 // Thread B: mutex<2> ... high priority rdlock<1>
767 // provided that the write lock wrlock<1> is never used in combination with mutex<2>.
768 // In order to take this into account, we need to pass the information that this is
769 // a read lock to the test function.
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)
773 {
774 __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
775 __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
776 }
777 else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
778 {
779 __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
780 __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
781 }
782 else
783 core_dump();
784 );
785 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdlock()");
786 }
rdunlock(void)787 static void rdunlock(void)
788 {
789 #if CWDEBUG_DEBUGT
790 LIBCWD_TSD_DECLARATION;
791 #endif
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()))
795 {
796 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdunlock() (skipped: thread has write lock)");
797 return; // No error checking is done.
798 }
799 LibcwDebugThreads( --__libcwd_tsd.inside_critical_area );
800 S_no_holders_condition.lock();
801 if (--S_holders_count == 0) // Was this the last reader?
802 S_no_holders_condition.signal(); // Tell waiting threads.
803 S_no_holders_condition.unlock();
804 LibcwDebugThreads(
805 if (__libcwd_tsd.instance_rdlocked[instance] == 2)
806 __libcwd_tsd.rdlocked_by2[instance] = 0;
807 else
808 __libcwd_tsd.rdlocked_by1[instance] = 0;
809 __libcwd_tsd.instance_rdlocked[instance] -= 1;
810 );
811 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rdunlock()");
812 }
wrlock(void)813 static void wrlock(void)
814 {
815 LibcwDebugThreads( LIBCWD_ASSERT( S_initialized ) );
816 #if CWDEBUG_DEBUGT
817 LIBCWD_TSD_DECLARATION;
818 #endif
819 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
820 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::wrlock()");
821 mutex_tct<readers_instance>::lock(); // Block new readers,
822 S_writer_is_waiting = true; // from this moment on.
823 #if CWDEBUG_DEBUGT
824 __libcwd_tsd.waiting_for_lock = instance;
825 #endif
826 S_no_holders_condition.lock();
827 while (S_holders_count != 0) // Other readers or writers have this lock?
828 S_no_holders_condition.wait(); // Wait until all current holders are done.
829 #if CWDEBUG_DEBUGT
830 __libcwd_tsd.waiting_for_lock = 0;
831 #endif
832 S_writer_is_waiting = false; // Stop checking the lock for new readers.
833 mutex_tct<readers_instance>::unlock(); // Release blocked readers.
834 S_holders_count = -1; // Mark that we have a writer.
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
840 #if CWDEBUG_DEBUGT
841 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
842 #endif
843 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wrlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
844 instance_locked[instance] += 1;
845 #if CWDEBUG_DEBUGT
846 locked_by[instance] = pthread_self();
847 locked_from[instance] = __builtin_return_address(0);
848 #endif
849 #endif
850 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::wrlock()");
851 }
wrunlock(void)852 static void wrunlock(void)
853 {
854 #if CWDEBUG_DEBUGT
855 LIBCWD_TSD_DECLARATION;
856 #endif
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.");
860 #if CWDEBUG_DEBUGT
861 LIBCWD_ASSERT( instance_locked[instance] > 0 && locked_by[instance] == pthread_self() );
862 #endif
863 instance_locked[instance] -= 1;
864 #endif
865 #if CWDEBUG_DEBUGT
866 if (instance > end_recursive_types || instance_locked[instance] == 0)
867 {
868 locked_by[instance] = 0;
869 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::unlock(): locked_by[" << instance << "] was reset.");
870 }
871 else
872 {
873 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wrunlock(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
874 }
875 #endif
876 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::wrunlock()");
877 LibcwDebugThreads( --__libcwd_tsd.inside_critical_area) ;
878 if (instance < end_recursive_types)
879 S_writer_id = 0;
880 S_no_holders_condition.lock();
881 S_holders_count = 0; // We have no writer anymore.
882 S_no_holders_condition.signal(); // No readers and no writers left.
883 S_no_holders_condition.unlock();
884 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::wrunlock()");
885 }
rd2wrlock(void)886 static void rd2wrlock(void)
887 {
888 #if CWDEBUG_DEBUGT
889 LIBCWD_TSD_DECLARATION;
890 #endif
891 LIBCWD_DEBUGDEBUG_ASSERT_CANCEL_DEFERRED;
892 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::rd2wrlock()");
893 #if CWDEBUG_DEBUGT
894 __libcwd_tsd.waiting_for_lock = instance;
895 #endif
896 S_no_holders_condition.lock();
897 if (--S_holders_count > 0)
898 {
899 mutex_tct<readers_instance>::lock(); // Block new readers.
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(); // Release blocked readers.
905 }
906 #if CWDEBUG_DEBUGT
907 __libcwd_tsd.waiting_for_lock = 0;
908 #endif
909 S_holders_count = -1; // We are a writer now.
910 S_no_holders_condition.unlock();
911 if (instance < end_recursive_types)
912 S_writer_id = pthread_self();
913 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
914 #if CWDEBUG_DEBUGT
915 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
916 #endif
917 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::rd2wrlock(): instance_locked[" << instance << "] == " << instance_locked[instance] << "; incrementing it.");
918 instance_locked[instance] += 1;
919 #if CWDEBUG_DEBUGT
920 locked_by[instance] = pthread_self();
921 locked_from[instance] = __builtin_return_address(0);
922 #endif
923 #endif
924 LibcwDebugThreads(
925 if (__libcwd_tsd.instance_rdlocked[instance] == 2)
926 __libcwd_tsd.rdlocked_by2[instance] = 0;
927 else
928 __libcwd_tsd.rdlocked_by1[instance] = 0;
929 __libcwd_tsd.instance_rdlocked[instance] -= 1;
930 );
931 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::rd2wrlock()");
932 }
wr2rdlock(void)933 static void wr2rdlock(void)
934 {
935 #if CWDEBUG_DEBUGT
936 LIBCWD_TSD_DECLARATION;
937 #endif
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.");
941 #if CWDEBUG_DEBUGT
942 LIBCWD_ASSERT( instance_locked[instance] > 0 && locked_by[instance] == pthread_self() );
943 #endif
944 instance_locked[instance] -= 1;
945 #if CWDEBUG_DEBUGT
946 if (instance > end_recursive_types || instance_locked[instance] == 0)
947 {
948 locked_by[instance] = 0;
949 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wr2rdlock(): locked_by[" << instance << "] was reset.");
950 }
951 else
952 {
953 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": rwlock_tct::wr2rdlock(): locked_by[" << instance << "] was not reset, it still is " << locked_by[instance] << ".");
954 }
955 #endif
956 #endif
957 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Calling rwlock_tct<" << instance << ">::wr2rdlock()");
958 if (instance < end_recursive_types)
959 S_writer_id = 0;
960 S_no_holders_condition.lock();
961 S_holders_count = 1; // Turn writer into a reader (atomic operation).
962 S_no_holders_condition.signal();
963 S_no_holders_condition.unlock();
964 LibcwDebugThreads(
965 _private_::test_for_deadlock(instance, __libcwd_tsd, __builtin_return_address(0));
966 if (instance >= instance_rdlocked_size)
967 core_dump();
968 __libcwd_tsd.instance_rdlocked[instance] += 1;
969 if (__libcwd_tsd.instance_rdlocked[instance] == 1)
970 {
971 __libcwd_tsd.rdlocked_by1[instance] = pthread_self();
972 __libcwd_tsd.rdlocked_from1[instance] = __builtin_return_address(0);
973 }
974 else if (__libcwd_tsd.instance_rdlocked[instance] == 2)
975 {
976 __libcwd_tsd.rdlocked_by2[instance] = pthread_self();
977 __libcwd_tsd.rdlocked_from2[instance] = __builtin_return_address(0);
978 }
979 else
980 core_dump();
981 );
982 LIBCWD_DEBUGDEBUGRWLOCK_CERR(pthread_self() << ": Leaving rwlock_tct<" << instance << ">::wr2rdlock()");
983 }
984 // This is used as cleanup handler with LIBCWD_DEFER_CLEANUP_PUSH.
985 static void cleanup(void*);
986 };
987
988 template <int instance>
989 int rwlock_tct<instance>::S_holders_count = 0;
990
991 template <int instance>
992 bool volatile rwlock_tct<instance>::S_writer_is_waiting = 0;
993
994 template <int instance>
995 pthread_t rwlock_tct<instance>::S_writer_id = 0;
996
997 #if CWDEBUG_DEBUGT || !LIBCWD_USE_LINUXTHREADS
998 template <int instance>
999 bool rwlock_tct<instance>::S_initialized = 0;
1000 #endif
1001
1002 template <int instance>
1003 typename rwlock_tct<instance>::cond_t rwlock_tct<instance>::S_no_holders_condition;
1004
1005 template <int instance>
cleanup(void *)1006 void rwlock_tct<instance>::cleanup(void*)
1007 {
1008 if (S_holders_count == -1)
1009 wrunlock();
1010 else
1011 rdunlock();
1012 }
1013
1014 extern void fatal_cancellation(void*);
1015
1016 } // namespace _private_
1017 } // namespace libcwd
1018
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
1036
1037