/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _THREAD_DB_H #define _THREAD_DB_H /* * * Description: * Types, global variables, and function definitions for users * of libc_db (formerly libthread_db). * */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define TD_THR_ANY_USER_FLAGS 0xffffffff #define TD_THR_LOWEST_PRIORITY -128 #define TD_SIGNO_MASK 0 #define TD_EVENTSIZE 2 /* * Opaque handle types. */ /* Client's handle for a process */ struct ps_prochandle; /* libthread's handle for a process */ typedef struct td_thragent td_thragent_t; /* The thread handle. */ typedef struct td_thrhandle { td_thragent_t *th_ta_p; psaddr_t th_unique; } td_thrhandle_t; /* The handle for a synchronization object. */ typedef struct td_synchandle { td_thragent_t *sh_ta_p; psaddr_t sh_unique; } td_synchandle_t; /* ------------------------------------------------------------------ */ /* * The libc_db event facility. */ #define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ #define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ #define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ /* Bitmask of enabled events. */ typedef struct td_thr_events { uint_t event_bits[TD_EVENTSIZE]; } td_thr_events_t; /* Event set manipulation macros. */ #define __td_eventmask(n) ((unsigned int)1 << (((n) - 1) \ & (BT_NBIPUI - 1))) #define __td_eventword(n) (((unsigned int)((n) - 1))>>5) #define td_event_emptyset(setp) \ { \ int _i_; \ _i_ = TD_EVENTSIZE; \ while (_i_) (setp)->event_bits[--_i_] = 0; \ } #define td_event_fillset(setp) \ { \ int _i_; \ _i_ = TD_EVENTSIZE; \ while (_i_) (setp)->event_bits[--_i_] = \ 0xffffffff; \ } #define td_event_addset(setp, n) \ (((setp)->event_bits[__td_eventword(n)]) |= __td_eventmask(n)) #define td_event_delset(setp, n) \ (((setp)->event_bits[__td_eventword(n)]) &= ~__td_eventmask(n)) #define td_eventismember(setp, n) \ (__td_eventmask(n) & ((setp)->event_bits[__td_eventword(n)])) #define td_eventisempty(setp) \ (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) typedef enum { TD_ALL_EVENTS, /* pseudo-event number */ TD_EVENT_NONE = TD_ALL_EVENTS, /* depends on context */ TD_READY, TD_SLEEP, TD_SWITCHTO, TD_SWITCHFROM, TD_LOCK_TRY, TD_CATCHSIG, TD_IDLE, TD_CREATE, TD_DEATH, TD_PREEMPT, TD_PRI_INHERIT, TD_REAP, TD_CONCURRENCY, TD_TIMEOUT, TD_MIN_EVENT_NUM = TD_READY, TD_MAX_EVENT_NUM = TD_TIMEOUT, TD_EVENTS_ENABLE = 31 /* Event reporting enabled */ } td_event_e; /* * Ways that an event type can be reported. */ typedef enum { NOTIFY_BPT, /* * bpt to be inserted at u.bptaddr by * debugger */ NOTIFY_AUTOBPT, /* bpt inserted at u.bptaddr by application */ NOTIFY_SYSCALL /* syscall u.syscallno will be invoked */ } td_notify_e; /* * How an event type is reported. */ typedef struct td_notify { td_notify_e type; union { psaddr_t bptaddr; int syscallno; } u; } td_notify_t; /* * An event message. */ typedef struct td_event_msg { td_event_e event; /* Event type being reported */ const td_thrhandle_t *th_p; /* Thread reporting the event */ union { /* Type-dependent event data */ td_synchandle_t *sh; /* historical rubbish; ignore */ uintptr_t data; /* valid, depending on event type */ } msg; } td_event_msg_t; /* --------------------------------------------------------------------- */ /* * Thread information structure as returned by td_thr_get_info(), and * related types. */ /* * Possible thread states. TD_THR_ANY_STATE is a pseudo-state used * to select threads regardless of state in td_ta_thr_iter(). */ typedef enum { TD_THR_ANY_STATE, TD_THR_UNKNOWN, TD_THR_STOPPED, TD_THR_RUN, TD_THR_ACTIVE, TD_THR_ZOMBIE, TD_THR_SLEEP, TD_THR_STOPPED_ASLEEP } td_thr_state_e; /* * Thread type: user or system. * As of Solaris 9, all threads are type TD_THR_USER. */ typedef enum { TD_THR_ANY_TYPE, /* not used */ TD_THR_USER, TD_THR_SYSTEM } td_thr_type_e; typedef struct td_thrinfo { td_thragent_t *ti_ta_p; /* process handle */ unsigned ti_user_flags; /* flags passed to thr_create() */ thread_t ti_tid; /* tid returned by thr_create() */ void *ti_exitval; /* thread exit value (TD_THR_ZOMBIE) */ psaddr_t ti_startfunc; /* startfunc passed to thr_create() */ psaddr_t ti_stkbase; /* base of thread's stack */ long ti_stksize; /* size of thread's stack */ psaddr_t ti_ro_area; /* address of uthread_t struct */ int ti_ro_size; /* size of uthread_t struct */ td_thr_state_e ti_state; /* thread state */ uchar_t ti_db_suspended; /* boolean: suspended by debugger? */ td_thr_type_e ti_type; /* thread type */ intptr_t ti_pc; /* resume PC when sleeping */ intptr_t ti_sp; /* resume SP when sleeping */ short ti_flags; /* flags used by libthread */ int ti_pri; /* thread priority */ lwpid_t ti_lid; /* last LWP assigned to this thread */ sigset_t ti_sigmask; /* signal mask */ uchar_t ti_traceme; /* event reporting enabled? */ uchar_t ti_preemptflag; /* was thread preemppted? */ uchar_t ti_pirecflag; /* priority inheritance happened */ sigset_t ti_pending; /* set of pending signals */ td_thr_events_t ti_events; /* set of enabled events */ } td_thrinfo_t; #define ti_tls ti_exitval /* for source compatibility */ typedef struct td_ta_stats { int nthreads; /* total number of threads in use */ int r_concurrency; /* requested concurrency level */ int nrunnable_num; /* numerator, avg. runnable threads */ int nrunnable_den; /* denominator, avg. runnable threads */ int a_concurrency_num; /* numerator, achieved concurrency level */ int a_concurrency_den; /* denominator, concurrency level */ int nlwps_num; /* numerator, average number of LWP's in use */ int nlwps_den; /* denom., average number of LWP's in use */ int nidle_num; /* numerator, avg. number of idling LWP's */ int nidle_den; /* denom., avg. number of idling LWP's */ } td_ta_stats_t; /* * Iterator callback function declarations. */ /* Callback function for td_ta_tsd_iter(). */ typedef int td_key_iter_f(thread_key_t, void (*destructor)(), void *); /* Callback function for td_ta_thr_iter(). */ typedef int td_thr_iter_f(const td_thrhandle_t *, void *); /* Callback function for td_ta_sync_iter(). */ typedef int td_sync_iter_f(const td_synchandle_t *, void *); /* -------------------------------------------------------------------- */ /* * Synchronization Objects */ /* Enumeration of synchronization object types. */ typedef enum td_sync_type_e { TD_SYNC_UNKNOWN, /* Sync. variable of unknown type */ TD_SYNC_COND, /* Condition variable */ TD_SYNC_MUTEX, /* Mutex lock */ TD_SYNC_SEMA, /* Semaphore */ TD_SYNC_RWLOCK /* Reader/Writer lock */ } td_sync_type_e; #define TD_SV_MAX_FLAGS 4 typedef uint8_t td_sync_flags_t; /* * Synchronization object information structure filled in by td_sync_get_info() */ typedef struct td_syncinfo { td_thragent_t *si_ta_p; /* process handle */ psaddr_t si_sv_addr; /* address of sync. object */ td_sync_type_e si_type; /* object type */ uint32_t si_shared_type; /* process-shared or process-private */ td_sync_flags_t si_flags[TD_SV_MAX_FLAGS]; /* flags (?) */ pid_t si_ownerpid; /* owner's process-id (USYNC_PROCESS) */ union _si_un_state { int sem_count; /* semaphore count */ int nreaders; /* number of readers, -1 if writer */ int mutex_locked; /* non-zero iff locked */ } si_state; int si_size; /* size in bytes of synch variable */ uint8_t si_has_waiters; /* non-zero iff at least one waiter */ uint8_t si_is_wlock; /* non-zero iff rwlock write-locked */ uint8_t si_rcount; /* count for locked recursive mutex */ uint8_t si_prioceiling; /* ceiling pri (PTHREAD_PRIO_PROTECT) */ td_thrhandle_t si_owner; /* mutex holder or write-lock holder */ psaddr_t si_data; /* optional data */ } td_syncinfo_t; /* * Statistics structures for the various synchronization objects, contained * within the td_syncstats structure returned by td_sync_get_stats(). */ typedef struct { uint_t mutex_lock; uint_t mutex_sleep; hrtime_t mutex_sleep_time; hrtime_t mutex_hold_time; uint_t mutex_try; uint_t mutex_try_fail; uint_t mutex_internal; /* internal to libthread */ } td_mutex_stats_t; typedef struct { uint_t cond_wait; uint_t cond_timedwait; hrtime_t cond_wait_sleep_time; hrtime_t cond_timedwait_sleep_time; uint_t cond_timedwait_timeout; uint_t cond_signal; uint_t cond_broadcast; uint_t cond_internal; /* internal to libthread */ } td_cond_stats_t; typedef struct { uint_t rw_rdlock; uint_t rw_rdlock_sleep; hrtime_t rw_rdlock_sleep_time; uint_t rw_rdlock_try; uint_t rw_rdlock_try_fail; uint_t rw_wrlock; uint_t rw_wrlock_sleep; hrtime_t rw_wrlock_sleep_time; hrtime_t rw_wrlock_hold_time; uint_t rw_wrlock_try; uint_t rw_wrlock_try_fail; } td_rwlock_stats_t; typedef struct { 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_post; uint_t sema_max_count; uint_t sema_min_count; } td_sema_stats_t; /* * Synchronization object statistics structure filled in by td_sync_get_stats() */ typedef struct td_syncstats { td_syncinfo_t ss_info; /* as returned by td_sync_get_info() */ union { td_mutex_stats_t mutex; td_cond_stats_t cond; td_rwlock_stats_t rwlock; td_sema_stats_t sema; uint_t pad[32]; /* for future growth */ } ss_un; } td_syncstats_t; /* The set of error codes. */ typedef enum { TD_OK, /* generic "call succeeded" */ TD_ERR, /* generic error. */ TD_NOTHR, /* no thread can be found to satisfy query */ TD_NOSV, /* no synch. handle can be found to satisfy query */ TD_NOLWP, /* no lwp can be found to satisfy query */ TD_BADPH, /* invalid process handle */ TD_BADTH, /* invalid thread handle */ TD_BADSH, /* invalid synchronization handle */ TD_BADTA, /* invalid thread agent */ TD_BADKEY, /* invalid key */ TD_NOMSG, /* no event message for td_thr_event_getmsg() */ TD_NOFPREGS, /* FPU register set not available */ TD_NOLIBTHREAD, /* application not linked with libthread */ TD_NOEVENT, /* requested event is not supported */ TD_NOCAPAB, /* capability not available */ TD_DBERR, /* Debugger service failed */ TD_NOAPLIC, /* Operation not applicable to */ TD_NOTSD, /* No thread-specific data for this thread */ TD_MALLOC, /* Malloc failed */ TD_PARTIALREG, /* Only part of register set was writen/read */ TD_NOXREGS, /* X register set not available for given thread */ TD_NOTLS, /* There is no TLS in the specified module */ TD_TLSDEFER /* module's TLS not yet allocated by the thread */ } td_err_e; /* ----------------------------------------------------------------------- */ /* * Exported functions. */ /* * Initialize the threads debug interface. */ td_err_e td_init(void); /* * A no-op, left for historical reasons. */ void td_log(void); /* * Allocate a new process handle ("thread agent"). */ td_err_e td_ta_new(struct ps_prochandle *, td_thragent_t **); /* * De-allocate a process handle, releasing all related resources. */ td_err_e td_ta_delete(td_thragent_t *); /* * Map a process handle to a client process handle. */ td_err_e td_ta_get_ph(const td_thragent_t *, struct ps_prochandle **); /* * Set the process's suggested concurrency level. */ td_err_e td_ta_setconcurrency(const td_thragent_t *, int); /* * Get the number of threads in the process, including zombie threads. */ td_err_e td_ta_get_nthreads(const td_thragent_t *, int *); /* * Map a tid, as returned by thr_create(), to a thread handle. */ td_err_e td_ta_map_id2thr(const td_thragent_t *, thread_t, td_thrhandle_t *); /* * Map the address of a synchronization object to a sync. object handle. */ td_err_e td_ta_map_addr2sync(const td_thragent_t *, psaddr_t, td_synchandle_t *); /* * Iterate over a process's thread-specific data (TSD) keys. */ td_err_e td_ta_tsd_iter(const td_thragent_t *, td_key_iter_f *, void *); /* * Iterate over a process's threads, including zombie threads. */ td_err_e td_ta_thr_iter(const td_thragent_t *, td_thr_iter_f *, void *, td_thr_state_e, int, sigset_t *, unsigned); /* * Iterate over a process's known synchronization objects. */ td_err_e td_ta_sync_iter(const td_thragent_t *, td_sync_iter_f *, void *); /* * Enable/disable process statistics collection. */ td_err_e td_ta_enable_stats(const td_thragent_t *, int); /* * Reset process statistics. */ td_err_e td_ta_reset_stats(const td_thragent_t *); /* * Read process statistics. */ td_err_e td_ta_get_stats(const td_thragent_t *, td_ta_stats_t *); /* * Get thread information. */ td_err_e td_thr_get_info(const td_thrhandle_t *, td_thrinfo_t *); /* * Get the "event address" for an event type. */ td_err_e td_ta_event_addr(const td_thragent_t *, td_event_e, td_notify_t *); /* * Enable/disable event reporting for a thread. */ td_err_e td_thr_event_enable(const td_thrhandle_t *, int); /* * Enable a set of events for a thread. */ td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *); /* * Disable a set of events for a thread. */ td_err_e td_thr_clear_event(const td_thrhandle_t *, td_thr_events_t *); /* * Retrieve (and consume) an event message for a thread. */ td_err_e td_thr_event_getmsg(const td_thrhandle_t *, td_event_msg_t *); /* * Enable a set of events in the process. */ td_err_e td_ta_set_event(const td_thragent_t *, td_thr_events_t *); /* * Disable a set of events in the process. */ td_err_e td_ta_clear_event(const td_thragent_t *, td_thr_events_t *); /* * Retrieve (and consume) an event message for some thread in the process. */ td_err_e td_ta_event_getmsg(const td_thragent_t *, td_event_msg_t *); /* * Suspend a thread. */ td_err_e td_thr_dbsuspend(const td_thrhandle_t *); /* * Resume a suspended thread. */ td_err_e td_thr_dbresume(const td_thrhandle_t *); /* * Set a thread's signal mask. */ td_err_e td_thr_sigsetmask(const td_thrhandle_t *, const sigset_t); /* * Set a thread's "signals-pending" set. */ td_err_e td_thr_setsigpending(const td_thrhandle_t *, uchar_t, const sigset_t); /* * Get a thread's general register set. */ td_err_e td_thr_getgregs(const td_thrhandle_t *, prgregset_t); /* * Set a thread's general register set. */ td_err_e td_thr_setgregs(const td_thrhandle_t *, const prgregset_t); /* * Get a thread's floating-point register set. */ td_err_e td_thr_getfpregs(const td_thrhandle_t *, prfpregset_t *); /* * Set a thread's floating-point register set. */ td_err_e td_thr_setfpregs(const td_thrhandle_t *, const prfpregset_t *); /* * Get the size of the extra state register set for this architecture. */ td_err_e td_thr_getxregsize(const td_thrhandle_t *th_p, int *xregsize); /* * Get a thread's extra state register set. */ td_err_e td_thr_getxregs(const td_thrhandle_t *th_p, void *xregs); /* * Set a thread's extra state register set. */ td_err_e td_thr_setxregs(const td_thrhandle_t *th_p, const void *xregs); /* * Validate a thread handle. */ td_err_e td_thr_validate(const td_thrhandle_t *); /* * Get a thread-specific data pointer for a thread. */ td_err_e td_thr_tsd(const td_thrhandle_t *, thread_key_t, void **); /* * Get the base address of a thread's thread local storage (TLS) block * for the module (executable or shared object) identified by 'moduleid'. */ td_err_e td_thr_tlsbase(const td_thrhandle_t *, ulong_t moduleid, psaddr_t *base); /* * Set a thread's priority. */ td_err_e td_thr_setprio(const td_thrhandle_t *, int); /* * Iterate over the set of locks owned by a thread. */ td_err_e td_thr_lockowner(const td_thrhandle_t *, td_sync_iter_f *, void *); /* * Return the sync. handle of the object this thread is sleeping on. */ td_err_e td_thr_sleepinfo(const td_thrhandle_t *, td_synchandle_t *); /* * Map an lwpid, as returned by _lwp_create(), to a thread handle. */ td_err_e td_ta_map_lwp2thr(const td_thragent_t *, lwpid_t, td_thrhandle_t *th_p); /* * Enable/disable a process's synchronization object tracking. */ td_err_e td_ta_sync_tracking_enable(const td_thragent_t *, int); /* * Get information about a synchronization object. */ td_err_e td_sync_get_info(const td_synchandle_t *, td_syncinfo_t *); /* * Get statistics for a synchronization object. */ td_err_e td_sync_get_stats(const td_synchandle_t *, td_syncstats_t *); /* * Set the state of a synchronization object. */ td_err_e td_sync_setstate(const td_synchandle_t *, int value); /* * Iterate over all threads blocked on a synchronization object. */ td_err_e td_sync_waiters(const td_synchandle_t *, td_thr_iter_f *, void *); #ifdef __cplusplus } #endif #endif /* _THREAD_DB_H */