]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/cddl/dev/lockstat/lockstat.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / cddl / dev / lockstat / lockstat.c
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  *
21  * Portions Copyright (c) 2008 Stacey Son <stacey@son.org> 
22  *
23  * $FreeBSD$
24  *
25  */
26
27 /*
28  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
29  * Use is subject to license terms.
30  */
31
32 #define KDTRACE_HOOKS
33
34 #include <sys/cdefs.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/kernel.h>
39 #include <sys/limits.h>
40 #include <sys/lock.h>
41 #include <sys/linker.h>
42 #include <sys/module.h>
43 #include <sys/mutex.h>
44
45 #include <sys/dtrace.h>
46 #include <sys/lockstat.h>
47
48 #if defined(__i386__) || defined(__amd64__)
49 #define LOCKSTAT_AFRAMES 1
50 #else
51 #error "architecture not supported"
52 #endif
53
54 static d_open_t lockstat_open;
55 static void     lockstat_provide(void *, dtrace_probedesc_t *);
56 static void     lockstat_destroy(void *, dtrace_id_t, void *);
57 static void     lockstat_enable(void *, dtrace_id_t, void *);
58 static void     lockstat_disable(void *, dtrace_id_t, void *);
59 static void     lockstat_load(void *);
60 static int      lockstat_unload(void);
61
62
63 typedef struct lockstat_probe {
64         char            *lsp_func;
65         char            *lsp_name;
66         int             lsp_probe;
67         dtrace_id_t     lsp_id;
68 } lockstat_probe_t;
69
70 #ifdef __FreeBSD__
71 lockstat_probe_t lockstat_probes[] =
72 {
73   /* Spin Locks */
74   { LS_MTX_SPIN_LOCK,   LSS_ACQUIRE,    LS_MTX_SPIN_LOCK_ACQUIRE,   DTRACE_IDNONE },
75   { LS_MTX_SPIN_LOCK,   LSS_SPIN,       LS_MTX_SPIN_LOCK_SPIN,      DTRACE_IDNONE },
76   { LS_MTX_SPIN_UNLOCK, LSS_RELEASE,    LS_MTX_SPIN_UNLOCK_RELEASE, DTRACE_IDNONE },
77   /* Adaptive Locks */
78   { LS_MTX_LOCK,        LSA_ACQUIRE,    LS_MTX_LOCK_ACQUIRE,        DTRACE_IDNONE },
79   { LS_MTX_LOCK,        LSA_BLOCK,      LS_MTX_LOCK_BLOCK,          DTRACE_IDNONE },
80   { LS_MTX_LOCK,        LSA_SPIN,       LS_MTX_LOCK_SPIN,           DTRACE_IDNONE },
81   { LS_MTX_UNLOCK,      LSA_RELEASE,    LS_MTX_UNLOCK_RELEASE,      DTRACE_IDNONE },
82   { LS_MTX_TRYLOCK,     LSA_ACQUIRE,    LS_MTX_TRYLOCK_ACQUIRE,     DTRACE_IDNONE },
83   /* Reader/Writer Locks */
84   { LS_RW_RLOCK,        LSR_ACQUIRE,    LS_RW_RLOCK_ACQUIRE,        DTRACE_IDNONE },
85   { LS_RW_RLOCK,        LSR_BLOCK,      LS_RW_RLOCK_BLOCK,          DTRACE_IDNONE },
86   { LS_RW_RLOCK,        LSR_SPIN,       LS_RW_RLOCK_SPIN,           DTRACE_IDNONE },
87   { LS_RW_RUNLOCK,      LSR_RELEASE,    LS_RW_RUNLOCK_RELEASE,      DTRACE_IDNONE },
88   { LS_RW_WLOCK,        LSR_ACQUIRE,    LS_RW_WLOCK_ACQUIRE,        DTRACE_IDNONE },
89   { LS_RW_WLOCK,        LSR_BLOCK,      LS_RW_WLOCK_BLOCK,          DTRACE_IDNONE },
90   { LS_RW_WLOCK,        LSR_SPIN,       LS_RW_WLOCK_SPIN,           DTRACE_IDNONE },
91   { LS_RW_WUNLOCK,      LSR_RELEASE,    LS_RW_WUNLOCK_RELEASE,      DTRACE_IDNONE },
92   { LS_RW_TRYUPGRADE,   LSR_UPGRADE,    LS_RW_TRYUPGRADE_UPGRADE,   DTRACE_IDNONE },
93   { LS_RW_DOWNGRADE,    LSR_DOWNGRADE,  LS_RW_DOWNGRADE_DOWNGRADE,  DTRACE_IDNONE },
94   /* Shared/Exclusive Locks */
95   { LS_SX_SLOCK,        LSX_ACQUIRE,    LS_SX_SLOCK_ACQUIRE,        DTRACE_IDNONE },
96   { LS_SX_SLOCK,        LSX_BLOCK,      LS_SX_SLOCK_BLOCK,          DTRACE_IDNONE },
97   { LS_SX_SLOCK,        LSX_SPIN,       LS_SX_SLOCK_SPIN,           DTRACE_IDNONE },
98   { LS_SX_SUNLOCK,      LSX_RELEASE,    LS_SX_SUNLOCK_RELEASE,      DTRACE_IDNONE },
99   { LS_SX_XLOCK,        LSX_ACQUIRE,    LS_SX_XLOCK_ACQUIRE,        DTRACE_IDNONE },
100   { LS_SX_XLOCK,        LSX_BLOCK,      LS_SX_XLOCK_BLOCK,          DTRACE_IDNONE },
101   { LS_SX_XLOCK,        LSX_SPIN,       LS_SX_XLOCK_SPIN,           DTRACE_IDNONE },
102   { LS_SX_XUNLOCK,      LSX_RELEASE,    LS_SX_XUNLOCK_RELEASE,      DTRACE_IDNONE },
103   { LS_SX_TRYUPGRADE,   LSX_UPGRADE,    LS_SX_TRYUPGRADE_UPGRADE,   DTRACE_IDNONE },
104   { LS_SX_DOWNGRADE,    LSX_DOWNGRADE,  LS_SX_DOWNGRADE_DOWNGRADE,  DTRACE_IDNONE },
105   /* Thread Locks */
106   { LS_THREAD_LOCK,     LST_SPIN,       LS_THREAD_LOCK_SPIN,        DTRACE_IDNONE },
107   { NULL }
108 };
109 #else
110 #error "OS not supported"
111 #endif
112
113
114 static struct cdevsw lockstat_cdevsw = {
115         .d_version      = D_VERSION,
116         .d_open         = lockstat_open,
117         .d_name         = "lockstat",
118 };
119
120 static struct cdev              *lockstat_cdev; 
121 static dtrace_provider_id_t     lockstat_id;
122
123 /*ARGSUSED*/
124 static void
125 lockstat_enable(void *arg, dtrace_id_t id, void *parg)
126 {
127         lockstat_probe_t *probe = parg;
128
129         ASSERT(!lockstat_probemap[probe->lsp_probe]);
130
131         lockstat_probemap[probe->lsp_probe] = id;
132 #ifdef DOODAD
133         membar_producer();
134 #endif
135
136         lockstat_probe_func = dtrace_probe;
137 #ifdef DOODAD
138         membar_producer();
139
140         lockstat_hot_patch();
141         membar_producer();
142 #endif
143 }
144
145 /*ARGSUSED*/
146 static void
147 lockstat_disable(void *arg, dtrace_id_t id, void *parg)
148 {
149         lockstat_probe_t *probe = parg;
150         int i;
151
152         ASSERT(lockstat_probemap[probe->lsp_probe]);
153
154         lockstat_probemap[probe->lsp_probe] = 0;
155 #ifdef DOODAD
156         lockstat_hot_patch();
157         membar_producer();
158 #endif
159
160         /*
161          * See if we have any probes left enabled.
162          */
163         for (i = 0; i < LS_NPROBES; i++) {
164                 if (lockstat_probemap[i]) {
165                         /*
166                          * This probe is still enabled.  We don't need to deal
167                          * with waiting for all threads to be out of the
168                          * lockstat critical sections; just return.
169                          */
170                         return;
171                 }
172         }
173
174 }
175
176 /*ARGSUSED*/
177 static int
178 lockstat_open(struct cdev *dev __unused, int oflags __unused, 
179               int devtype __unused, struct thread *td __unused)
180 {
181         return (0);
182 }
183
184 /*ARGSUSED*/
185 static void
186 lockstat_provide(void *arg, dtrace_probedesc_t *desc)
187 {
188         int i = 0;
189
190         for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) {
191                 lockstat_probe_t *probe = &lockstat_probes[i];
192
193                 if (dtrace_probe_lookup(lockstat_id, "kernel",
194                     probe->lsp_func, probe->lsp_name) != 0)
195                         continue;
196
197                 ASSERT(!probe->lsp_id);
198                 probe->lsp_id = dtrace_probe_create(lockstat_id,
199                     "kernel", probe->lsp_func, probe->lsp_name,
200                     LOCKSTAT_AFRAMES, probe);
201         }
202 }
203
204 /*ARGSUSED*/
205 static void
206 lockstat_destroy(void *arg, dtrace_id_t id, void *parg)
207 {
208         lockstat_probe_t *probe = parg;
209
210         ASSERT(!lockstat_probemap[probe->lsp_probe]);
211         probe->lsp_id = 0;
212 }
213
214 static dtrace_pattr_t lockstat_attr = {
215 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
216 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
217 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
218 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
219 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
220 };
221
222 static dtrace_pops_t lockstat_pops = {
223         lockstat_provide,
224         NULL,
225         lockstat_enable,
226         lockstat_disable,
227         NULL,
228         NULL,
229         NULL,
230         NULL,
231         NULL,
232         lockstat_destroy
233 };
234
235 static void
236 lockstat_load(void *dummy)
237 {
238         /* Create the /dev/dtrace/lockstat entry. */
239         lockstat_cdev = make_dev(&lockstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
240             "dtrace/lockstat");
241
242         if (dtrace_register("lockstat", &lockstat_attr, DTRACE_PRIV_USER,
243             NULL, &lockstat_pops, NULL, &lockstat_id) != 0)
244                 return;
245 }
246
247 static int
248 lockstat_unload()
249 {
250         int error = 0;
251
252         if ((error = dtrace_unregister(lockstat_id)) != 0)
253             return (error);
254
255         destroy_dev(lockstat_cdev);
256
257         return (error);
258 }
259
260 /* ARGSUSED */
261 static int
262 lockstat_modevent(module_t mod __unused, int type, void *data __unused)
263 {
264         int error = 0;
265
266         switch (type) {
267         case MOD_LOAD:
268                 break;
269
270         case MOD_UNLOAD:
271                 break;
272
273         case MOD_SHUTDOWN:
274                 break;
275
276         default:
277                 error = EOPNOTSUPP;
278                 break;
279         }
280         return (error);
281 }
282
283 SYSINIT(lockstat_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_load, NULL);
284 SYSUNINIT(lockstat_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, lockstat_unload, NULL);
285
286 DEV_MODULE(lockstat, lockstat_modevent, NULL);
287 MODULE_VERSION(lockstat, 1);
288 MODULE_DEPEND(lockstat, dtrace, 1, 1, 1);
289 MODULE_DEPEND(lockstat, opensolaris, 1, 1, 1);