4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 * Portions Copyright (c) 2008-2009 Stacey Son <sson@FreeBSD.org>
28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
32 #include "opt_kdtrace.h"
34 #include <sys/cdefs.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/limits.h>
41 #include <sys/linker.h>
42 #include <sys/module.h>
43 #include <sys/mutex.h>
45 #include <sys/dtrace.h>
46 #include <sys/lockstat.h>
48 #if defined(__i386__) || defined(__amd64__) || \
49 defined(__mips__) || defined(__powerpc__)
50 #define LOCKSTAT_AFRAMES 1
52 #error "architecture not supported"
55 static d_open_t lockstat_open;
56 static void lockstat_provide(void *, dtrace_probedesc_t *);
57 static void lockstat_destroy(void *, dtrace_id_t, void *);
58 static void lockstat_enable(void *, dtrace_id_t, void *);
59 static void lockstat_disable(void *, dtrace_id_t, void *);
60 static void lockstat_load(void *);
61 static int lockstat_unload(void);
64 typedef struct lockstat_probe {
75 lockstat_probe_t lockstat_probes[] =
78 { LS_MTX_SPIN_LOCK, LSS_ACQUIRE, LS_MTX_SPIN_LOCK_ACQUIRE,
79 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
80 { LS_MTX_SPIN_LOCK, LSS_SPIN, LS_MTX_SPIN_LOCK_SPIN,
81 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
82 { LS_MTX_SPIN_UNLOCK, LSS_RELEASE, LS_MTX_SPIN_UNLOCK_RELEASE,
83 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
85 { LS_MTX_LOCK, LSA_ACQUIRE, LS_MTX_LOCK_ACQUIRE,
86 DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
87 { LS_MTX_LOCK, LSA_BLOCK, LS_MTX_LOCK_BLOCK,
88 DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
89 { LS_MTX_LOCK, LSA_SPIN, LS_MTX_LOCK_SPIN,
90 DTRACE_IDNONE, (LOCKSTAT_AFRAMES + 1) },
91 { LS_MTX_UNLOCK, LSA_RELEASE, LS_MTX_UNLOCK_RELEASE,
92 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
93 { LS_MTX_TRYLOCK, LSA_ACQUIRE, LS_MTX_TRYLOCK_ACQUIRE,
94 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
95 /* Reader/Writer Locks */
96 { LS_RW_RLOCK, LSR_ACQUIRE, LS_RW_RLOCK_ACQUIRE,
97 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
98 { LS_RW_RLOCK, LSR_BLOCK, LS_RW_RLOCK_BLOCK,
99 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
100 { LS_RW_RLOCK, LSR_SPIN, LS_RW_RLOCK_SPIN,
101 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
102 { LS_RW_RUNLOCK, LSR_RELEASE, LS_RW_RUNLOCK_RELEASE,
103 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
104 { LS_RW_WLOCK, LSR_ACQUIRE, LS_RW_WLOCK_ACQUIRE,
105 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
106 { LS_RW_WLOCK, LSR_BLOCK, LS_RW_WLOCK_BLOCK,
107 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
108 { LS_RW_WLOCK, LSR_SPIN, LS_RW_WLOCK_SPIN,
109 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
110 { LS_RW_WUNLOCK, LSR_RELEASE, LS_RW_WUNLOCK_RELEASE,
111 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
112 { LS_RW_TRYUPGRADE, LSR_UPGRADE, LS_RW_TRYUPGRADE_UPGRADE,
113 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
114 { LS_RW_DOWNGRADE, LSR_DOWNGRADE, LS_RW_DOWNGRADE_DOWNGRADE,
115 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
116 /* Shared/Exclusive Locks */
117 { LS_SX_SLOCK, LSX_ACQUIRE, LS_SX_SLOCK_ACQUIRE,
118 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
119 { LS_SX_SLOCK, LSX_BLOCK, LS_SX_SLOCK_BLOCK,
120 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
121 { LS_SX_SLOCK, LSX_SPIN, LS_SX_SLOCK_SPIN,
122 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
123 { LS_SX_SUNLOCK, LSX_RELEASE, LS_SX_SUNLOCK_RELEASE,
124 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
125 { LS_SX_XLOCK, LSX_ACQUIRE, LS_SX_XLOCK_ACQUIRE,
126 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
127 { LS_SX_XLOCK, LSX_BLOCK, LS_SX_XLOCK_BLOCK,
128 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
129 { LS_SX_XLOCK, LSX_SPIN, LS_SX_XLOCK_SPIN,
130 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
131 { LS_SX_XUNLOCK, LSX_RELEASE, LS_SX_XUNLOCK_RELEASE,
132 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
133 { LS_SX_TRYUPGRADE, LSX_UPGRADE, LS_SX_TRYUPGRADE_UPGRADE,
134 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
135 { LS_SX_DOWNGRADE, LSX_DOWNGRADE, LS_SX_DOWNGRADE_DOWNGRADE,
136 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
138 { LS_THREAD_LOCK, LST_SPIN, LS_THREAD_LOCK_SPIN,
139 DTRACE_IDNONE, LOCKSTAT_AFRAMES },
143 #error "OS not supported"
147 static struct cdevsw lockstat_cdevsw = {
148 .d_version = D_VERSION,
149 .d_open = lockstat_open,
150 .d_name = "lockstat",
153 static struct cdev *lockstat_cdev;
154 static dtrace_provider_id_t lockstat_id;
158 lockstat_enable(void *arg, dtrace_id_t id, void *parg)
160 lockstat_probe_t *probe = parg;
162 ASSERT(!lockstat_probemap[probe->lsp_probe]);
166 lockstat_probemap[probe->lsp_probe] = id;
171 lockstat_probe_func = dtrace_probe;
175 lockstat_hot_patch();
182 lockstat_disable(void *arg, dtrace_id_t id, void *parg)
184 lockstat_probe_t *probe = parg;
187 ASSERT(lockstat_probemap[probe->lsp_probe]);
191 lockstat_probemap[probe->lsp_probe] = 0;
193 lockstat_hot_patch();
198 * See if we have any probes left enabled.
200 for (i = 0; i < LS_NPROBES; i++) {
201 if (lockstat_probemap[i]) {
203 * This probe is still enabled. We don't need to deal
204 * with waiting for all threads to be out of the
205 * lockstat critical sections; just return.
215 lockstat_open(struct cdev *dev __unused, int oflags __unused,
216 int devtype __unused, struct thread *td __unused)
223 lockstat_provide(void *arg, dtrace_probedesc_t *desc)
227 for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) {
228 lockstat_probe_t *probe = &lockstat_probes[i];
230 if (dtrace_probe_lookup(lockstat_id, "kernel",
231 probe->lsp_func, probe->lsp_name) != 0)
234 ASSERT(!probe->lsp_id);
236 probe->lsp_id = dtrace_probe_create(lockstat_id,
237 "kernel", probe->lsp_func, probe->lsp_name,
238 probe->lsp_frame, probe);
240 probe->lsp_id = dtrace_probe_create(lockstat_id,
241 "kernel", probe->lsp_func, probe->lsp_name,
242 LOCKSTAT_AFRAMES, probe);
249 lockstat_destroy(void *arg, dtrace_id_t id, void *parg)
251 lockstat_probe_t *probe = parg;
253 ASSERT(!lockstat_probemap[probe->lsp_probe]);
257 static dtrace_pattr_t lockstat_attr = {
258 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
259 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
260 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
261 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
262 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
265 static dtrace_pops_t lockstat_pops = {
279 lockstat_load(void *dummy)
281 /* Create the /dev/dtrace/lockstat entry. */
282 lockstat_cdev = make_dev(&lockstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
285 if (dtrace_register("lockstat", &lockstat_attr, DTRACE_PRIV_USER,
286 NULL, &lockstat_pops, NULL, &lockstat_id) != 0)
295 if ((error = dtrace_unregister(lockstat_id)) != 0)
298 destroy_dev(lockstat_cdev);
305 lockstat_modevent(module_t mod __unused, int type, void *data __unused)
326 SYSINIT(lockstat_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_load, NULL);
327 SYSUNINIT(lockstat_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_unload, NULL);
329 DEV_MODULE(lockstat, lockstat_modevent, NULL);
330 MODULE_VERSION(lockstat, 1);
331 MODULE_DEPEND(lockstat, dtrace, 1, 1, 1);
332 MODULE_DEPEND(lockstat, opensolaris, 1, 1, 1);