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 2005 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 #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <dt_impl.h> 30*0Sstevel@tonic-gate #include <stddef.h> 31*0Sstevel@tonic-gate #include <errno.h> 32*0Sstevel@tonic-gate #include <assert.h> 33*0Sstevel@tonic-gate #include <time.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate static const struct { 36*0Sstevel@tonic-gate int dtslt_option; 37*0Sstevel@tonic-gate size_t dtslt_offs; 38*0Sstevel@tonic-gate } _dtrace_sleeptab[] = { 39*0Sstevel@tonic-gate { DTRACEOPT_STATUSRATE, offsetof(dtrace_hdl_t, dt_laststatus) }, 40*0Sstevel@tonic-gate { DTRACEOPT_AGGRATE, offsetof(dtrace_hdl_t, dt_lastagg) }, 41*0Sstevel@tonic-gate { DTRACEOPT_SWITCHRATE, offsetof(dtrace_hdl_t, dt_lastswitch) }, 42*0Sstevel@tonic-gate { DTRACEOPT_MAX, 0 } 43*0Sstevel@tonic-gate }; 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate void 46*0Sstevel@tonic-gate dtrace_sleep(dtrace_hdl_t *dtp) 47*0Sstevel@tonic-gate { 48*0Sstevel@tonic-gate dt_proc_hash_t *dph = dtp->dt_procs; 49*0Sstevel@tonic-gate dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY]; 50*0Sstevel@tonic-gate dt_proc_t *dpr; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate hrtime_t earliest = INT64_MAX; 53*0Sstevel@tonic-gate struct timespec tv; 54*0Sstevel@tonic-gate hrtime_t now; 55*0Sstevel@tonic-gate int i; 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate for (i = 0; _dtrace_sleeptab[i].dtslt_option < DTRACEOPT_MAX; i++) { 58*0Sstevel@tonic-gate uintptr_t a = (uintptr_t)dtp + _dtrace_sleeptab[i].dtslt_offs; 59*0Sstevel@tonic-gate int opt = _dtrace_sleeptab[i].dtslt_option; 60*0Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[opt]; 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* 63*0Sstevel@tonic-gate * If the buffering policy is set to anything other than 64*0Sstevel@tonic-gate * "switch", we ignore the aggrate and switchrate -- they're 65*0Sstevel@tonic-gate * meaningless. 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate if (policy != DTRACEOPT_BUFPOLICY_SWITCH && 68*0Sstevel@tonic-gate _dtrace_sleeptab[i].dtslt_option != DTRACEOPT_STATUSRATE) 69*0Sstevel@tonic-gate continue; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate if (*((hrtime_t *)a) + interval < earliest) 72*0Sstevel@tonic-gate earliest = *((hrtime_t *)a) + interval; 73*0Sstevel@tonic-gate } 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate (void) pthread_mutex_lock(&dph->dph_lock); 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate now = gethrtime(); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate if (earliest < now) { 80*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&dph->dph_lock); 81*0Sstevel@tonic-gate return; /* sleep duration has already past */ 82*0Sstevel@tonic-gate } 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate tv.tv_sec = (earliest - now) / NANOSEC; 85*0Sstevel@tonic-gate tv.tv_nsec = (earliest - now) % NANOSEC; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /* 88*0Sstevel@tonic-gate * Wait for either 'tv' nanoseconds to pass or to receive notification 89*0Sstevel@tonic-gate * that a process is in an interesting state. Regardless of why we 90*0Sstevel@tonic-gate * awaken, iterate over any pending notifications and process them. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate (void) pthread_cond_reltimedwait_np(&dph->dph_cv, &dph->dph_lock, &tv); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate while ((dpr = dph->dph_notify) != NULL) { 95*0Sstevel@tonic-gate dph->dph_notify = dpr->dpr_notify; 96*0Sstevel@tonic-gate dpr->dpr_notify = NULL; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate if (dtp->dt_prochdlr != NULL) 99*0Sstevel@tonic-gate dtp->dt_prochdlr(dpr->dpr_proc, dtp->dt_procarg); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&dph->dph_lock); 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate int 106*0Sstevel@tonic-gate dtrace_status(dtrace_hdl_t *dtp) 107*0Sstevel@tonic-gate { 108*0Sstevel@tonic-gate int gen = dtp->dt_statusgen; 109*0Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_STATUSRATE]; 110*0Sstevel@tonic-gate hrtime_t now = gethrtime(); 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate if (!dtp->dt_active) 113*0Sstevel@tonic-gate return (DTRACE_STATUS_NONE); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate if (dtp->dt_stopped) 116*0Sstevel@tonic-gate return (DTRACE_STATUS_STOPPED); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate if (dtp->dt_laststatus != 0) { 119*0Sstevel@tonic-gate if (now - dtp->dt_laststatus < interval) 120*0Sstevel@tonic-gate return (DTRACE_STATUS_NONE); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate dtp->dt_laststatus += interval; 123*0Sstevel@tonic-gate } else { 124*0Sstevel@tonic-gate dtp->dt_laststatus = now; 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1) 128*0Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate dtp->dt_statusgen ^= 1; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate if (dt_handle_status(dtp, &dtp->dt_status[dtp->dt_statusgen], 133*0Sstevel@tonic-gate &dtp->dt_status[gen]) == -1) 134*0Sstevel@tonic-gate return (-1); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate if (dtp->dt_status[gen].dtst_exiting) { 137*0Sstevel@tonic-gate if (!dtp->dt_stopped) 138*0Sstevel@tonic-gate (void) dtrace_stop(dtp); 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate return (DTRACE_STATUS_EXITED); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate if (dtp->dt_status[gen].dtst_filled == 0) 144*0Sstevel@tonic-gate return (DTRACE_STATUS_OKAY); 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL) 147*0Sstevel@tonic-gate return (DTRACE_STATUS_OKAY); 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate if (!dtp->dt_stopped) { 150*0Sstevel@tonic-gate if (dtrace_stop(dtp) == -1) 151*0Sstevel@tonic-gate return (-1); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate return (DTRACE_STATUS_FILLED); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate dtrace_workstatus_t 158*0Sstevel@tonic-gate dtrace_work(dtrace_hdl_t *dtp, FILE *fp, 159*0Sstevel@tonic-gate dtrace_consume_probe_f *pfunc, dtrace_consume_rec_f *rfunc, void *arg) 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate int status = dtrace_status(dtp); 162*0Sstevel@tonic-gate dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY]; 163*0Sstevel@tonic-gate dtrace_workstatus_t rval; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate switch (status) { 166*0Sstevel@tonic-gate case DTRACE_STATUS_EXITED: 167*0Sstevel@tonic-gate case DTRACE_STATUS_FILLED: 168*0Sstevel@tonic-gate case DTRACE_STATUS_STOPPED: 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * Tracing is stopped. We now want to force dtrace_consume() 171*0Sstevel@tonic-gate * and dtrace_aggregate_snap() to proceed, regardless of 172*0Sstevel@tonic-gate * switchrate and aggrate. We do this by clearing the times. 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate dtp->dt_lastswitch = 0; 175*0Sstevel@tonic-gate dtp->dt_lastagg = 0; 176*0Sstevel@tonic-gate rval = DTRACE_WORKSTATUS_DONE; 177*0Sstevel@tonic-gate break; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate case DTRACE_STATUS_NONE: 180*0Sstevel@tonic-gate case DTRACE_STATUS_OKAY: 181*0Sstevel@tonic-gate rval = DTRACE_WORKSTATUS_OKAY; 182*0Sstevel@tonic-gate break; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate case -1: 185*0Sstevel@tonic-gate return (DTRACE_WORKSTATUS_ERROR); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate if ((status == DTRACE_STATUS_NONE || status == DTRACE_STATUS_OKAY) && 189*0Sstevel@tonic-gate policy != DTRACEOPT_BUFPOLICY_SWITCH) { 190*0Sstevel@tonic-gate /* 191*0Sstevel@tonic-gate * There either isn't any status or things are fine -- and 192*0Sstevel@tonic-gate * this is a "ring" or "fill" buffer. We don't want to consume 193*0Sstevel@tonic-gate * any of the trace data or snapshot the aggregations; we just 194*0Sstevel@tonic-gate * return. 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate assert(rval == DTRACE_WORKSTATUS_OKAY); 197*0Sstevel@tonic-gate return (rval); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate if (dtrace_aggregate_snap(dtp) == -1) 201*0Sstevel@tonic-gate return (DTRACE_WORKSTATUS_ERROR); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (dtrace_consume(dtp, fp, pfunc, rfunc, arg) == -1) 204*0Sstevel@tonic-gate return (DTRACE_WORKSTATUS_ERROR); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate return (rval); 207*0Sstevel@tonic-gate } 208