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
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.
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]
24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #pragma ident "%Z%%M% %I% %E% SMI"
39 } _dtrace_sleeptab
[] = {
40 { DTRACEOPT_STATUSRATE
, offsetof(dtrace_hdl_t
, dt_laststatus
) },
41 { DTRACEOPT_AGGRATE
, offsetof(dtrace_hdl_t
, dt_lastagg
) },
42 { DTRACEOPT_SWITCHRATE
, offsetof(dtrace_hdl_t
, dt_lastswitch
) },
47 dtrace_sleep(dtrace_hdl_t
*dtp
)
49 dt_proc_hash_t
*dph
= dtp
->dt_procs
;
50 dtrace_optval_t policy
= dtp
->dt_options
[DTRACEOPT_BUFPOLICY
];
51 dt_proc_notify_t
*dprn
;
53 hrtime_t earliest
= INT64_MAX
;
58 for (i
= 0; _dtrace_sleeptab
[i
].dtslt_option
< DTRACEOPT_MAX
; i
++) {
59 uintptr_t a
= (uintptr_t)dtp
+ _dtrace_sleeptab
[i
].dtslt_offs
;
60 int opt
= _dtrace_sleeptab
[i
].dtslt_option
;
61 dtrace_optval_t interval
= dtp
->dt_options
[opt
];
64 * If the buffering policy is set to anything other than
65 * "switch", we ignore the aggrate and switchrate -- they're
68 if (policy
!= DTRACEOPT_BUFPOLICY_SWITCH
&&
69 _dtrace_sleeptab
[i
].dtslt_option
!= DTRACEOPT_STATUSRATE
)
72 if (*((hrtime_t
*)a
) + interval
< earliest
)
73 earliest
= *((hrtime_t
*)a
) + interval
;
76 (void) pthread_mutex_lock(&dph
->dph_lock
);
81 (void) pthread_mutex_unlock(&dph
->dph_lock
);
82 return; /* sleep duration has already past */
85 tv
.tv_sec
= (earliest
- now
) / NANOSEC
;
86 tv
.tv_nsec
= (earliest
- now
) % NANOSEC
;
89 * Wait for either 'tv' nanoseconds to pass or to receive notification
90 * that a process is in an interesting state. Regardless of why we
91 * awaken, iterate over any pending notifications and process them.
93 (void) pthread_cond_reltimedwait_np(&dph
->dph_cv
, &dph
->dph_lock
, &tv
);
95 while ((dprn
= dph
->dph_notify
) != NULL
) {
96 if (dtp
->dt_prochdlr
!= NULL
) {
97 char *err
= dprn
->dprn_errmsg
;
101 dtp
->dt_prochdlr(dprn
->dprn_dpr
->dpr_proc
, err
,
105 dph
->dph_notify
= dprn
->dprn_next
;
109 (void) pthread_mutex_unlock(&dph
->dph_lock
);
113 dtrace_status(dtrace_hdl_t
*dtp
)
115 int gen
= dtp
->dt_statusgen
;
116 dtrace_optval_t interval
= dtp
->dt_options
[DTRACEOPT_STATUSRATE
];
117 hrtime_t now
= gethrtime();
120 return (DTRACE_STATUS_NONE
);
123 return (DTRACE_STATUS_STOPPED
);
125 if (dtp
->dt_laststatus
!= 0) {
126 if (now
- dtp
->dt_laststatus
< interval
)
127 return (DTRACE_STATUS_NONE
);
129 dtp
->dt_laststatus
+= interval
;
131 dtp
->dt_laststatus
= now
;
134 if (dt_ioctl(dtp
, DTRACEIOC_STATUS
, &dtp
->dt_status
[gen
]) == -1)
135 return (dt_set_errno(dtp
, errno
));
137 dtp
->dt_statusgen
^= 1;
139 if (dt_handle_status(dtp
, &dtp
->dt_status
[dtp
->dt_statusgen
],
140 &dtp
->dt_status
[gen
]) == -1)
143 if (dtp
->dt_status
[gen
].dtst_exiting
) {
144 if (!dtp
->dt_stopped
)
145 (void) dtrace_stop(dtp
);
147 return (DTRACE_STATUS_EXITED
);
150 if (dtp
->dt_status
[gen
].dtst_filled
== 0)
151 return (DTRACE_STATUS_OKAY
);
153 if (dtp
->dt_options
[DTRACEOPT_BUFPOLICY
] != DTRACEOPT_BUFPOLICY_FILL
)
154 return (DTRACE_STATUS_OKAY
);
156 if (!dtp
->dt_stopped
) {
157 if (dtrace_stop(dtp
) == -1)
161 return (DTRACE_STATUS_FILLED
);
165 dtrace_go(dtrace_hdl_t
*dtp
)
171 return (dt_set_errno(dtp
, EINVAL
));
174 * If a dtrace:::ERROR program and callback are registered, enable the
175 * program before we start tracing. If this fails for a vector open
176 * with ENOTTY, we permit dtrace_go() to succeed so that vector clients
177 * such as mdb's dtrace module can execute the rest of dtrace_go() even
178 * though they do not provide support for the DTRACEIOC_ENABLE ioctl.
180 if (dtp
->dt_errprog
!= NULL
&&
181 dtrace_program_exec(dtp
, dtp
->dt_errprog
, NULL
) == -1 && (
182 dtp
->dt_errno
!= ENOTTY
|| dtp
->dt_vector
== NULL
))
183 return (-1); /* dt_errno has been set for us */
185 if ((dof
= dtrace_getopt_dof(dtp
)) == NULL
)
186 return (-1); /* dt_errno has been set for us */
188 err
= dt_ioctl(dtp
, DTRACEIOC_ENABLE
, dof
);
189 dtrace_dof_destroy(dtp
, dof
);
191 if (err
== -1 && (errno
!= ENOTTY
|| dtp
->dt_vector
== NULL
))
192 return (dt_set_errno(dtp
, errno
));
194 if (dt_ioctl(dtp
, DTRACEIOC_GO
, &dtp
->dt_beganon
) == -1) {
196 return (dt_set_errno(dtp
, EDT_DESTRUCTIVE
));
198 if (errno
== EALREADY
)
199 return (dt_set_errno(dtp
, EDT_ISANON
));
202 return (dt_set_errno(dtp
, EDT_NOANON
));
205 return (dt_set_errno(dtp
, EDT_ENDTOOBIG
));
208 return (dt_set_errno(dtp
, EDT_BUFTOOSMALL
));
210 return (dt_set_errno(dtp
, errno
));
215 if (dt_options_load(dtp
) == -1)
216 return (dt_set_errno(dtp
, errno
));
218 return (dt_aggregate_go(dtp
));
222 dtrace_stop(dtrace_hdl_t
*dtp
)
224 int gen
= dtp
->dt_statusgen
;
229 if (dt_ioctl(dtp
, DTRACEIOC_STOP
, &dtp
->dt_endedon
) == -1)
230 return (dt_set_errno(dtp
, errno
));
235 * Now that we're stopped, we're going to get status one final time.
237 if (dt_ioctl(dtp
, DTRACEIOC_STATUS
, &dtp
->dt_status
[gen
]) == -1)
238 return (dt_set_errno(dtp
, errno
));
240 if (dt_handle_status(dtp
, &dtp
->dt_status
[gen
^ 1],
241 &dtp
->dt_status
[gen
]) == -1)
249 dtrace_work(dtrace_hdl_t
*dtp
, FILE *fp
,
250 dtrace_consume_probe_f
*pfunc
, dtrace_consume_rec_f
*rfunc
, void *arg
)
252 int status
= dtrace_status(dtp
);
253 dtrace_optval_t policy
= dtp
->dt_options
[DTRACEOPT_BUFPOLICY
];
254 dtrace_workstatus_t rval
;
257 case DTRACE_STATUS_EXITED
:
258 case DTRACE_STATUS_FILLED
:
259 case DTRACE_STATUS_STOPPED
:
261 * Tracing is stopped. We now want to force dtrace_consume()
262 * and dtrace_aggregate_snap() to proceed, regardless of
263 * switchrate and aggrate. We do this by clearing the times.
265 dtp
->dt_lastswitch
= 0;
267 rval
= DTRACE_WORKSTATUS_DONE
;
270 case DTRACE_STATUS_NONE
:
271 case DTRACE_STATUS_OKAY
:
272 rval
= DTRACE_WORKSTATUS_OKAY
;
276 return (DTRACE_WORKSTATUS_ERROR
);
279 if ((status
== DTRACE_STATUS_NONE
|| status
== DTRACE_STATUS_OKAY
) &&
280 policy
!= DTRACEOPT_BUFPOLICY_SWITCH
) {
282 * There either isn't any status or things are fine -- and
283 * this is a "ring" or "fill" buffer. We don't want to consume
284 * any of the trace data or snapshot the aggregations; we just
287 assert(rval
== DTRACE_WORKSTATUS_OKAY
);
291 if (dtrace_aggregate_snap(dtp
) == -1)
292 return (DTRACE_WORKSTATUS_ERROR
);
294 if (dtrace_consume(dtp
, fp
, pfunc
, rfunc
, arg
) == -1)
295 return (DTRACE_WORKSTATUS_ERROR
);