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_struct_TSD.h
15  * Do not include this header file directly, instead include \ref preparation_step2 "debug.h".
16  */
17 
18 #ifndef LIBCWD_PRIVATE_STRUCT_TSD_H
19 #define LIBCWD_PRIVATE_STRUCT_TSD_H
20 
21 #ifndef LIBCWD_CONFIG_H
22 #include <libcwd/config.h>
23 #endif
24 #ifndef LIBCWD_PRIVATE_ASSERT_H
25 #include <libcwd/private_assert.h>
26 #endif
27 #ifndef LIBCWD_PRIVATE_MUTEX_INSTANCES_H
28 #include <libcwd/private_mutex_instances.h>
29 #endif
30 #ifndef LIBCW_CSTRING
31 #define LIBCW_CSTRING
32 #include <cstring>	// Needed for std::memset.
33 #endif
34 #ifndef LIBCW_LIMITS_H
35 #define LIBCW_LIMITS_H
36 #include <limits.h>	// For PTHREAD_THREADS_MAX
37 #endif
38 #if LIBCWD_THREAD_SAFE
39 #include <libcwd/private_mutex.h>
40 #ifdef LIBCWD_HAVE_PTHREAD
41 #ifndef LIBCW_PTHREAD_H
42 #define LIBCW_PTHREAD_H
43 #include <pthread.h>
44 #endif
45 #endif
46 #endif
47 
48 namespace libcwd {
49   namespace _private_ {
50     struct TSD_st;
51   } // namespace _private_
52 } // namespace libcwd
53 
54 // When LIBCWD_THREAD_SAFE is set then `__libcwd_tsd' is a local variable
55 // (see LIBCWD_TSD_DECLARATION) or function parameter (LIBCWD_TSD_PARAM and LIBCWD_COMMA_TSD_PARAM).
56 // This approach means that many function signatures are different because with thread support a
57 // `__libcwd_tsd' reference needs to be passed.  We use several helper macros for this:
58 #if LIBCWD_THREAD_SAFE
59 
60 #define LIBCWD_TSD __libcwd_tsd				// Optional `__libcwd_tsd' parameter (foo() or foo(__libcwd_tsd)).
61 #define LIBCWD_COMMA_TSD , LIBCWD_TSD			// Idem, but as second or higher parameter.
62 #define LIBCWD_TSD_PARAM ::libcwd::_private_::TSD_st& __libcwd_tsd
63 							// Optional function parameter (foo(void) or foo(TSD_st& __libcwd_tsd)).
64 #define LIBCWD_TSD_PARAM_UNUSED ::libcwd::_private_::TSD_st&
65 							// Same without parameter.
66 #define LIBCWD_COMMA_TSD_PARAM , LIBCWD_TSD_PARAM	// Idem, but as second or higher parameter.
67 #define LIBCWD_COMMA_TSD_PARAM_UNUSED , LIBCWD_TSD_PARAM_UNUSED
68 							// Idem, without parameter.
69 #define LIBCWD_TSD_INSTANCE ::libcwd::_private_::TSD_st::instance()
70 							// For directly passing the `__libcwd_tsd' instance to a function (foo(TSD::instance())).
71 #define LIBCWD_COMMA_TSD_INSTANCE , LIBCWD_TSD_INSTANCE	// Idem, but as second or higher parameter.
72 #define LIBCWD_TSD_DECLARATION ::libcwd::_private_::TSD_st& __libcwd_tsd(::libcwd::_private_::TSD_st::instance())
73 							// Declaration of local `__libcwd_tsd' structure reference.
74 #define LIBCWD_DO_TSD(debug_object) (*__libcwd_tsd.do_array[(debug_object).WNS_index])
75     							// For use inside class debug_ct to access member `m'.
76 #define LIBCWD_TSD_MEMBER_OFF (__libcwd_tsd.do_off_array[WNS_index])
77 							// For use inside class debug_ct to access member `_off'.
78 #define LIBCWD_DO_TSD_MEMBER_OFF(debug_object) (__libcwd_tsd.do_off_array[(debug_object).WNS_index])
79 							// To access member _off of debug object.
80 
81 #else // !LIBCWD_THREAD_SAFE
82 
83 #define LIBCWD_TSD
84 #define LIBCWD_COMMA_TSD
85 #define LIBCWD_TSD_PARAM void
86 #define LIBCWD_TSD_PARAM_UNUSED void
87 #define LIBCWD_COMMA_TSD_PARAM
88 #define LIBCWD_COMMA_TSD_PARAM_UNUSED
89 #define LIBCWD_TSD_INSTANCE
90 #define LIBCWD_COMMA_TSD_INSTANCE
91 #define LIBCWD_TSD_DECLARATION
92 #define LIBCWD_DO_TSD(debug_object) ((debug_object).tsd)
93 #define LIBCWD_TSD_MEMBER_OFF (tsd._off)
94 #define LIBCWD_DO_TSD_MEMBER_OFF(debug_object) ((debug_object).tsd._off)
95 
96 #endif // !LIBCWD_THREAD_SAFE
97 
98 #define LIBCWD_DO_TSD_MEMBER(debug_object, m) (LIBCWD_DO_TSD(debug_object).m)
99 #define LIBCWD_TSD_MEMBER(m) LIBCWD_DO_TSD_MEMBER(*this, m)
100 
101 // These includes use the above macros.
102 #ifndef LIBCWD_STRUCT_DEBUG_TSD_H
103 #include <libcwd/struct_debug_tsd.h>
104 #endif
105 #if LIBCWD_THREAD_SAFE
106 #ifndef LIBCWD_PRIVATE_THREAD_H
107 #include <libcwd/private_thread.h>
108 #endif
109 #endif
110 
111 namespace libcwd {
112 
113 #if CWDEBUG_LOCATION
114 /** \addtogroup group_locations */
115 /** \{ */
116 
117 /** \brief The type of the argument of location_format
118  *
119  * This type is the same as alloc_format_t but should
120  * only be used together with the bit masks \ref show_objectfile, \ref show_function and \ref show_path.
121  */
122 typedef unsigned short int location_format_t;
123 
124 /** \} */ // End of group 'group_locations'
125 #endif
126 
127   namespace _private_ {
128 
129 extern int WST_initializing_TSD;
130 class thread_ct;
131 
132 struct TSD_st {
133 public:
134 #if CWDEBUG_ALLOC
135   int internal;				// libsysrecord.so relies on this being the first element.
136   int library_call;			// libsysrecord.so relies on this being the second element.
137   int inside_malloc_or_free;		// Set when entering a (de)allocation routine non-internal.
138   int invisible;			// When set, allocation done must be invisible.
139 #endif // CWDEBUG_ALLOC
140 #if CWDEBUG_LOCATION
141   location_format_t format;		// Determines how to print location_ct to an ostream.
142 #endif
143 #if LIBCWD_THREAD_SAFE
144   threadlist_t::iterator thread_iter;	// Persistant thread specific data (might even stay after this object is destructed).
145   bool thread_iter_valid;
146   thread_ct* target_thread;
147   int terminating;
148   bool pthread_lock_interface_is_locked;// Set while writing debugout to the final ostream.
149   bool list_allocations_on_show_allthreads;
150   int inside_free;			// Set when entering free().
151 #endif
152 #if CWDEBUG_DEBUGM
153   int marker;
154 #if CWDEBUG_MAGIC
155   int annotation;
156 #endif
157 #endif
158   bool recursive_fatal;			// Detect loop involving dc::fatal or dc::core.
159 #if CWDEBUG_DEBUG
160   bool recursive_assert;		// Detect loop involving LIBCWD_ASSERT.
161 #endif
162 #if CWDEBUG_DEBUGT
163   int cancel_explicitely_deferred;
164   int cancel_explicitely_disabled;
165   int inside_critical_area;
166   int cleanup_handler_installed;
167   int internal_debugging_code;
168   mutex_ct* waiting_for_mutex;		// mutex_ct that this thread is waiting for.
169   int waiting_for_lock;			// The instance of the lock that this thread is waiting for.
170   int waiting_for_rdlock;		// The instance of the rdlock that this thread is waiting for.
171   int instance_rdlocked[instance_rdlocked_size];
172   pthread_t rdlocked_by1[instance_rdlocked_size];
173   pthread_t rdlocked_by2[instance_rdlocked_size];
174   void const* rdlocked_from1[instance_rdlocked_size];
175   void const* rdlocked_from2[instance_rdlocked_size];
176 #endif
177 #if LIBCWD_THREAD_SAFE
178   pthread_t tid;			// Thread ID.
179   pid_t pid;				// Process ID.
180   int do_off_array[LIBCWD_DO_MAX];	// Thread Specific on/off counter for Debug Objects.
181   debug_tsd_st* do_array[LIBCWD_DO_MAX];// Thread Specific Data of Debug Objects or NULL when no debug object.
182   void cleanup_routine(void);
183   int off_cnt_array[LIBCWD_DC_MAX];	// Thread Specific Data of Debug Channels.
184 private:
185   int tsd_destructor_count;
186 #endif
187 
188 public:
189   void thread_destructed(void);
190 
191 #if LIBCWD_THREAD_SAFE
192 //-------------------------------------------------------
193 // Static data and methods.
194 private:
195   static TSD_st& S_create(int from_free);
196   static pthread_key_t S_tsd_key;
197   static pthread_once_t S_tsd_key_once;
198   static void S_tsd_key_alloc(void);
199   static void S_cleanup_routine(void* arg);
200 
201 public:
202   static TSD_st& instance(void);
203   static TSD_st& instance_free(void);
204   static void free_instance(TSD_st&);
205 #endif // LIBCWD_THREAD_SAFE
206 };
207 
208 // Thread Specific Data (TSD) is stored in a structure TSD_st
209 // and is accessed through a reference to `__libcwd_tsd'.
210 
211 #if !LIBCWD_THREAD_SAFE
212 // When LIBCWD_THREAD_SAFE is set then `__libcwd_tsd' is a local variable that references
213 // the Thread Specific Data as returned by TSD_st::instance(), otherwise it is simply a
214 // global object in namespace _private_:
215 extern TSD_st __libcwd_tsd;
216 #else
217 extern bool WST_tsd_key_created;
218 
219 inline
instance(void)220 TSD_st& TSD_st::instance(void)
221 {
222   TSD_st* instance;
223   if (!WST_tsd_key_created || !(instance = (TSD_st*)pthread_getspecific(S_tsd_key)))
224     return S_create(0);
225   return *instance;
226 }
227 
228 // This function is called at the start of free().
229 inline
instance_free(void)230 TSD_st& TSD_st::instance_free(void)
231 {
232   TSD_st* instance;
233   if (!WST_tsd_key_created || !(instance = (TSD_st*)pthread_getspecific(S_tsd_key)))
234     return S_create(1);
235   else
236     instance->inside_free++;
237   return *instance;
238 }
239 #endif
240 
241   } // namespace _private_
242 } // namespace libcwd
243 
244 #if !LIBCWD_THREAD_SAFE
245 // Put __libcwd_tsd in global namespace because anywhere we always refer to it
246 // as `__libcwd_tsd' because when LIBCWD_THREAD_SAFE is set it is local variable.
247 using ::libcwd::_private_::__libcwd_tsd;
248 #endif
249 
250 #endif // LIBCWD_PRIVATE_STRUCT_TSD_H
251