summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2003-06-22 02:54:33 +0000
committeriedowse <iedowse@FreeBSD.org>2003-06-22 02:54:33 +0000
commit65000a220ab41d3a7e96a605fef81d386eeca712 (patch)
tree68d45a057c7fb88626bb480c259807ef2a5bf778 /sys/kern
parent17a394677499453b70b54c9df6978b192d58b581 (diff)
downloadFreeBSD-src-65000a220ab41d3a7e96a605fef81d386eeca712.zip
FreeBSD-src-65000a220ab41d3a7e96a605fef81d386eeca712.tar.gz
Use a new message buffer `consmsgbuf' to forward messages to a
TIOCCONS console (e.g. xconsole) via a timeout routine instead of calling into the tty code directly from printf(). This fixes a number of cases where calling printf() at the wrong time (such as with locks held) would cause a panic if xconsole is running. The TIOCCONS message buffer is 8k in size by default, but this can be changed with the kern.consmsgbuf_size sysctl. By default, messages are checked for 5 times per second. The timer runs and the buffer memory remains allocated only at times when a TIOCCONS console is active. Discussed on: freebsd-arch
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/subr_prf.c26
-rw-r--r--sys/kern/tty.c6
-rw-r--r--sys/kern/tty_cons.c70
3 files changed, 86 insertions, 16 deletions
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
index d564cf6..e802e00 100644
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -89,9 +89,6 @@ struct snprintf_arg {
extern int log_open;
-struct tty *constty; /* pointer to console "window" tty */
-
-static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
static void msglogchar(int c, int pri);
static void putchar(int ch, void *arg);
static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
@@ -335,21 +332,24 @@ static void
putchar(int c, void *arg)
{
struct putchar_arg *ap = (struct putchar_arg*) arg;
- int flags = ap->flags;
struct tty *tp = ap->tty;
+ int consdirect, flags = ap->flags;
+
+ consdirect = ((flags & TOCONS) && constty == NULL);
+ /* Don't use the tty code after a panic. */
if (panicstr)
- constty = NULL;
- if ((flags & TOCONS) && tp == NULL && constty) {
- tp = constty;
- flags |= TOTTY;
+ consdirect = 1;
+ if (consdirect) {
+ if (c != '\0')
+ cnputc(c);
+ } else {
+ if ((flags & TOTTY) && tp != NULL)
+ tputchar(c, tp);
+ if ((flags & TOCONS) && constty != NULL)
+ msgbuf_addchar(&consmsgbuf, c);
}
- if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
- (flags & TOCONS) && tp == constty)
- constty = NULL;
if ((flags & TOLOG))
msglogchar(c, ap->pri);
- if ((flags & TOCONS) && constty == NULL && c != '\0')
- (*v_putc)(c);
}
/*
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 1c8aa6b..4bebd65 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -261,7 +261,7 @@ ttyclose(struct tty *tp)
funsetown(&tp->t_sigio);
s = spltty();
if (constty == tp)
- constty = NULL;
+ constty_clear();
ttyflush(tp, FREAD | FWRITE);
clist_free_cblocks(&tp->t_canq);
@@ -871,9 +871,9 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag)
if (error)
return (error);
- constty = tp;
+ constty_set(tp);
} else if (tp == constty)
- constty = NULL;
+ constty_clear();
break;
case TIOCDRAIN: /* wait till output drained */
error = ttywait(tp);
diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c
index fe723e6..53a5d3d 100644
--- a/sys/kern/tty_cons.c
+++ b/sys/kern/tty_cons.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/msgbuf.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/queue.h>
@@ -117,11 +118,16 @@ int cons_unavail = 0; /* XXX:
static int cn_mute;
static int openflag; /* how /dev/console was opened */
static int cn_is_open;
+static char *consbuf; /* buffer used by `consmsgbuf' */
+static struct callout conscallout; /* callout for outputting to constty */
+struct msgbuf consmsgbuf; /* message buffer for console tty */
static u_char console_pausing; /* pause after each line during probe */
static char *console_pausestr=
"<pause; press any key to proceed to next line or '.' to end pause mode>";
+struct tty *constty; /* pointer to console "window" tty */
void cndebug(char *);
+static void constty_timeout(void *arg);
CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
SET_DECLARE(cons_set, struct consdev);
@@ -589,6 +595,70 @@ cndbctl(int on)
refcount++;
}
+static int consmsgbuf_size = 8192;
+SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0,
+ "");
+
+/*
+ * Redirect console output to a tty.
+ */
+void
+constty_set(struct tty *tp)
+{
+ int size;
+
+ KASSERT(tp != NULL, ("constty_set: NULL tp"));
+ if (consbuf == NULL) {
+ size = consmsgbuf_size;
+ consbuf = malloc(size, M_TTYS, M_WAITOK);
+ msgbuf_init(&consmsgbuf, consbuf, size);
+ callout_init(&conscallout, 0);
+ }
+ constty = tp;
+ constty_timeout(NULL);
+}
+
+/*
+ * Disable console redirection to a tty.
+ */
+void
+constty_clear(void)
+{
+ int c;
+
+ constty = NULL;
+ if (consbuf == NULL)
+ return;
+ callout_stop(&conscallout);
+ while ((c = msgbuf_getchar(&consmsgbuf)) != -1)
+ cnputc(c);
+ free(consbuf, M_TTYS);
+ consbuf = NULL;
+}
+
+/* Times per second to check for pending console tty messages. */
+static int constty_wakeups_per_second = 5;
+SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW,
+ &constty_wakeups_per_second, 0, "");
+
+static void
+constty_timeout(void *arg)
+{
+ int c;
+
+ while (constty != NULL && (c = msgbuf_getchar(&consmsgbuf)) != -1) {
+ if (tputchar(c, constty) < 0)
+ constty = NULL;
+ }
+ if (constty != NULL) {
+ callout_reset(&conscallout, hz / constty_wakeups_per_second,
+ constty_timeout, NULL);
+ } else {
+ /* Deallocate the constty buffer memory. */
+ constty_clear();
+ }
+}
+
static void
cn_drvinit(void *unused)
{
OpenPOWER on IntegriCloud