aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric van Gyzen <vangyzen@FreeBSD.org>2019-07-03 19:22:44 +0000
committerEric van Gyzen <vangyzen@FreeBSD.org>2019-07-03 19:22:44 +0000
commit8c5a9161d16094d9db474fe78ddead1325246d05 (patch)
tree535f10674ec735e1b14f8b64dc269b1239ea0b08
parentd70f0ab38d62708116e90de6dd57f9b31182e02e (diff)
Notes
-rw-r--r--sys/kern/kern_timeout.c47
-rw-r--r--tools/test/callout_free/Makefile6
-rw-r--r--tools/test/callout_free/callout_free.c87
3 files changed, 139 insertions, 1 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 81b4a14ecf08..c069e5b3bb9b 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
#ifdef DDB
#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
#include <machine/_inttypes.h>
#endif
@@ -143,12 +144,14 @@ u_int callwheelsize, callwheelmask;
struct cc_exec {
struct callout *cc_curr;
void (*cc_drain)(void *);
+ void *cc_last_func;
+ void *cc_last_arg;
#ifdef SMP
void (*ce_migration_func)(void *);
void *ce_migration_arg;
- int ce_migration_cpu;
sbintime_t ce_migration_time;
sbintime_t ce_migration_prec;
+ int ce_migration_cpu;
#endif
bool cc_cancel;
bool cc_waiting;
@@ -177,6 +180,8 @@ struct callout_cpu {
#define callout_migrating(c) ((c)->c_iflags & CALLOUT_DFRMIGRATION)
#define cc_exec_curr(cc, dir) cc->cc_exec_entity[dir].cc_curr
+#define cc_exec_last_func(cc, dir) cc->cc_exec_entity[dir].cc_last_func
+#define cc_exec_last_arg(cc, dir) cc->cc_exec_entity[dir].cc_last_arg
#define cc_exec_drain(cc, dir) cc->cc_exec_entity[dir].cc_drain
#define cc_exec_next(cc) cc->cc_next
#define cc_exec_cancel(cc, dir) cc->cc_exec_entity[dir].cc_cancel
@@ -686,6 +691,8 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc,
c->c_iflags &= ~CALLOUT_PENDING;
cc_exec_curr(cc, direct) = c;
+ cc_exec_last_func(cc, direct) = c_func;
+ cc_exec_last_arg(cc, direct) = c_arg;
cc_exec_cancel(cc, direct) = false;
cc_exec_drain(cc, direct) = NULL;
CC_UNLOCK(cc);
@@ -1670,4 +1677,42 @@ DB_SHOW_COMMAND(callout, db_show_callout)
_show_callout((struct callout *)addr);
}
+
+static void
+_show_last_callout(int cpu, int direct, const char *dirstr)
+{
+ struct callout_cpu *cc;
+ void *func, *arg;
+
+ cc = CC_CPU(cpu);
+ func = cc_exec_last_func(cc, direct);
+ arg = cc_exec_last_arg(cc, direct);
+ db_printf("cpu %d last%s callout function: %p ", cpu, dirstr, func);
+ db_printsym((db_expr_t)func, DB_STGY_ANY);
+ db_printf("\ncpu %d last%s callout argument: %p\n", cpu, dirstr, arg);
+}
+
+DB_SHOW_COMMAND(callout_last, db_show_callout_last)
+{
+ int cpu, last;
+
+ if (have_addr) {
+ if (addr < 0 || addr > mp_maxid || CPU_ABSENT(addr)) {
+ db_printf("no such cpu: %d\n", (int)addr);
+ return;
+ }
+ cpu = last = addr;
+ } else {
+ cpu = 0;
+ last = mp_maxid;
+ }
+
+ while (cpu <= last) {
+ if (!CPU_ABSENT(cpu)) {
+ _show_last_callout(cpu, 0, "");
+ _show_last_callout(cpu, 1, " direct");
+ }
+ cpu++;
+ }
+}
#endif /* DDB */
diff --git a/tools/test/callout_free/Makefile b/tools/test/callout_free/Makefile
new file mode 100644
index 000000000000..ee17d752b820
--- /dev/null
+++ b/tools/test/callout_free/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+KMOD= callout_free
+SRCS= callout_free.c
+
+.include <bsd.kmod.mk>
diff --git a/tools/test/callout_free/callout_free.c b/tools/test/callout_free/callout_free.c
new file mode 100644
index 000000000000..4556687e06f6
--- /dev/null
+++ b/tools/test/callout_free/callout_free.c
@@ -0,0 +1,87 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Eric van Gyzen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Free a pending callout. This was useful for testing the
+ * "show callout_last" ddb command.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+static struct callout callout_free;
+static struct mtx callout_free_mutex;
+static int callout_free_arg;
+
+static void
+callout_free_func(void *arg)
+{
+ printf("squirrel!\n");
+ mtx_destroy(&callout_free_mutex);
+ memset(&callout_free, 'C', sizeof(callout_free));
+}
+
+static int
+callout_free_load(module_t mod, int cmd, void *arg)
+{
+ int error;
+
+ switch (cmd) {
+ case MOD_LOAD:
+ mtx_init(&callout_free_mutex, "callout_free", NULL, MTX_DEF);
+ /*
+ * Do not pass CALLOUT_RETURNUNLOCKED so the callout
+ * subsystem will unlock the "destroyed" mutex.
+ */
+ callout_init_mtx(&callout_free, &callout_free_mutex, 0);
+ printf("callout_free_func = %p\n", callout_free_func);
+ printf("callout_free_arg = %p\n", &callout_free_arg);
+ callout_reset(&callout_free, hz/10, callout_free_func,
+ &callout_free_arg);
+ error = 0;
+ break;
+
+ case MOD_UNLOAD:
+ error = 0;
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+DEV_MODULE(callout_free, callout_free_load, NULL);