Deleted Added
full compact
21c21
< * $FreeBSD: head/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c 248752 2013-03-26 20:17:08Z pfg $
---
> * $FreeBSD: head/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c 248983 2013-04-01 19:13:46Z pfg $
184a185
> hrtime_t dtrace_unregister_defunct_reap = (hrtime_t)60 * NANOSEC;
206d206
< static taskq_t *dtrace_taskq; /* task queue */
207a208
> static taskq_t *dtrace_taskq; /* task queue */
552a554
> static void dtrace_enabling_reap(void);
557a560
> static int dtrace_buffer_consumed(dtrace_buffer_t *, hrtime_t when);
7596c7599
< int i, self = 0;
---
> int i, self = 0, noreap = 0;
7655c7658,7664
< * We have at least one ECB; we can't remove this provider.
---
> * If we are trying to unregister a defunct provider, and the
> * provider was made defunct within the interval dictated by
> * dtrace_unregister_defunct_reap, we'll (asynchronously)
> * attempt to reap our enablings. To denote that the provider
> * should reattempt to unregister itself at some point in the
> * future, we will return a differentiable error code (EAGAIN
> * instead of EBUSY) in this case.
7656a7666,7669
> if (dtrace_gethrtime() - old->dtpv_defunct >
> dtrace_unregister_defunct_reap)
> noreap = 1;
>
7662c7675,7682
< return (EBUSY);
---
>
> if (noreap)
> return (EBUSY);
>
> (void) taskq_dispatch(dtrace_taskq,
> (task_func_t *)dtrace_enabling_reap, NULL, TQ_SLEEP);
>
> return (EAGAIN);
7759c7779
< pvp->dtpv_defunct = 1;
---
> pvp->dtpv_defunct = dtrace_gethrtime();
10721a10742
> hrtime_t now = dtrace_gethrtime();
10736a10758,10759
> buf->dtb_interval = now - buf->dtb_switched;
> buf->dtb_switched = now;
11224a11248,11277
> /*
> * This routine determines if data generated at the specified time has likely
> * been entirely consumed at user-level. This routine is called to determine
> * if an ECB on a defunct probe (but for an active enabling) can be safely
> * disabled and destroyed.
> */
> static int
> dtrace_buffer_consumed(dtrace_buffer_t *bufs, hrtime_t when)
> {
> int i;
>
> for (i = 0; i < NCPU; i++) {
> dtrace_buffer_t *buf = &bufs[i];
>
> if (buf->dtb_size == 0)
> continue;
>
> if (buf->dtb_flags & DTRACEBUF_RING)
> return (0);
>
> if (!buf->dtb_switched && buf->dtb_offset != 0)
> return (0);
>
> if (buf->dtb_switched - buf->dtb_interval < when)
> return (0);
> }
>
> return (1);
> }
>
11695a11749,11827
> * Called to reap ECBs that are attached to probes from defunct providers.
> */
> static void
> dtrace_enabling_reap(void)
> {
> dtrace_provider_t *prov;
> dtrace_probe_t *probe;
> dtrace_ecb_t *ecb;
> hrtime_t when;
> int i;
>
> mutex_enter(&cpu_lock);
> mutex_enter(&dtrace_lock);
>
> for (i = 0; i < dtrace_nprobes; i++) {
> if ((probe = dtrace_probes[i]) == NULL)
> continue;
>
> if (probe->dtpr_ecb == NULL)
> continue;
>
> prov = probe->dtpr_provider;
>
> if ((when = prov->dtpv_defunct) == 0)
> continue;
>
> /*
> * We have ECBs on a defunct provider: we want to reap these
> * ECBs to allow the provider to unregister. The destruction
> * of these ECBs must be done carefully: if we destroy the ECB
> * and the consumer later wishes to consume an EPID that
> * corresponds to the destroyed ECB (and if the EPID metadata
> * has not been previously consumed), the consumer will abort
> * processing on the unknown EPID. To reduce (but not, sadly,
> * eliminate) the possibility of this, we will only destroy an
> * ECB for a defunct provider if, for the state that
> * corresponds to the ECB:
> *
> * (a) There is no speculative tracing (which can effectively
> * cache an EPID for an arbitrary amount of time).
> *
> * (b) The principal buffers have been switched twice since the
> * provider became defunct.
> *
> * (c) The aggregation buffers are of zero size or have been
> * switched twice since the provider became defunct.
> *
> * We use dts_speculates to determine (a) and call a function
> * (dtrace_buffer_consumed()) to determine (b) and (c). Note
> * that as soon as we've been unable to destroy one of the ECBs
> * associated with the probe, we quit trying -- reaping is only
> * fruitful in as much as we can destroy all ECBs associated
> * with the defunct provider's probes.
> */
> while ((ecb = probe->dtpr_ecb) != NULL) {
> dtrace_state_t *state = ecb->dte_state;
> dtrace_buffer_t *buf = state->dts_buffer;
> dtrace_buffer_t *aggbuf = state->dts_aggbuffer;
>
> if (state->dts_speculates)
> break;
>
> if (!dtrace_buffer_consumed(buf, when))
> break;
>
> if (!dtrace_buffer_consumed(aggbuf, when))
> break;
>
> dtrace_ecb_disable(ecb);
> ASSERT(probe->dtpr_ecb != ecb);
> dtrace_ecb_destroy(ecb);
> }
> }
>
> mutex_exit(&dtrace_lock);
> mutex_exit(&cpu_lock);
> }
>
> /*
15531a15664,15667
> /* This code actually belongs in dtrace_attach() */
> if (dtrace_opens == 1)
> dtrace_taskq = taskq_create("dtrace_taskq", 1, maxclsyspri,
> 1, INT_MAX, 0);
15618a15755,15759
> /* This code actually belongs in dtrace_detach() */
> if ((dtrace_opens == 0) && (dtrace_taskq != NULL)) {
> taskq_destroy(dtrace_taskq);
> dtrace_taskq = NULL;
> }