This is an automated email from the ASF dual-hosted git repository.
casaroli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 6fcad27d700 drivers/serial: scan tty control characters with memchr
6fcad27d700 is described below
commit 6fcad27d700da0abcf6494d551ad38db7bb3dca8
Author: yangsong8 <[email protected]>
AuthorDate: Mon Nov 2 18:10:08 2026 +0800
drivers/serial: scan tty control characters with memchr
uart_check_special() scanned the received buffer one byte at a time,
comparing every byte against the configured tty control characters.
Walk the buffer with memchr instead: locate the earliest control
character (FORCE_PANIC/LAUNCH/SIGINT/SIGTSTP) in the remaining data,
handle it, then continue past it, skipping the ordinary bytes in bulk.
SIGINT/SIGTSTP return their signal; FORCE_PANIC (consecutive count,
reset on any other byte) and LAUNCH are handled in passing so that a
later signal in the same buffer is still delivered.
Signed-off-by: yangsong8 <[email protected]>
---
drivers/serial/serial.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 79 insertions(+), 5 deletions(-)
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 775c25938d5..1a6225dda6b 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -2600,18 +2600,94 @@ void uart_reset_sem(FAR uart_dev_t *dev)
int uart_check_special(FAR uart_dev_t *dev, FAR char *buf,
FAR size_t *size)
{
+ FAR char *src = buf;
+ FAR char *end = buf + *size;
size_t kept = 0;
int signo = 0;
- size_t i;
if ((dev->tc_lflag & ISIG) == 0)
{
return 0;
}
- for (i = 0; i < *size; i++)
+ /* Walk the buffer, jumping to the next special character with memchr
+ * instead of testing every byte. The ordinary bytes before it are kept
+ * in one move, then the special character is acted on and dropped.
+ */
+
+ while (src < end)
{
- char ch = buf[i];
+ FAR char *special = NULL;
+ FAR char *tmp;
+ size_t n;
+ char ch;
+
+#ifdef CONFIG_TTY_FORCE_PANIC
+ tmp = memchr(src, CONFIG_TTY_FORCE_PANIC_CHAR, end - src);
+ if (tmp != NULL && (special == NULL || tmp < special))
+ {
+ special = tmp;
+ }
+#endif
+
+#ifdef CONFIG_TTY_LAUNCH
+ tmp = memchr(src, CONFIG_TTY_LAUNCH_CHAR, end - src);
+ if (tmp != NULL && (special == NULL || tmp < special))
+ {
+ special = tmp;
+ }
+#endif
+
+#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP)
+ if (dev->pid > 0)
+ {
+#ifdef CONFIG_TTY_SIGINT
+ if (dev->tc_vintr != _POSIX_VDISABLE)
+ {
+ tmp = memchr(src, dev->tc_vintr, end - src);
+ if (tmp != NULL && (special == NULL || tmp < special))
+ {
+ special = tmp;
+ }
+ }
+#endif
+
+#ifdef CONFIG_TTY_SIGTSTP
+ if (dev->tc_vsusp != _POSIX_VDISABLE)
+ {
+ tmp = memchr(src, dev->tc_vsusp, end - src);
+ if (tmp != NULL && (special == NULL || tmp < special))
+ {
+ special = tmp;
+ }
+ }
+#endif
+ }
+#endif
+
+ n = (special != NULL ? special : end) - src;
+ if (n > 0)
+ {
+ if (&buf[kept] != src)
+ {
+ memmove(&buf[kept], src, n);
+ }
+
+ kept += n;
+#ifdef CONFIG_TTY_FORCE_PANIC
+ dev->panic_count = 0;
+#endif
+ }
+
+ if (special == NULL)
+ {
+ break;
+ }
+
+ ch = *special;
+ src = special + 1;
+
+ /* One action per special character, in this order, then drop it */
#ifdef CONFIG_TTY_FORCE_PANIC
if (ch == CONFIG_TTY_FORCE_PANIC_CHAR)
@@ -2660,8 +2736,6 @@ int uart_check_special(FAR uart_dev_t *dev, FAR char *buf,
continue;
}
#endif
-
- buf[kept++] = ch;
}
*size = kept;