Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 Apr 2006 22:01:10 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 95732 for review
Message-ID:  <200604202201.k3KM1AxJ027925@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=95732

Change 95732 by jb@jb_freebsd2 on 2006/04/20 22:00:17

	In the spirit of keeping Sun's functions grouped the way that they did,
	add the other registration functions to this file.
	
	I'm leaving CDDL copyright off these files for the time being so that
	I can cat the files together to diff them against Sun's dtrace.c

Affected files ...

.. //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_register.c#2 edit

Differences ...

==== //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_register.c#2 (text+ko) ====

@@ -1,25 +1,11 @@
+
 /*
- * CDDL HEADER START
+ * DTrace Provider-to-Framework API Functions
  *
- * 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
- *
- * $FreeBSD$
- *
+ * These functions implement much of the Provider-to-Framework API, as
+ * described in <sys/dtrace.h>.  The parts of the API not in this section are
+ * the functions in the API for probe management (found below), and
+ * dtrace_probe() itself (found above).
  */
 
 /*
@@ -77,14 +63,12 @@
 		return (EINVAL);
 	}
 
-	/* The caller has probably obtained locks, so use M_NOWAIT here. */
-	provider = malloc(sizeof (dtrace_provider_t), M_DTRACE, M_NOWAIT | M_ZERO);
-	provider->dtpv_name = malloc(strlen(name) + 1, M_DTRACE, M_NOWAIT | M_ZERO);
+	provider = kmem_zalloc(sizeof (dtrace_provider_t), KM_SLEEP);
+	provider->dtpv_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
 	(void) strcpy(provider->dtpv_name, name);
 
 	provider->dtpv_attr = *pap;
 	provider->dtpv_priv.dtpp_flags = priv;
-#ifdef DOODAD
 	if (cr != NULL) {
 		provider->dtpv_priv.dtpp_uid = crgetuid(cr);
 		provider->dtpv_priv.dtpp_zoneid = crgetzoneid(cr);
@@ -127,10 +111,9 @@
 		dtrace_provider = provider;
 		return (0);
 	}
-#endif
 
-	mtx_lock(&dtrace_provider_lock);
-	mtx_lock(&dtrace_lock);
+	mutex_enter(&dtrace_provider_lock);
+	mutex_enter(&dtrace_lock);
 
 	/*
 	 * If there is at least one provider registered, we'll add this
@@ -143,7 +126,6 @@
 		dtrace_provider = provider;
 	}
 
-#ifdef DOODAD
 	if (dtrace_retained != NULL) {
 		dtrace_enabling_provide(provider);
 
@@ -158,11 +140,248 @@
 
 		return (0);
 	}
-#endif
+
+	mutex_exit(&dtrace_lock);
+	mutex_exit(&dtrace_provider_lock);
+
+	return (0);
+}
+
+/*
+ * Unregister the specified provider from the DTrace framework.  This should
+ * generally be called by DTrace providers in their detach(9E) entry point.
+ */
+int
+dtrace_unregister(dtrace_provider_id_t id)
+{
+	dtrace_provider_t *old = (dtrace_provider_t *)id;
+	dtrace_provider_t *prev = NULL;
+	int i, self = 0;
+	dtrace_probe_t *probe, *first = NULL;
+
+	if (old->dtpv_pops.dtps_enable ==
+	    (void (*)(void *, dtrace_id_t, void *))dtrace_nullop) {
+		/*
+		 * If DTrace itself is the provider, we're called with locks
+		 * already held.
+		 */
+		ASSERT(old == dtrace_provider);
+		ASSERT(dtrace_devi != NULL);
+		ASSERT(MUTEX_HELD(&dtrace_provider_lock));
+		ASSERT(MUTEX_HELD(&dtrace_lock));
+		self = 1;
+
+		if (dtrace_provider->dtpv_next != NULL) {
+			/*
+			 * There's another provider here; return failure.
+			 */
+			return (EBUSY);
+		}
+	} else {
+		mutex_enter(&dtrace_provider_lock);
+		mutex_enter(&mod_lock);
+		mutex_enter(&dtrace_lock);
+	}
+
+	/*
+	 * If anyone has /dev/dtrace open, or if there are anonymous enabled
+	 * probes, we refuse to let providers slither away, unless this
+	 * provider has already been explicitly invalidated.
+	 */
+	if (!old->dtpv_defunct &&
+	    (dtrace_opens || (dtrace_anon.dta_state != NULL &&
+	    dtrace_anon.dta_state->dts_necbs > 0))) {
+		if (!self) {
+			mutex_exit(&dtrace_lock);
+			mutex_exit(&mod_lock);
+			mutex_exit(&dtrace_provider_lock);
+		}
+		return (EBUSY);
+	}
+
+	/*
+	 * Attempt to destroy the probes associated with this provider.
+	 */
+	for (i = 0; i < dtrace_nprobes; i++) {
+		if ((probe = dtrace_probes[i]) == NULL)
+			continue;
+
+		if (probe->dtpr_provider != old)
+			continue;
+
+		if (probe->dtpr_ecb == NULL)
+			continue;
+
+		/*
+		 * We have at least one ECB; we can't remove this provider.
+		 */
+		if (!self) {
+			mutex_exit(&dtrace_lock);
+			mutex_exit(&mod_lock);
+			mutex_exit(&dtrace_provider_lock);
+		}
+		return (EBUSY);
+	}
+
+	/*
+	 * All of the probes for this provider are disabled; we can safely
+	 * remove all of them from their hash chains and from the probe array.
+	 */
+	for (i = 0; i < dtrace_nprobes; i++) {
+		if ((probe = dtrace_probes[i]) == NULL)
+			continue;
+
+		if (probe->dtpr_provider != old)
+			continue;
+
+		dtrace_probes[i] = NULL;
+
+		dtrace_hash_remove(dtrace_bymod, probe);
+		dtrace_hash_remove(dtrace_byfunc, probe);
+		dtrace_hash_remove(dtrace_byname, probe);
+
+		if (first == NULL) {
+			first = probe;
+			probe->dtpr_nextmod = NULL;
+		} else {
+			probe->dtpr_nextmod = first;
+			first = probe;
+		}
+	}
+
+	/*
+	 * The provider's probes have been removed from the hash chains and
+	 * from the probe array.  Now issue a dtrace_sync() to be sure that
+	 * everyone has cleared out from any probe array processing.
+	 */
+	dtrace_sync();
+
+	for (probe = first; probe != NULL; probe = first) {
+		first = probe->dtpr_nextmod;
+
+		old->dtpv_pops.dtps_destroy(old->dtpv_arg, probe->dtpr_id,
+		    probe->dtpr_arg);
+		kmem_free(probe->dtpr_mod, strlen(probe->dtpr_mod) + 1);
+		kmem_free(probe->dtpr_func, strlen(probe->dtpr_func) + 1);
+		kmem_free(probe->dtpr_name, strlen(probe->dtpr_name) + 1);
+		vmem_free(dtrace_arena, (void *)(uintptr_t)(probe->dtpr_id), 1);
+		kmem_free(probe, sizeof (dtrace_probe_t));
+	}
+
+	if ((prev = dtrace_provider) == old) {
+		ASSERT(self || dtrace_devi == NULL);
+		ASSERT(old->dtpv_next == NULL || dtrace_devi == NULL);
+		dtrace_provider = old->dtpv_next;
+	} else {
+		while (prev != NULL && prev->dtpv_next != old)
+			prev = prev->dtpv_next;
+
+		if (prev == NULL) {
+			panic("attempt to unregister non-existent "
+			    "dtrace provider %p\n", (void *)id);
+		}
+
+		prev->dtpv_next = old->dtpv_next;
+	}
+
+	if (!self) {
+		mutex_exit(&dtrace_lock);
+		mutex_exit(&mod_lock);
+		mutex_exit(&dtrace_provider_lock);
+	}
+
+	kmem_free(old->dtpv_name, strlen(old->dtpv_name) + 1);
+	kmem_free(old, sizeof (dtrace_provider_t));
+
+	return (0);
+}
+
+/*
+ * Invalidate the specified provider.  All subsequent probe lookups for the
+ * specified provider will fail, but its probes will not be removed.
+ */
+void
+dtrace_invalidate(dtrace_provider_id_t id)
+{
+	dtrace_provider_t *pvp = (dtrace_provider_t *)id;
+
+	ASSERT(pvp->dtpv_pops.dtps_enable !=
+	    (void (*)(void *, dtrace_id_t, void *))dtrace_nullop);
+
+	mutex_enter(&dtrace_provider_lock);
+	mutex_enter(&dtrace_lock);
+
+	pvp->dtpv_defunct = 1;
+
+	mutex_exit(&dtrace_lock);
+	mutex_exit(&dtrace_provider_lock);
+}
+
+/*
+ * Indicate whether or not DTrace has attached.
+ */
+int
+dtrace_attached(void)
+{
+	/*
+	 * dtrace_provider will be non-NULL iff the DTrace driver has
+	 * attached.  (It's non-NULL because DTrace is always itself a
+	 * provider.)
+	 */
+	return (dtrace_provider != NULL);
+}
+
+/*
+ * Remove all the unenabled probes for the given provider.  This function is
+ * not unlike dtrace_unregister(), except that it doesn't remove the provider
+ * -- just as many of its associated probes as it can.
+ */
+int
+dtrace_condense(dtrace_provider_id_t id)
+{
+	dtrace_provider_t *prov = (dtrace_provider_t *)id;
+	int i;
+	dtrace_probe_t *probe;
+
+	/*
+	 * Make sure this isn't the dtrace provider itself.
+	 */
+	ASSERT(prov->dtpv_pops.dtps_enable !=
+	    (void (*)(void *, dtrace_id_t, void *))dtrace_nullop);
+
+	mutex_enter(&dtrace_provider_lock);
+	mutex_enter(&dtrace_lock);
+
+	/*
+	 * Attempt to destroy the probes associated with this provider.
+	 */
+	for (i = 0; i < dtrace_nprobes; i++) {
+		if ((probe = dtrace_probes[i]) == NULL)
+			continue;
+
+		if (probe->dtpr_provider != prov)
+			continue;
+
+		if (probe->dtpr_ecb != NULL)
+			continue;
+
+		dtrace_probes[i] = NULL;
+
+		dtrace_hash_remove(dtrace_bymod, probe);
+		dtrace_hash_remove(dtrace_byfunc, probe);
+		dtrace_hash_remove(dtrace_byname, probe);
+
+		prov->dtpv_pops.dtps_destroy(prov->dtpv_arg, i + 1,
+		    probe->dtpr_arg);
+		kmem_free(probe->dtpr_mod, strlen(probe->dtpr_mod) + 1);
+		kmem_free(probe->dtpr_func, strlen(probe->dtpr_func) + 1);
+		kmem_free(probe->dtpr_name, strlen(probe->dtpr_name) + 1);
+		kmem_free(probe, sizeof (dtrace_probe_t));
+		vmem_free(dtrace_arena, (void *)((uintptr_t)i + 1), 1);
+	}
 
-	mtx_unlock(&dtrace_lock);
-	mtx_unlock(&dtrace_provider_lock);
-printf("dtrace_register: name '%s'\n",name);
+	mutex_exit(&dtrace_lock);
+	mutex_exit(&dtrace_provider_lock);
 
 	return (0);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200604202201.k3KM1AxJ027925>