summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/inc/tdb_agent.h
blob: 5fff6dca0323241f33223b46777d3f4c2355ffa1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_TDB_AGENT_H
#define	_TDB_AGENT_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * Thread debug agent control structures.
 *
 * This is an implementation-specific header file that is shared
 * between libc and libc_db.  It is NOT a public header file
 * and must never be installed in /usr/include
 */

#include <thread_db.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * The structure containing per-thread event data.
 */
typedef struct {
	td_thr_events_t	eventmask;	/* Which events are enabled? */
	td_event_e	eventnum;	/* Most recent enabled event */
	void		*eventdata;	/* Param. for most recent event */
} td_evbuf_t;

#ifdef _SYSCALL32
typedef struct {
	td_thr_events_t	eventmask;	/* Which events are enabled? */
	td_event_e	eventnum;	/* Most recent enabled event */
	caddr32_t	eventdata;	/* Param. for most recent event */
} td_evbuf32_t;
#endif /* _SYSCALL32 */


/*
 * All of these structures are constrained to have a size of 48 bytes.
 * This is so that two 8-byte pointers can be inserted at the front to
 * make up a complete tdb_sync_stats_t structure of exactly 64 bytes.
 * The 'type' element of each structure identifies the type of the union,
 * with values from the following defines.
 */

#define	TDB_NONE	0
#define	TDB_MUTEX	1
#define	TDB_COND	2
#define	TDB_RWLOCK	3
#define	TDB_SEMA	4

typedef struct {
	uint16_t	type;
	uint16_t	unused;
	uint_t		mutex_lock;
	hrtime_t	mutex_hold_time;
	hrtime_t	mutex_sleep_time;
	uint_t		mutex_sleep;
	uint_t		mutex_try;
	uint_t		mutex_try_fail;
	uint_t		mutex_pad[1];
	hrtime_t	mutex_begin_hold;
} tdb_mutex_stats_t;

typedef struct {
	uint16_t	type;
	uint16_t	unused;
	uint_t		cond_wait;
	uint_t		cond_timedwait;
	uint_t		cond_timedwait_timeout;
	hrtime_t	cond_wait_sleep_time;
	hrtime_t	cond_timedwait_sleep_time;
	uint_t		cond_signal;
	uint_t		cond_broadcast;
	uint_t		cond_pad[2];
} tdb_cond_stats_t;

typedef struct {
	uint16_t	type;
	uint16_t	unused;
	uint_t		rw_rdlock;
	/* rw_rdlock_sleep is the reader cv's cond_wait count */
	/* rw_rdlock_sleep_time is the reader cv's cond_wait_sleep_time */
	uint_t		rw_rdlock_try;
	uint_t		rw_rdlock_try_fail;
	uint_t		rw_pad[1];
	uint_t		rw_wrlock;
	/* rw_wrlock_sleep is the writer cv's cond_wait count */
	/* rw_wrlock_sleep_time is the writer cv's cond_wait_sleep_time */
	hrtime_t	rw_wrlock_hold_time;
	uint_t		rw_wrlock_try;
	uint_t		rw_wrlock_try_fail;
	hrtime_t	rw_wrlock_begin_hold;
} tdb_rwlock_stats_t;

typedef struct {
	uint16_t	type;
	uint16_t	unused;
	uint_t		sema_post;
	uint_t		sema_wait;
	uint_t		sema_wait_sleep;
	hrtime_t	sema_wait_sleep_time;
	uint_t		sema_trywait;
	uint_t		sema_trywait_fail;
	uint_t		sema_max_count;
	uint_t		sema_min_count;
	uint_t		sema_pad[2];
} tdb_sema_stats_t;

/*
 * An entry in the sync. object hash table.
 */
typedef struct {
	uint64_t	next;
	uint64_t	sync_addr;
	union {
		uint16_t		type;
		tdb_mutex_stats_t	mutex;
		tdb_cond_stats_t	cond;
		tdb_rwlock_stats_t	rwlock;
		tdb_sema_stats_t	sema;
	} un;
} tdb_sync_stats_t;

/* peg count values at UINT_MAX */
#define	tdb_incr(x)	(((x) != UINT_MAX)? (x)++ : 0)

/*
 * The tdb_register_sync variable is set to REGISTER_SYNC_ENABLE by a
 * debugger to enable synchronization object registration.
 * Thereafter, synchronization primitives call tdb_sync_obj_register()
 * to put their synchronization objects in the registration hash table.
 * In this state, the first call to tdb_sync_obj_register() empties the
 * hash table and sets tdb_register_sync to REGISTER_SYNC_ON.
 *
 * The tdb_register_sync variable is set to REGISTER_SYNC_DISABLE by a
 * debugger to disable synchronization object registration.
 * In this state, the first call to tdb_sync_obj_register() empties the
 * hash table and sets tdb_register_sync to REGISTER_SYNC_OFF.
 * Thereafter, synchronization primitives do not call tdb_sync_obj_register().
 *
 * Sync object *_destroy() functions always call tdb_sync_obj_deregister().
 */
typedef	uint8_t	register_sync_t;
#define	REGISTER_SYNC_OFF	0	/* registration is off */
#define	REGISTER_SYNC_ON	1	/* registration is on */
#define	REGISTER_SYNC_DISABLE	2	/* request to disable registration */
#define	REGISTER_SYNC_ENABLE	3	/* request to enable registration */

extern	tdb_sync_stats_t	*tdb_sync_obj_register(void *, int *);
extern	void			tdb_sync_obj_deregister(void *);

/*
 * Definitions for acquiring pointers to synch object statistics blocks
 * contained in the synchronization object registration hash table.
 */
extern	tdb_mutex_stats_t	*tdb_mutex_stats(mutex_t *);
extern	tdb_cond_stats_t	*tdb_cond_stats(cond_t *);
extern	tdb_rwlock_stats_t	*tdb_rwlock_stats(rwlock_t *);
extern	tdb_sema_stats_t	*tdb_sema_stats(sema_t *);

#define	REGISTER_SYNC(udp)	(udp)->uberflags.uf_tdb_register_sync

#define	MUTEX_STATS(mp, udp)	\
		(REGISTER_SYNC(udp)? tdb_mutex_stats(mp): NULL)
#define	COND_STATS(cvp, udp)	\
		(REGISTER_SYNC(udp)? tdb_cond_stats(cvp): NULL)
#define	RWLOCK_STATS(rwlp, udp)	\
		(REGISTER_SYNC(udp)? tdb_rwlock_stats(rwlp): NULL)
#define	SEMA_STATS(sp, udp)	\
		(REGISTER_SYNC(udp)? tdb_sema_stats(sp): NULL)

/*
 * Parameters of the synchronization object registration hash table.
 */
#define	TDB_HASH_SHIFT	15	/* 32K hash table entries */
#define	TDB_HASH_SIZE	(1 << TDB_HASH_SHIFT)
#define	TDB_HASH_MASK	(TDB_HASH_SIZE - 1)

/*
 * uberdata.tdb_hash_lock protects all synchronization object
 * hash table data structures.
 * uberdata.tdb_hash_lock_stats is a special tdb_sync_stats structure
 * reserved for tdb_hash_lock.
 */

typedef	void (*tdb_ev_func_t)(void);

/*
 * Uberdata for thread debug interfaces (known to libc_db).
 */
typedef struct {
	/*
	 * Pointer to the hash table of sync_addr_t descriptors.
	 * This holds the addresses of all of the synchronization variables
	 * that the library has seen since tracking was enabled by a debugger.
	 */
	uint64_t		*tdb_sync_addr_hash;
	/*
	 * The number of entries in the hash table.
	 */
	uint_t			tdb_register_count;
	int			tdb_hash_alloc_failed;
	/*
	 * The free list of sync_addr_t descriptors.
	 * When the free list is used up, it is replenished using mmap().
	 * sync_addr_t descriptors are never freed, though they may be
	 * removed from the hash table and returned to the free list.
	 */
	tdb_sync_stats_t	*tdb_sync_addr_free;
	tdb_sync_stats_t	*tdb_sync_addr_last;
	size_t			tdb_sync_alloc;
	/*
	 * The set of globally enabled events to report to libc_db.
	 */
	td_thr_events_t		tdb_ev_global_mask;
	/*
	 * The array of event function pointers.
	 */
	const tdb_ev_func_t	*tdb_events;
} tdb_t;

#ifdef _SYSCALL32
typedef struct {
	caddr32_t	tdb_sync_addr_hash;
	uint_t		tdb_register_count;
	int		tdb_hash_alloc_failed;
	caddr32_t	tdb_sync_addr_free;
	caddr32_t	tdb_sync_addr_last;
	size32_t	tdb_sync_alloc;
	td_thr_events_t	tdb_ev_global_mask;
	caddr32_t	tdb_events;
} tdb32_t;
#endif /* _SYSCALL32 */

/*
 * This will have to change if event numbers exceed 31.
 * Note that we only test tdb_ev_global_mask.event_bits[0] below.
 */
#define	__td_event_report(ulwp, event, udp)				\
	(((ulwp)->ul_td_events_enable &&				\
	td_eventismember(&(ulwp)->ul_td_evbuf.eventmask, (event))) ||	\
	((udp)->tdb.tdb_ev_global_mask.event_bits[0] &&			\
	td_eventismember(&(udp)->tdb.tdb_ev_global_mask, (event))))

/*
 * Event "reporting" functions.  A thread reports an event by calling
 * one of these empty functions; a debugger can set a breakpoint
 * at the address of any of these functions to determine that an
 * event is being reported.
 */
extern const tdb_ev_func_t tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1];

#define	tdb_event(event, udp)		\
	(*(udp)->tdb.tdb_events[(event) - TD_MIN_EVENT_NUM])()

#ifdef __cplusplus
}
#endif

#endif	/* _TDB_AGENT_H */