casaroli opened a new pull request, #21144: URL: https://github.com/apache/nuttx/pull/21144
## Summary This PR fixes two parts of job control on a console: the Ctrl-C and Ctrl-Z characters that send a signal, and `kill()` to a process group. - **drivers/serial: Discard the INTR and SUSP characters that send a signal.** When `ISIG` is set and the terminal knows its foreground process, INTR (Ctrl-C) and SUSP (Ctrl-Z) send `SIGINT` and `SIGTSTP`. The serial driver also put the character into the receive buffer, so the next `read()` gave it to the program: after Ctrl-C, a shell read `^C` in front of the next command line. POSIX (General Terminal Interface, 11.1.9 "Special Characters") says that the terminal discards these characters when `ISIG` is set; the pty and telnet drivers already do. Now `uart_recvchars()` removes them in the `receive()` and `recvbuf()` paths. A character that sends no signal (no foreground process, or `ISIG` not set) stays in the data. The DMA path does not change. The commit also keeps the first signal of a batch: the check of each later character set the signal back to 0, so Ctrl-C followed by more characters in the same interrupt sent no signal. - **Documentation: Say that the serial driver discards Ctrl-C and Ctrl-Z.** One sentence in the job control paragraph of `serial.rst`. - **sched/signal: Send kill() to a process group as one process.** `kill()` failed with `ENOSYS` for a negative pid (a process group), and pid 0 (the process group of the caller) sent the signal to the idle task. In NuttX a process group is one process: `getpgid()` and `setpgid()` use the process ID as the group ID, and `killpg()` already sends the signal to that process. Now pid 0 is the caller and -pid is the process pid; pid -1 (all processes) still fails with `ENOSYS`. A shell with job control sends `kill %1` to the process group of the job. - **Documentation: Say that kill() sends to a process group of one process.** The `kill()` reference and `serial.rst` said that a signal to a process group is not supported. ## Impact Behaviour change, every build mode (flat too): - Serial consoles with `CONFIG_TTY_SIGINT` or `CONFIG_TTY_SIGTSTP` and a foreground process: the program no longer reads the Ctrl-C or Ctrl-Z character that sent the signal. Without a foreground process nothing changes: NSH sets the foreground process only while a foreground command runs (`TIOCSCTTY`, then `TIOCNOTTY`), so at the NSH prompt the readline editor still gets Ctrl-C. - `kill(0, sig)` now signals the caller (before: the idle task). `kill(-pid, sig)` now signals process pid (before: `ENOSYS`); a group that does not exist gives `ESRCH` (before: `ENOSYS`). `kill(-1, sig)` still fails with `ENOSYS`. In-tree users, nuttx and nuttx-apps master: `examples/nanoxterm` calls `kill(-pid, SIGHUP)`; it now reaches the child. NSH's `kill` command accepts only a pid >= 0, so `kill -9 0` now signals NSH itself (before: the idle task). All other `kill()` and `nxsig_kill()` callers pass a pid > 0 (a child, a daemon, the foreground PID of a terminal). The only ^C reader in nuttx-apps, `system/readline` (Ctrl-C cancels a Ctrl-R search), runs at the NSH prompt. ## Testing Tested on master 192ac6d3fbc and on this PR rebased on it, with QEMU (HVF), `CONFIG_TTY_SIGINT`, `CONFIG_TTY_SIGTSTP` and `CONFIG_SIG_DEFAULT`: `qemu-armv8a:knsh` (kernel build, programs on v9fs) and `qemu-armv8a:nsh` (flat build, the programs as NSH built-ins on the serial console). `isigtest.c` catches `SIGINT` and reads a line from the console; the test types Ctrl-C, then `abc` and Enter. The same result in the kernel and the flat build: | Case | master | this PR | |---|---|---| | one `SIGINT` | 1: PASS | 1: PASS | | the line that `read()` gives | `03 61 62 63 0a` (the Ctrl-C first): FAIL | `61 62 63 0a`: PASS | `killpgrp.c`; the child is the program itself, started with `posix_spawn()`. The same result in the kernel and the flat build: | Case | master | this PR | |---|---|---| | `getpgid(child) == child` | PASS | PASS | | `kill(-child, SIGTERM)` | -1, `ENOSYS`: FAIL | 0: PASS | | the child ends (`waitpid()`) | PASS (the test kills it) | PASS | | `kill(0, SIGUSR1)` runs the handler of the caller | no (the idle task got it): FAIL | PASS | | `kill(0, 0)` | 0: PASS | 0: PASS | | `kill(-1, 0)` | -1, `ENOSYS`: PASS | -1, `ENOSYS`: PASS | | `kill(-30000, 0)` (no such group) | -1, `ENOSYS`: FAIL | -1, `ESRCH`: PASS | ostest exits with status 0 on `qemu-armv8a:knsh` and `qemu-armv8a:nsh`, on master and with this PR. Builds, each OK and without new warnings: `lm3s6965-ek:nsh` (flat, Cortex-M3) with `CONFIG_SERIAL_TERMIOS`, `CONFIG_TTY_SIGINT` and `CONFIG_TTY_SIGTSTP`; `lm3s6965-ek:qemu-protected` (protected, Cortex-M3); `rv-virt:pnsh64` (protected, RISC-V) and `rv-virt:knsh64` (kernel, RISC-V) with `CONFIG_SERIAL_TERMIOS`, `CONFIG_TTY_SIGINT` and `CONFIG_TTY_SIGTSTP`. `tools/checkpatch.sh -c -u -m -g` passes. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
