casaroli opened a new pull request, #20815: URL: https://github.com/apache/nuttx/pull/20815
## Summary `nxsem_wait_slow()` returns `-EINTR` at once when an unmasked signal is pending. During a system call, an unmasked signal stays pending until the call returns. The kernel versions of `nxsem_wait_uninterruptible()`, `nxsem_clockwait_uninterruptible()` and `nxsem_tickwait_uninterruptible()` retry on `-EINTR`. Thus each retry fails at once, and the task loops without blocking. A lower-priority task on the same CPU does not run. If that task must post the semaphore, the system stops. For example, a signal with a handler to a thread in `pthread_join()` makes the thread loop in the kernel, and a lower-priority joined thread never runs. Commit 1 adds `TCB_FLAG_UNINTERRUPTIBLE`. The kernel uninterruptible waits first try `nxsem_trywait()`. If the semaphore is not free, they set the flag in a critical section and wait. `nxsem_wait_slow()` does not do the pending signal check when the flag is set. The kernel versions of `nxsem_wait_uninterruptible()` and `nxsem_clockwait_uninterruptible()` move to `sched/semaphore`, because libc does not change the TCB. The libc versions stay for user space, where a pending signal is delivered when the system call returns. Commit 2 stops the signal from waking an uninterruptible wait in a system call. The handler runs only when the call returns, so the wake costs two context switches and a retry for each signal. The signal stays pending, and its handler runs when the call returns. In a flat build and in a kernel thread, the signal still wakes the wait, so the handler runs at once and the wait then continues. ## Impact Kernel and protected builds: an uninterruptible wait blocks when a signal is pending. It does not use the CPU, and lower-priority tasks run. A signal to such a wait does not cause context switches. Flat builds: no change in behavior. Interruptible waits (`sem_wait()`, `nxsem_wait()`) do not change: a pending signal still makes them return `EINTR` before they block. No API change. ## Testing `qemu-armv8a:knsh` (kernel build) and `qemu-armv8a:nsh` (flat build), HVF, 1 CPU. The base is apache/nuttx#20766, which is now merged. After the rebase on master (c7cba680a10), both tests and ostest give the same results. Test 1 (spin): the main thread (priority 100) calls `pthread_join()` on a worker (priority 50) that works for 100 ms. A third thread (priority 150) sends `SIGUSR1` (with a handler) to the main thread after 50 ms. After 2 s, it boosts the worker if the join did not return. It also checks that `sem_wait()` still returns `EINTR` for the signal. | knsh | base | commit 1 | commit 2 | |---|---|---|---| | `pthread_join()` with `SIGUSR1` pending | FAIL: loops; worker progress 0 in 2 s; join returns after the boost (2052 ms) | PASS (100 ms) | PASS (100 ms) | | `SIGUSR1` handler runs once | PASS | PASS | PASS | | `sem_wait()` returns `EINTR` | PASS | PASS | PASS | With `CONFIG_PRIORITY_INHERITANCE` and a join semaphore with priority inheritance (a local test change), the base never returns from the join, also after the worker exits: `nxsem_wait()` has no fast path for such a semaphore, so the check runs before the count. Both commits pass. Test 2 (wake): the main thread (priority 100) joins a worker (priority 120) that sleeps 1 s. A sender (priority 90) sends 100000 `SIGUSR1` (with a handler) to the main thread during the join. A local counter in `nxsem_wait_irq()` counts the `EINTR` wakes. | | base | commit 1 | commit 2 | |---|---|---|---| | knsh: signals sent during the join | 1 (the join loops, the sender does not run) | 100000 | 100000 | | knsh: `EINTR` wakes | 1 | 100000 | 0 | | knsh: time per `pthread_kill()` | - | 200 ns | 80-96 ns | | knsh: handler runs during the join / in all | - | 0 / 1 | 0 / 1 | | nsh: `EINTR` wakes | 100000 | 100000 | 100000 | | nsh: handler runs during the join / in all | 100000 / 100000 | 100000 / 100000 | 100000 / 100000 | ostest passes on `qemu-armv8a:knsh` and `qemu-armv8a:nsh`. Builds: `qemu-armv8a:knsh`, `qemu-armv8a:nsh`, `qemu-armv7a:knsh`. -- 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]
