xref: /illumos-gate/usr/src/lib/libc/inc/tdb_agent.h (revision 42b53e0fbc5c05289c3d334bb864b784fafe5ce4)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef	_TDB_AGENT_H
28 #define	_TDB_AGENT_H
29 
30 /*
31  * Thread debug agent control structures.
32  *
33  * This is an implementation-specific header file that is shared
34  * between libc and libc_db.  It is NOT a public header file
35  * and must never be installed in /usr/include
36  */
37 
38 #include <thread_db.h>
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /*
45  * The structure containing per-thread event data.
46  */
47 typedef struct {
48 	td_thr_events_t	eventmask;	/* Which events are enabled? */
49 	td_event_e	eventnum;	/* Most recent enabled event */
50 	void		*eventdata;	/* Param. for most recent event */
51 } td_evbuf_t;
52 
53 #ifdef _SYSCALL32
54 typedef struct {
55 	td_thr_events_t	eventmask;	/* Which events are enabled? */
56 	td_event_e	eventnum;	/* Most recent enabled event */
57 	caddr32_t	eventdata;	/* Param. for most recent event */
58 } td_evbuf32_t;
59 #endif /* _SYSCALL32 */
60 
61 
62 /*
63  * All of these structures are constrained to have a size of 48 bytes.
64  * This is so that two 8-byte pointers can be inserted at the front to
65  * make up a complete tdb_sync_stats_t structure of exactly 64 bytes.
66  * The 'type' element of each structure identifies the type of the union,
67  * with values from the following defines.
68  */
69 
70 #define	TDB_NONE	0
71 #define	TDB_MUTEX	1
72 #define	TDB_COND	2
73 #define	TDB_RWLOCK	3
74 #define	TDB_SEMA	4
75 
76 typedef struct {
77 	uint16_t	type;
78 	uint16_t	unused;
79 	uint_t		mutex_lock;
80 	hrtime_t	mutex_hold_time;
81 	hrtime_t	mutex_sleep_time;
82 	uint_t		mutex_sleep;
83 	uint_t		mutex_try;
84 	uint_t		mutex_try_fail;
85 	uint_t		mutex_pad[1];
86 	hrtime_t	mutex_begin_hold;
87 } tdb_mutex_stats_t;
88 
89 typedef struct {
90 	uint16_t	type;
91 	uint16_t	unused;
92 	uint_t		cond_wait;
93 	uint_t		cond_timedwait;
94 	uint_t		cond_timedwait_timeout;
95 	hrtime_t	cond_wait_sleep_time;
96 	hrtime_t	cond_timedwait_sleep_time;
97 	uint_t		cond_signal;
98 	uint_t		cond_broadcast;
99 	uint_t		cond_pad[2];
100 } tdb_cond_stats_t;
101 
102 typedef struct {
103 	uint16_t	type;
104 	uint16_t	unused;
105 	uint_t		rw_rdlock;
106 	/* rw_rdlock_sleep is the reader cv's cond_wait count */
107 	/* rw_rdlock_sleep_time is the reader cv's cond_wait_sleep_time */
108 	uint_t		rw_rdlock_try;
109 	uint_t		rw_rdlock_try_fail;
110 	uint_t		rw_pad[1];
111 	uint_t		rw_wrlock;
112 	/* rw_wrlock_sleep is the writer cv's cond_wait count */
113 	/* rw_wrlock_sleep_time is the writer cv's cond_wait_sleep_time */
114 	hrtime_t	rw_wrlock_hold_time;
115 	uint_t		rw_wrlock_try;
116 	uint_t		rw_wrlock_try_fail;
117 	hrtime_t	rw_wrlock_begin_hold;
118 } tdb_rwlock_stats_t;
119 
120 typedef struct {
121 	uint16_t	type;
122 	uint16_t	unused;
123 	uint_t		sema_post;
124 	uint_t		sema_wait;
125 	uint_t		sema_wait_sleep;
126 	hrtime_t	sema_wait_sleep_time;
127 	uint_t		sema_trywait;
128 	uint_t		sema_trywait_fail;
129 	uint_t		sema_max_count;
130 	uint_t		sema_min_count;
131 	uint_t		sema_pad[2];
132 } tdb_sema_stats_t;
133 
134 /*
135  * An entry in the sync. object hash table.
136  */
137 typedef struct {
138 	uint64_t	next;
139 	uint64_t	sync_addr;
140 	union {
141 		uint16_t		type;
142 		tdb_mutex_stats_t	mutex;
143 		tdb_cond_stats_t	cond;
144 		tdb_rwlock_stats_t	rwlock;
145 		tdb_sema_stats_t	sema;
146 	} un;
147 } tdb_sync_stats_t;
148 
149 /* peg count values at UINT_MAX */
150 #define	tdb_incr(x)	(((x) != UINT_MAX)? (x)++ : 0)
151 
152 /*
153  * The tdb_register_sync variable is set to REGISTER_SYNC_ENABLE by a
154  * debugger to enable synchronization object registration.
155  * Thereafter, synchronization primitives call tdb_sync_obj_register()
156  * to put their synchronization objects in the registration hash table.
157  * In this state, the first call to tdb_sync_obj_register() empties the
158  * hash table and sets tdb_register_sync to REGISTER_SYNC_ON.
159  *
160  * The tdb_register_sync variable is set to REGISTER_SYNC_DISABLE by a
161  * debugger to disable synchronization object registration.
162  * In this state, the first call to tdb_sync_obj_register() empties the
163  * hash table and sets tdb_register_sync to REGISTER_SYNC_OFF.
164  * Thereafter, synchronization primitives do not call tdb_sync_obj_register().
165  *
166  * Sync object *_destroy() functions always call tdb_sync_obj_deregister().
167  */
168 typedef	uint8_t	register_sync_t;
169 #define	REGISTER_SYNC_OFF	0	/* registration is off */
170 #define	REGISTER_SYNC_ON	1	/* registration is on */
171 #define	REGISTER_SYNC_DISABLE	2	/* request to disable registration */
172 #define	REGISTER_SYNC_ENABLE	3	/* request to enable registration */
173 
174 extern	tdb_sync_stats_t	*tdb_sync_obj_register(void *, int *);
175 extern	void			tdb_sync_obj_deregister(void *);
176 
177 /*
178  * Definitions for acquiring pointers to synch object statistics blocks
179  * contained in the synchronization object registration hash table.
180  */
181 extern	tdb_mutex_stats_t	*tdb_mutex_stats(mutex_t *);
182 extern	tdb_cond_stats_t	*tdb_cond_stats(cond_t *);
183 extern	tdb_rwlock_stats_t	*tdb_rwlock_stats(rwlock_t *);
184 extern	tdb_sema_stats_t	*tdb_sema_stats(sema_t *);
185 
186 #define	REGISTER_SYNC(udp)	(udp)->uberflags.uf_tdb_register_sync
187 
188 #define	MUTEX_STATS(mp, udp)	\
189 		(REGISTER_SYNC(udp)? tdb_mutex_stats(mp): NULL)
190 #define	COND_STATS(cvp, udp)	\
191 		(REGISTER_SYNC(udp)? tdb_cond_stats(cvp): NULL)
192 #define	RWLOCK_STATS(rwlp, udp)	\
193 		(REGISTER_SYNC(udp)? tdb_rwlock_stats(rwlp): NULL)
194 #define	SEMA_STATS(sp, udp)	\
195 		(REGISTER_SYNC(udp)? tdb_sema_stats(sp): NULL)
196 
197 /*
198  * Parameters of the synchronization object registration hash table.
199  */
200 #define	TDB_HASH_SHIFT	15	/* 32K hash table entries */
201 #define	TDB_HASH_SIZE	(1 << TDB_HASH_SHIFT)
202 #define	TDB_HASH_MASK	(TDB_HASH_SIZE - 1)
203 
204 /*
205  * uberdata.tdb_hash_lock protects all synchronization object
206  * hash table data structures.
207  * uberdata.tdb_hash_lock_stats is a special tdb_sync_stats structure
208  * reserved for tdb_hash_lock.
209  */
210 
211 typedef	void (*tdb_ev_func_t)(void);
212 
213 /*
214  * Uberdata for thread debug interfaces (known to libc_db).
215  */
216 typedef struct {
217 	/*
218 	 * Pointer to the hash table of sync_addr_t descriptors.
219 	 * This holds the addresses of all of the synchronization variables
220 	 * that the library has seen since tracking was enabled by a debugger.
221 	 */
222 	uint64_t		*tdb_sync_addr_hash;
223 	/*
224 	 * The number of entries in the hash table.
225 	 */
226 	uint_t			tdb_register_count;
227 	int			tdb_hash_alloc_failed;
228 	/*
229 	 * The free list of sync_addr_t descriptors.
230 	 * When the free list is used up, it is replenished using mmap().
231 	 * sync_addr_t descriptors are never freed, though they may be
232 	 * removed from the hash table and returned to the free list.
233 	 */
234 	tdb_sync_stats_t	*tdb_sync_addr_free;
235 	tdb_sync_stats_t	*tdb_sync_addr_last;
236 	size_t			tdb_sync_alloc;
237 	/*
238 	 * The set of globally enabled events to report to libc_db.
239 	 */
240 	td_thr_events_t		tdb_ev_global_mask;
241 	/*
242 	 * The array of event function pointers.
243 	 */
244 	const tdb_ev_func_t	*tdb_events;
245 } tdb_t;
246 
247 #ifdef _SYSCALL32
248 typedef struct {
249 	caddr32_t	tdb_sync_addr_hash;
250 	uint_t		tdb_register_count;
251 	int		tdb_hash_alloc_failed;
252 	caddr32_t	tdb_sync_addr_free;
253 	caddr32_t	tdb_sync_addr_last;
254 	size32_t	tdb_sync_alloc;
255 	td_thr_events_t	tdb_ev_global_mask;
256 	caddr32_t	tdb_events;
257 } tdb32_t;
258 #endif /* _SYSCALL32 */
259 
260 /*
261  * This will have to change if event numbers exceed 31.
262  * Note that we only test tdb_ev_global_mask.event_bits[0] below.
263  */
264 #define	__td_event_report(ulwp, event, udp)				\
265 	(((ulwp)->ul_td_events_enable &&				\
266 	td_eventismember(&(ulwp)->ul_td_evbuf.eventmask, (event))) ||	\
267 	((udp)->tdb.tdb_ev_global_mask.event_bits[0] &&			\
268 	td_eventismember(&(udp)->tdb.tdb_ev_global_mask, (event))))
269 
270 /*
271  * Event "reporting" functions.  A thread reports an event by calling
272  * one of these empty functions; a debugger can set a breakpoint
273  * at the address of any of these functions to determine that an
274  * event is being reported.
275  */
276 extern const tdb_ev_func_t tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1];
277 
278 #define	tdb_event(event, udp)		\
279 	(*(udp)->tdb.tdb_events[(event) - TD_MIN_EVENT_NUM])()
280 
281 #ifdef __cplusplus
282 }
283 #endif
284 
285 #endif	/* _TDB_AGENT_H */
286