Hello all,

The draft pull request is open:

  https://github.com/apache/nuttx/pull/20796

It is stacked on two cleanup pull requests:

  https://github.com/apache/nuttx/pull/20794  nxstyle errors in 60 of
      the touched files (whitespace and formatting only)
  https://github.com/apache/nuttx/pull/20795  fusb302.c: two
      unbalanced parentheses (it did not compile with
      CONFIG_I2C_RESET), and its nxstyle errors

When they merge and #20796 is rebased, it becomes easier to review.
The relevant commits of #20796 are the last 3:

  !fs/poll: Use struct pollfd_s for the kernel side of poll.
  !fs/poll: Give struct pollfd the POSIX layout.
  Documentation: Describe struct pollfd and struct pollfd_s.

One change since my first mail: the rename commit is also marked with
"!" and "BREAKING CHANGE", because it changes the poll method of
out-of-tree drivers.

The two nuttx-apps pull requests:

  https://github.com/apache/nuttx-apps/pull/3878  PRIx32 formats
  https://github.com/apache/nuttx-apps/pull/3879  rpmsgdev test driver

I also ran the test program on real hardware, two architectures,
flat builds:

Raspberry Pi RP2350 (Cortex-M33), pimoroni-pico-2-plus:nsh

  master:  the layout checks FAIL. poll() on 3 entries with the
           standard layout returns 1 and does not write revents. The
           ppoll() timeout check FAILs. ostest: status 0.
  #20796:  all checks PASS. ostest: status 0.

ESP32-S3 (Xtensa LX7), esp32s3-devkit:nsh

  master:  the layout checks FAIL, and the test with two threads that
           poll the same array crashes the board:

             xtensa_user_panic: User Exception: EXCCAUSE=001d
                 task: pollabi
             PC: 42025cda  VADDR: 00000000
             pipecommon_poll at drivers/pipes/pipe_common.c:773
             file_poll at fs/vfs/fs_poll.c:352

           EXCCAUSE 0x1d is a store to address 0. In a flat build,
           poll() keeps its state (arg, cb, priv) in the caller's
           array. When two threads poll the same array, the teardown
           of one thread clears the state that the other thread still
           uses, and the pipe driver then writes through a NULL
           pointer.

  #20796:  all checks PASS, no crash. poll() now works on its own
           kernel copy of the array in every build mode.

On this ESP32-S3, ostest stops with an assertion in its libc tests,
on master and with #20796 alike. That is an older failure on this
board, not related to poll().

The pull request has the test tables.

Regards,
Marco Casaroli

On Mon, Oct 19, 2026 at 1:02 AM Marco C. <[email protected]> wrote:
>
> Hello all,
>
> I want to change struct pollfd in include/sys/poll.h to the POSIX
> layout. This is a breaking change, so I ask for your comments before
> the pull request leaves the draft state.
>
> 1. The problem
>
> Today struct pollfd has 32-bit events and revents and three internal
> fields (arg, cb and priv). It is 40 bytes on a 64-bit target and 24
> bytes on a 32-bit target. POSIX gives it three fields: int fd, short
> events and short revents (8 bytes).
>
> - A program or a library that builds its own array with the standard
>   layout and calls poll() gets its neighbouring entries overwritten.
>   Language runtimes, for example the Rust libc crate, already use the
>   8-byte layout for NuttX.
> - In flat and protected builds, poll() uses the caller's array
>   directly. The kernel writes a semaphore address and a callback
>   pointer into it, and poll_notify() calls that callback, often from an
>   interrupt handler. In a protected build the array is user memory, so
>   the kernel keeps a callback in memory that user code can change.
> - Two threads cannot poll the same array at the same time (see the
>   REVISIT comment in poll.h).
>
> 2. The change
>
> - struct pollfd gets the POSIX layout: int fd; short events;
>   short revents.
> - A new kernel header, include/nuttx/poll.h, holds the kernel type
>   struct pollfd_s (fd, 32-bit events and revents, arg, cb, priv),
>   pollevent_t, pollcb_t, POLLALWAYS, poll_notify() and
>   poll_default_cb(). sys/poll.h keeps only the POSIX part.
> - poll() copies the fd and events of each entry into a struct pollfd_s
>   array and copies revents back. Up to 4 entries go on the stack, more
>   go on the fs heap. The kernel build already copied the array on every
>   call.
> - The poll() method of drivers and sockets, file_poll(), psock_poll()
>   and poll_notify() take struct pollfd_s. This is a mechanical rename
>   in about 150 files.
> - select(), ppoll(), pselect(), epoll and the system call interface do
>   not change. epoll already keeps its own kernel entry for each file
>   descriptor.
>
> 3. Cost
>
> On qemu-armv8a the code grows by 168 bytes (flat build) and 48 bytes
> (kernel build). The stack of poll() grows by 160 bytes on a 64-bit
> target and by 96 bytes on a 32-bit target.
>
> 4. Effect on users
>
> - Applications: rebuild. Source code that uses only fd, events and
>   revents does not change. Code that prints events or revents with
>   PRIx32 must use %x (one nuttx-apps pull request fixes the five
>   programs in nuttx-apps).
> - Out-of-tree drivers: rename struct pollfd to struct pollfd_s in the
>   poll methods, the waiter arrays and the poll callbacks. Include
>   <nuttx/poll.h> if the file does not include <nuttx/fs/fs.h>. The
>   compiler reports every place that is not renamed.
>
> 5. Pull requests
>
> - One pull request with three commits: the rename (no change in
>   behaviour), the layout change (marked with "!" and "BREAKING
>   CHANGE"), and the documentation.
> - Two nuttx-apps pull requests: the PRIx32 formats, and the rpmsgdev
>   test driver.
>
> Tests: a test program checks the size of struct pollfd and polls an
> array with the standard layout (pipes, ppoll(), select(), epoll, two
> threads on one array). ostest passes on qemu-armv8a:knsh and
> qemu-armv8a:nsh. Help with tests on real hardware is welcome.
>
> Please comment here before I open the draft pull request, or in
> the draft pull request, that comes after the whitespace and
> formatting preparation PRs.
>
> Regards,
> Marco Casaroli

Reply via email to