git: 3e5e9939cda3 - main - ddb: enable the use of ^C and ^S/^Q

Ryan Libby rlibby at FreeBSD.org
Sun Mar 14 23:20:31 UTC 2021


The branch main has been updated by rlibby:

URL: https://cgit.FreeBSD.org/src/commit/?id=3e5e9939cda3b24df37c37da5f195415a894d9fd

commit 3e5e9939cda3b24df37c37da5f195415a894d9fd
Author:     Ryan Libby <rlibby at FreeBSD.org>
AuthorDate: 2021-03-14 23:04:27 +0000
Commit:     Ryan Libby <rlibby at FreeBSD.org>
CommitDate: 2021-03-14 23:04:27 +0000

    ddb: enable the use of ^C and ^S/^Q
    
    This lets one interrupt DDB's output, which is useful if paging is
    disabled and the output device is slow.
    
    This follows a previous implementation in svn r311952 / git
    5fddef79998678d256ba30316353393b4d8ebb32 which was reverted because it
    broke DDB type-ahead.
    
    Now, try this again, but with a 512-byte type-ahead buffer.  While there
    is buffer space, control input is handled and non-control input is
    buffered.  When the buffer is exhausted, the default is to print a
    warning and drop further non-control input in order to continue handling
    control input.  sysctl debug.ddb.prioritize_control_input can be set to
    0 to instead preserve all input but lose immediate handling of control
    input.  This could for example effect pasting of a large script into the
    ddb console.
    
    Suggested by:   Anton Rang <rang at acm.org>
    Reviewed by:    markj
    Discussed with: imp
    Sponsored by:   Dell EMC Isilon
    Differential Revision:  https://reviews.freebsd.org/D28676
---
 share/man/man4/ddb.4 |  15 +++++-
 sys/ddb/db_input.c   | 126 +++++++++++++++++++++++++++++++++++++++++----------
 sys/ddb/db_output.c  |   2 +-
 sys/ddb/ddb.h        |   1 +
 4 files changed, 119 insertions(+), 25 deletions(-)

diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4
index 1fe3490edd36..4f1614d8e006 100644
--- a/share/man/man4/ddb.4
+++ b/share/man/man4/ddb.4
@@ -26,7 +26,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 26, 2021
+.Dd March 14, 2021
 .Dt DDB 4
 .Os
 .Sh NAME
@@ -1571,6 +1571,19 @@ The debugger may be entered by setting the
 .Xr sysctl 8
 .Va debug.kdb.enter
 to 1.
+.Pp
+Output may be interrupted, paused, and resumed with the control
+characters CTRL-C, CTRL-S, and CTRL-Q.
+Because these control characters are received as in-band data from the
+console, there is an input buffer, and once that buffer fills
+.Nm
+must either stop responding to control characters or drop additional
+input while continuing to search for control characters.
+This behavior is controlled by the tunable
+.Xr sysctl 8
+.Va debug.ddb.prioritize_control_input ,
+which defaults to 1.
+The input buffer size is 512 bytes.
 .Sh FILES
 Header files mentioned in this manual page can be found below
 .Pa /usr/include
diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c
index 41396e0a041f..a7d06e17f5c1 100644
--- a/sys/ddb/db_input.c
+++ b/sys/ddb/db_input.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/cons.h>
+#include <sys/sysctl.h>
 
 #include <ddb/ddb.h>
 #include <ddb/db_output.h>
@@ -54,6 +55,19 @@ static char *	db_lbuf_end;	/* end of input line buffer */
 static char *	db_lc;		/* current character */
 static char *	db_le;		/* one past last character */
 
+/*
+ * Raw input buffer, processed only for certain control characters.
+ */
+#define	DB_RAW_SIZE	512
+static char	db_raw[DB_RAW_SIZE];
+static u_int	db_raw_pos;
+static u_int	db_raw_cnt;
+static int	db_raw_warned;
+static int	ddb_prioritize_control_input = 1;
+SYSCTL_INT(_debug_ddb, OID_AUTO, prioritize_control_input, CTLFLAG_RWTUN,
+    &ddb_prioritize_control_input, 0,
+    "Drop input when the buffer fills in order to keep servicing ^C/^S/^Q");
+
 /*
  * Simple input line history support.
  */
@@ -65,11 +79,13 @@ static int	db_lhist_nlines;
 #define	BLANK		' '
 #define	BACKUP		'\b'
 
-static int	cnmaygetc(void);
 static void	db_delete(int n, int bwd);
 static int	db_inputchar(int c);
 static void	db_putnchars(int c, int count);
 static void	db_putstring(char *s, int count);
+static int	db_raw_pop(void);
+static void	db_raw_push(int);
+static int	db_raw_space(void);
 
 static void
 db_putstring(s, count)
@@ -307,10 +323,50 @@ db_inputchar(c)
 	return (0);
 }
 
+/* Get a character from the console, first checking the raw input buffer. */
+int
+db_getc(void)
+{
+	int c;
+
+	if (db_raw_cnt == 0) {
+		c = cngetc();
+	} else {
+		c = db_raw_pop();
+		if (c == '\r')
+			c = '\n';
+	}
+	return (c);
+}
+
+/* Whether the raw input buffer has space to accept another character. */
 static int
-cnmaygetc()
+db_raw_space(void)
+{
+
+	return (db_raw_cnt < DB_RAW_SIZE);
+}
+
+/* Un-get a character from the console by buffering it. */
+static void
+db_raw_push(int c)
 {
-	return (-1);
+
+	if (!db_raw_space())
+		db_error(NULL);
+	db_raw[(db_raw_pos + db_raw_cnt++) % DB_RAW_SIZE] = c;
+}
+
+/* Drain a character from the raw input buffer. */
+static int
+db_raw_pop(void)
+{
+
+	if (db_raw_cnt == 0)
+		return (-1);
+	db_raw_cnt--;
+	db_raw_warned = 0;
+	return (db_raw[db_raw_pos++ % DB_RAW_SIZE]);
 }
 
 int
@@ -339,7 +395,7 @@ db_readline(lstart, lsize)
 	db_lc = lstart;
 	db_le = lstart;
 
-	while (!db_inputchar(cngetc()))
+	while (!db_inputchar(db_getc()))
 	    continue;
 
 	db_capture_write(lstart, db_le - db_lbuf_start);
@@ -361,30 +417,54 @@ db_readline(lstart, lsize)
 	return (db_le - db_lbuf_start);
 }
 
+static void
+db_do_interrupt(const char *reason)
+{
+
+	/* Do a pager quit too because some commands have jmpbuf handling. */
+	db_disable_pager();
+	db_pager_quit = 1;
+	db_error(reason);
+}
+
 void
 db_check_interrupt(void)
 {
 	int	c;
 
-	c = cnmaygetc();
-	switch (c) {
-	    case -1:		/* no character */
-		return;
-
-	    case CTRL('c'):
-		db_error((char *)0);
-		/*NOTREACHED*/
-
-	    case CTRL('s'):
-		do {
-		    c = cnmaygetc();
-		    if (c == CTRL('c'))
-			db_error((char *)0);
-		} while (c != CTRL('q'));
-		break;
+	/*
+	 * Check console input for control characters.  Non-control input is
+	 * buffered.  When buffer space is exhausted, either stop responding to
+	 * control input or drop further non-control input on the floor.
+	 */
+	for (;;) {
+		if (!ddb_prioritize_control_input && !db_raw_space())
+			return;
+		c = cncheckc();
+		switch (c) {
+		case -1:		/* no character */
+			return;
+
+		case CTRL('c'):
+			db_do_interrupt("^C");
+			/*NOTREACHED*/
+
+		case CTRL('s'):
+			do {
+				c = cncheckc();
+				if (c == CTRL('c'))
+					db_do_interrupt("^C");
+			} while (c != CTRL('q'));
+			break;
 
-	    default:
-		/* drop on floor */
-		break;
+		default:
+			if (db_raw_space()) {
+				db_raw_push(c);
+			} else if (!db_raw_warned) {
+				db_raw_warned = 1;
+				db_printf("\n--Exceeded input buffer--\n");
+			}
+			break;
+		}
 	}
 }
diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c
index 3517187f8206..41a8c7128359 100644
--- a/sys/ddb/db_output.c
+++ b/sys/ddb/db_output.c
@@ -260,7 +260,7 @@ db_pager(void)
 	db_printf("--More--\r");
 	done = 0;
 	while (!done) {
-		c = cngetc();
+		c = db_getc();
 		switch (c) {
 		case 'e':
 		case 'j':
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index 81448474c514..5ae48d21fda9 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -197,6 +197,7 @@ db_addr_t	db_disasm(db_addr_t loc, bool altfmt);
 				/* instruction disassembler */
 void		db_error(const char *s);
 int		db_expression(db_expr_t *valuep);
+int		db_getc(void);
 int		db_get_variable(db_expr_t *valuep);
 void		db_iprintf(const char *,...) __printflike(1, 2);
 struct proc	*db_lookup_proc(db_expr_t addr);


More information about the dev-commits-src-main mailing list