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