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
