aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorRyan Libby <rlibby@FreeBSD.org>2021-03-14 23:04:27 +0000
committerRyan Libby <rlibby@FreeBSD.org>2021-03-14 23:04:27 +0000
commit3e5e9939cda3b24df37c37da5f195415a894d9fd (patch)
tree84345747828c274ae8784397ecc6fd156a2f1a5d /sys
parent588ce1a3ac8d61c99c7827dc71191c46c2d927b7 (diff)
downloadsrc-3e5e9939cda3b24df37c37da5f195415a894d9fd.tar.gz
src-3e5e9939cda3b24df37c37da5f195415a894d9fd.zip
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@acm.org> Reviewed by: markj Discussed with: imp Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D28676
Diffstat (limited to 'sys')
-rw-r--r--sys/ddb/db_input.c126
-rw-r--r--sys/ddb/db_output.c2
-rw-r--r--sys/ddb/ddb.h1
3 files changed, 105 insertions, 24 deletions
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>
@@ -55,6 +56,19 @@ 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.
*/
static char db_lhistory[2048];
@@ -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);