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