Hello, NuttX does not have POSIX job control today. On master:
- setpgid() fails with EPERM if pgid is not the process ID. setsid() returns the process ID and does not start a session. kill(-pgrp) signals only the process pgrp. - /dev/tty does not exist, and a terminal keeps one foreground process ID. - WIFSTOPPED(), WSTOPSIG() and WIFCONTINUED() are always 0. waitid(P_PGID) gives ENOSYS. - No code reads SA_RESTART, so each interrupted blocking call fails with EINTR. #19184 added the terminal ioctls and these stubs for one process per group. I propose real process groups, and that model stays when the new options are off. (A POSIX process group is not a NuttX task group: a task group is one POSIX process.) What POSIX says (POSIX.1-2024): - <unistd.h>, _POSIX_JOB_CONTROL: "The implementation supports job control. This symbol shall always be set to a value greater than zero." - setpgid(), change history of Issue 6: "The setpgid() function is mandatory since _POSIX_JOB_CONTROL is required to be defined in this version." - XBD chapter 10 has /dev/tty in "The following files shall exist on conforming systems and shall be both readable and writable". - sigaction(), SA_RESTART: "the function shall restart and shall not fail with [EINTR] unless otherwise specified". Our posix.rst lists POSIX_JOB_CONTROL in PSE54 only, not in PSE51 to PSE53. A small system does not need it, so the two large parts have an option that is off by default. The work, in PR order: 1. Process groups and sessions: CONFIG_SCHED_PROCESS_GROUPS, default n, needs SCHED_HAVE_PARENT. setpgid(), getpgid(), setsid() and getsid() become system calls, at the end of the table, so no other number moves. kill(0), kill(-pgid) and killpg() signal the whole group. POSIX_SPAWN_SETSID works. Ctrl-C and Ctrl-Z go to the foreground group. About +820 lines. 2. Stopped and continued children: no option. SIGCHLD with CLD_STOPPED and CLD_CONTINUED, WUNTRACED, WCONTINUED, waitid(P_PGID). waitpid() uses the wait loop of waitid(). About +770 -580 lines. 3. SA_RESTART: no option, in each CONFIG_ENABLE_ALL_SIGNALS build. About +480 lines. 4. Controlling terminals: CONFIG_TTY_CTTY, default n, needs part 1 and TTY_SIGINT or TTY_SIGTSTP. /dev/tty, SIGHUP when the session leader exits, SIGTTIN and SIGTTOU for a background group, on the serial driver, pty and telnet. The TIOCSCTTY(pid) form of NSH and nxinit stays. About +1080 lines. 5. nxinit starts a console service in a new session. Small. With the options off, parts 1 and 4 add one small function, nxsig_kill_foreground(), and behavior stays the same. The one exception is killpg(1), which POSIX leaves unspecified: it now gives ENOSYS. Parts 2 and 3 change behavior for everyone, as POSIX asks: - NSH already waits with WUNTRACED. With SCHED_HAVE_PARENT it will return to the prompt when the foreground command stops. Today it keeps waiting. This is from the source; I did not run it yet. - examples/nanoxterm is the only program in the two repositories that sets SA_RESTART. Its calls will restart, as it asks. - Each task gets one more byte, and each pending signal action one more bool. arm64 and RISC-V get a check at system call exit. Flat builds and x86_64 retry inside read(), write(), the socket calls and waitpid(). Other architectures with system calls (Arm, Xtensa, MIPS) keep EINTR for now, because the handler runs only after the system call returns. They need the same change in their dispatcher. I did not measure the size yet. Each PR will give it. Tests so far, on a tree from 2026-10-20, with test programs that I will add to nuttx-apps: - qemu-armv8a:knsh: process groups 21/21, terminals 22/22, stopped children 8/10 (the other 2 need part 3), SA_RESTART 10/11 (the other case is a timeout on a local socket), ostest 0. - qemu-armv8a:nsh (flat): ostest 0. Most cases need fork() and skip: 4 process group cases ran, and no terminal case. I will change the tests to run these cases without fork(). - With all parts and my other open work on one tree: a POSIX shell on the console runs Ctrl-Z, jobs, bg, fg and Ctrl-C. - Not run: protected builds, and parts 1 and 4 on other architectures. I will rebase and test again before each PR. Part 2 has conflicts on master now. Not done yet, and I plan to do these too: - Define _POSIX_JOB_CONTROL and answer sysconf(_SC_JOB_CONTROL) when the option is on. - POSIX_SPAWN_SETPGROUP: posix_spawnattr_setpgroup() gives ENOSYS today. Builds without fork() need it, so it goes in part 1. - Orphaned process groups: no stop, and EIO on a read of the terminal. - SIGTTOU for tcsetattr() and similar calls from a background group. Only tcsetpgrp() has it now. - kill(-1), which gives ENOSYS. - A blocked SIGCONT does not continue a process, and without SCHED_CHILD_STATUS a stop can be lost. WIFSIGNALED() also stays 0 in this work. A separate change covers it. Questions: 1. Is this direction acceptable: real process groups and sessions behind default-off options, and the current stubs when they are off? 2. Parts 2 and 3 have no option, because they are standard behavior and an option would keep the wrong behavior in some builds. Does anyone want an option for them after the sizes are known? Thanks, Marco Casaroli
