Date: Sun, 14 Mar 2021 23:20:30 GMT From: Ryan Libby <rlibby@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 3e5e9939cda3 - main - ddb: enable the use of ^C and ^S/^Q Message-ID: <202103142320.12ENKUxx005660@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by rlibby: URL: https://cgit.FreeBSD.org/src/commit/?id=3e5e9939cda3b24df37c37da5f195415a894d9fd commit 3e5e9939cda3b24df37c37da5f195415a894d9fd Author: Ryan Libby <rlibby@FreeBSD.org> AuthorDate: 2021-03-14 23:04:27 +0000 Commit: Ryan Libby <rlibby@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@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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202103142320.12ENKUxx005660>