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]

Reply via email to