FelipeMdeO opened a new pull request, #19596:
URL: https://github.com/apache/nuttx/pull/19596
## Summary
A `fetch()`-only lower half reads the device on demand, so it's always
ready, nothing to wait for. The upper half didn't reflect that:
`sensor_poll()` only reported `POLLIN` when opened `O_NONBLOCK`, and a
blocking `read()` waited on `buffersem`, which only a driver-owned
interrupt (`notify_event`) posts. A `fetch()`-only sensor with no
interrupt therefore never satisfied `poll()`/`read()` at all — e.g.
in-tree `nucleo-h563zi:dts` hangs on a blocking `read()` today.
Applications worked around this with `O_NONBLOCK` (apache/nuttx-apps#3686);
this PR fixes it at the root instead, per reviewer feedback there.
Three commits:
1. **l3gd20 → push-only.** Its old `BUFFER_SIZE == 0` mode kept `fetch()`
set while also driving `notify_event` from the data-ready interrupt,
and that combination was itself buggy, not just inconsistent:
`sensor_poll()`'s fetch-only branch reported `POLLIN` whenever the
descriptor was `O_NONBLOCK`, regardless of whether the interrupt had
actually fired, so a multi-descriptor `poll()` loop could read stale
or duplicate data off the l3gd20 while correctly waiting on other
sensors. Push-only fixes that, and generalizes to every
interrupt-driven sensor in the tree: the interrupt handler reads the
sample and calls `push_event()`, landing it in the upper half's
circular buffer and waking any poller through `sensor_pollnotify()`.
`POLLIN` is then reported only when `sensor_is_updated()` sees a
generation the caller hasn't consumed yet — acquisition (the
interrupt reading the chip) and delivery (the app's `read()`) are
decoupled and correctly synchronized, instead of `read()` racing the
next interrupt. `read()` never touches the bus at that point, it just
copies out of the buffer. This is the existing, already-correct model
for every other push sensor in tree; l3gd20 was the one exception.
2. **`sensor_poll()`/`sensor_read()` always ready for `fetch()`-only.**
The actual fix. `notify_event` becomes dead code for `fetch()`-only
lower halves as a result; left the API in place, open to deprecating
it in a follow-up.
3. **Pace `POLLIN` at the requested interval.** Without it, a rate
request (`-r`) got no help from `poll()`, and apps sleeping it out
themselves serialize across multiple topics (three at 10 Hz → 3.3 Hz
each). A per-subscriber `work_s` timer, armed in `sensor_poll()`,
paces each one at its own interval — the `fetch()` counterpart of what
`sensor_is_updated()` already does for push. Falls back to
always-ready without `CONFIG_SCHED_LPWORK`.
## Impact
Any `fetch()`-only uORB sensor (on-demand I2C/SPI, no interrupt) now
works with `poll()`/`read()` without the app forcing `O_NONBLOCK`. Every
interrupt-driven sensor, including l3gd20 after commit 1, keeps blocking
correctly until real new data arrives — nothing about push semantics
changes for them, verified both by code and on hardware (Testing).
## Testing
Host: Ubuntu 24.04.3 LTS. `checkpatch.sh` (style + `-m` commit messages)
clean on all 3 commits.
**Compiles clean** on 3 architectures touching the changed
`drivers/sensors/sensor.c`: xtensa-esp-elf-gcc 14.2.0 (`esp32s3-devkit`),
arm-none-eabi-gcc 13.2.1 (`stm32f4discovery`), and `sim` (x86_64,
`UORB_LISTENER` + `CONFIG_SCHED_LPWORK`).
**Fetch-only sensor on hardware** — ESP32-S3-DevKitC + MPU6050 (GY-521)
on I2C0, `fetch()`-only with no interrupt line, no `O_NONBLOCK` anywhere
in the unmodified `apps/system/uorb/listener.c`:
```
nsh> uorb_listener -n 5 sensor_accel0
Monitor objects num:1
object_name:sensor_accel, object_instance:0
sensor_accel(now:37860000):timestamp:37860000,x:-0.205901,y:-0.122104,z:10.323798,temperature:23.824116
sensor_accel(now:37860000):timestamp:37860000,x:-0.205901,y:-0.122104,z:10.323798,temperature:23.777058
sensor_accel(now:37860000):timestamp:37860000,x:-0.205901,y:-0.122104,z:10.323798,temperature:23.730000
sensor_accel(now:37860000):timestamp:37860000,x:-0.205901,y:-0.122104,z:10.323798,temperature:23.918234
sensor_accel(now:37860000):timestamp:37860000,x:-0.131681,y:-0.134075,z:10.299856,temperature:23.824116
Object name:sensor_accel0, received:5
Total number of received Message:5/5
```
**Per-subscriber pacing**, same hardware: two `uorb_listener` processes
on `sensor_accel0` at once, `-r 20` and `-r 5`. Samples landed ~60ms and
~210ms apart respectively — each subscriber paced at its own rate, not
the minimum across both (the failure mode of an earlier per-device-timer
prototype).
**Teardown under stress**: 8 rounds of `uorb_listener -r 5 sensor_accel0 &`
followed by `SIGINT` mid-poll. `ps` afterward shows no leaked task and no
stuck `lpwork` item; the sensor still answers normally right after.
**Push sensor on hardware** — STM32F4Discovery onboard accelerometer via
`CONFIG_SENSORS_LIS3DSH_UORB`: turned out to be an LIS302DL (older board
revision, confirmed by `WHO_AM_I=0x3b` vs LIS3DSH's `0x3f`), a
pre-existing hardware mismatch unrelated to this change, so no live data
from this one. Push path correctness instead verified by inspection: the
`else` branch in `sensor_read()`/`sensor_poll()` that push sensors take
is untouched by this series.
--
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]