From: Chao Liu <chao.liu@processmission.com>
To: Gabriele Monaco <gmonaco@redhat.com>
Cc: Nam Cao <namcao@linutronix.de>,
Steven Rostedt <rostedt@goodmis.org>,
Jonathan Corbet <corbet@lwn.net>,
lianux.mm@gmail.com, lianux.wang@processmission.com,
Shuah Khan <skhan@linuxfoundation.org>,
linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH] Documentation/rv: Explain epoll and aborted sleeps
Date: Fri, 24 Jul 2026 23:59:59 +0800 [thread overview]
Message-ID: <amNlh-GZO-RcbpiL@ChaodeMacBook-Pro.local> (raw)
In-Reply-To: <f2679e058fa3904db3534a5f75d1339a4065018f.camel@redhat.com>
Hi Gabriele,
On Fri, Jul 24, 2026 at 09:20:44AM +0800, Gabriele Monaco wrote:
> On Wed, 2026-07-22 at 12:57 +0800, Chao Liu wrote:
> > The rtapp sleep monitor accepts epoll_wait() as a valid sleeping
> > reason, but the prose only discusses clock_nanosleep and futexes. Add
> > epoll_wait to the list of valid sleeping reasons.
> >
> > ABORT_SLEEP represents a task restoring TASK_RUNNING before entering
> > the scheduler, but its meaning is not described. Explain why the
> > aborted sleep attempt is valid.
> >
> > This RFC is based on Nam Cao's pending "rv: rtapp monitor update" v2
> > series:
> >
> > https://lore.kernel.org/r/cover.1781852967.git.namcao@linutronix.de
> >
> > Signed-off-by: Chao Liu <chao.liu@processmission.com>
> > ---
>
> Thanks for the contribution! I have a couple of comments, we want to be
> assertive in this docs: in general, let's not say something like "this is valid
> because the monitor thinks it's valid" but "this is valid because it is rt-safe
> for reason X".
Thanks for the review. :)
Agreed. In v2, I will update the documentation and the commit message
body to say directly why each case is safe for real-time use.
>
> > Documentation/trace/rv/monitor_rtapp.rst | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/Documentation/trace/rv/monitor_rtapp.rst
> > b/Documentation/trace/rv/monitor_rtapp.rst
> > index 238b59395ff5..234ed4d581ac 100644
> > --- a/Documentation/trace/rv/monitor_rtapp.rst
> > +++ b/Documentation/trace/rv/monitor_rtapp.rst
> > @@ -67,6 +67,8 @@ thread to sleep for one of the following reasons:
> > variables as safe for real-time. As an alternative, the librtpi library
> > exists to provide a conditional variable implementation that is correct
> > for
> > real-time applications in Linux.
> > + - Real-time thread waiting for events using `epoll_wait`,
>
> > + which the monitor accepts as a valid sleeping reason for real-time tasks.
>
> Not adding much value, try:
>
> which is a real-time-safe syscall for sleeping as it uses PI-aware locking.
>
Agreed. I will use this wording in v2.
> >
> > Beside the reason for sleeping, the eventual waker should also be
> > real-time-safe. Namely, one of:
> > @@ -114,6 +116,10 @@ The monitor's specification is::
> > ALLOWLIST = BLOCK_ON_RT_MUTEX
> > or FUTEX_LOCK_PI
> >
> > +`ABORT_SLEEP` represents a task restoring its state to `TASK_RUNNING` before
> > +entering the scheduler. In this case, the task does not actually block,
>
>
> > + so the monitor treats the aborted sleep attempt as valid.
>
> This sentence is a bit vague. Indeed an /aborted/ sleep is a valid wakeup, as if
> the task woke up itself without even sleeping, saying "the monitor treats the
> attempt as valid" adds no value.
>
> You could rephrase it to (full paragraph for clarity):
>
> `ABORT_SLEEP` represents a task restoring its state to `TASK_RUNNING` before
> entering the scheduler. In this case, the task does not actually block, so it is
> back to runnable without any wakeup sequence unsafe for real-time.
>
> What do you think?
>
Yes, this is clearer. I will use the proposed paragraph in v2.
To check my understanding, I also put together a small eventfd/epoll test
and ran it on arm64 and x86_64. The test code, configurations, patches,
serial traces, and reproduction steps are available here:
https://github.com/zevorn/rtapp-sleep-monitor-lab
Test environments
-----------------
+---------+--------------------------+---------------+------+------------+
| Guest | Host CPU | QEMU/accel | vCPU | Kernel |
+---------+--------------------------+---------------+------+------------+
| arm64 | Apple M5 Pro | 11.0.0/HVF | 2 | PREEMPT_RT |
| x86_64 | Intel Xeon Platinum 8163 | 11.0.0/KVM | 2 | PREEMPT_RT |
+---------+--------------------------+---------------+------+------------+
All three guest kernels used the same v7.2-rc4-based source baseline.
Test design
-----------
Phase 1 (P1):
P1 runs one epoll wait per iteration, for 2048 iterations, on
two vCPUs:
- vCPU 0 runs the SCHED_FIFO/50 waiter (`PID_WAITER`). It starts each
iteration, waits on epoll, reads the eventfd when epoll returns, and
acknowledges completion.
- vCPU 1 runs the SCHED_FIFO/60 writer (`PID_WRITER`). It waits for the
start signal, uses a different short delay in each iteration, writes
the eventfd, and waits for the acknowledgement.
The per-iteration flow is:
vCPU 0: waiter (PID_WAITER) vCPU 1: writer (PID_WRITER)
-------------------------------- ---------------------------------
set go = i
|------------------------> wait for go == i
enter epoll wait apply delay(i)
|<------------------------ write(eventfd)
epoll_wait() returns
read(eventfd)
set ack = i
|------------------------> wait for ack == i
Because the unmodified arm64 monitor does not recognize the
`epoll_pwait` entry, each wait that reaches the monitored sleep path
produces a P1 error. The test makes 2048 wait attempts, but an iteration
that sees readiness before setting `TASK_INTERRUPTIBLE` does not produce
a `SLEEP` event.
The PIDs are assigned dynamically. During P1, the `event_sleep` and
`error_sleep` filters use `pid == PID_WAITER`; `PID_WRITER` only supplies
the event.
Separate vCPUs let the event arrive while the waiter is preparing to
sleep, covering both normal blocking and ABORT_SLEEP. The writer has the
higher priority, so the normal wakeup is RT-safe.
Phase 2 (P2):
P2 is the negative control. A fresh task (`PID_NEGATIVE`) on
vCPU 0 performs one relative clock_nanosleep() without TIMER_ABSTIME. The
trace filters are switched to `pid == PID_NEGATIVE`. The expected
error_sleep confirms that the monitor is active.
The RV monitor tracks tasks, not vCPUs. PID 1 enables the sleep monitor
and the `event_sleep` and `error_sleep` events. After each phase, PID 1
stops tracing and prints the trace buffer; `scripts/summarize.sh` counts
the records in the serial log.
For example, the tests can be run and summarized with:
$ make initramfs-arm64
$ KERNEL_IMAGE=/path/to/Image ACCEL=hvf \
./scripts/run-qemu.sh arm64
$ ./scripts/summarize.sh serial-arm64.log
$ make initramfs-x86_64
$ KERNEL_IMAGE=/path/to/bzImage ACCEL=kvm \
./scripts/run-qemu.sh x86_64
$ ./scripts/summarize.sh serial-x86_64.log
The complete build steps, including the arm64 mapping variant, are in
docs/build-and-run.md.
Results
-------
The first two rows compare arm64 without and with the experimental
mapping. The x86_64 row is the unmodified cross-check using its native
`__NR_epoll_wait`. The arm64 rows enter through `epoll_pwait`.
Each case was run five times. `M [L-H]` means median
`[minimum-maximum]`; a single value means all five runs had that result.
+----------------+------------------+------------+---------------+--------+
| Case | P1 err | Ep abort | PI block | P2 err |
+----------------+------------------+------------+---------------+--------+
| arm64 baseline | 2043 [2031-2047] | 0 | 0 | 1 |
| arm64 mapping | 0 | 26 [20-28] | 355 [308-399] | 1 |
| x86_64 native | 0 | 31 [25-92] | 201 [147-204] | 1 |
+----------------+------------------+------------+---------------+--------+
The columns mean:
- `P1 err` counts `error_sleep` records from the Phase 1 epoll test.
- `Ep abort` counts records containing both `ep_wa` (`EPOLL_WAIT`) and
`ab_sl` (`ABORT_SLEEP`).
- `PI block` counts records containing both `ep_wa` and
`bl_on_rt_mu` (`BLOCK_ON_RT_MUTEX`).
- `P2 err` counts `error_sleep` records from the Phase 2 negative
control.
These are records retained in the trace buffer, not syscall totals or
rates. The P1/P2 error outcome was the same in all five runs. The
`Ep abort` and `PI block` counts vary with timing.
The per-run summaries and validation checks are in
results/revalidation-2026-07-24.md in the repository.
From the traces, I see the following path for a correctly recognized
epoll wait:
sys_enter(epoll_wait or epoll_pwait)
|
| native x86_64 entry, or arm64 experiment mapping
v
EPOLL_WAIT = true
|
v
ep_poll()
|
v
TASK_INTERRUPTIBLE -> SLEEP
|
+-- no event
| |
| v
| schedule() -> RT-safe wakeup -> SCHEDULE_IN
|
`-- event found by the locked recheck
|
v
skip schedule()
|
v
TASK_RUNNING -> ABORT_SLEEP
In the abort case, `ep_wa + sle` (`EPOLL_WAIT + SLEEP`) is followed by
`ep_wa + ab_sl` (`EPOLL_WAIT + ABORT_SLEEP`), with no `sch_in`
(`SCHEDULE_IN`) in between. This matches your wording: the task becomes
runnable again without blocking or going through a wakeup sequence.
I also observed `ep_wa + bl_on_rt_mu` while epoll wait was active, so the
test did reach the PI-aware locking path on PREEMPT_RT.
arm64 syscall-coverage gap
--------------------------
The arm64 run also turned up what looks like a syscall-coverage gap. The
current epoll support checks only `__NR_epoll_wait`. arm64 does not define
that syscall; its epoll wait enters the common implementation through
`__NR_epoll_pwait`. I went back to the review of the original epoll
support:
https://lore.kernel.org/r/58674d7f10c260369f5cb78599ba6ecb3804358f.camel@redhat.com
That reply discusses the `ltl_atom_update()` detail. I could not find any
discussion of cross-architecture syscall entry coverage there. In all
five unmodified arm64 runs, every retained `SLEEP` record has a matching
P1 error. Mapping `__NR_epoll_pwait` to the same atom removes those
errors, while P2 still produces the expected error.
This points to an instrumentation coverage issue rather than a difference
in epoll's real-time-safety. I kept the mapping out of this documentation
patch. Once the intended scope for `epoll_pwait`, `epoll_pwait2`, and
compat syscalls is clear, I can send a separate functional patch.
For reference, this is the experiment-only change:
diff --git a/kernel/trace/rv/monitors/sleep/sleep.c b/kernel/trace/rv/monitors/sleep/sleep.c
index aa5a984853b5..bf9ca4b5414e 100644
--- a/kernel/trace/rv/monitors/sleep/sleep.c
+++ b/kernel/trace/rv/monitors/sleep/sleep.c
@@ -136,8 +136,11 @@ static void handle_sys_enter(void *data, struct pt_regs *regs, long id)
break;
#ifdef __NR_epoll_wait
case __NR_epoll_wait:
+#endif
+#ifdef __NR_epoll_pwait
+ case __NR_epoll_pwait:
+#endif
ltl_atom_update(current, LTL_EPOLL_WAIT, true);
break;
-#endif
}
}
Thanks,
Chao
next prev parent reply other threads:[~2026-07-24 16:00 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 4:57 [RFC PATCH] Documentation/rv: Explain epoll and aborted sleeps Chao Liu
2026-07-24 7:20 ` Gabriele Monaco
2026-07-24 15:59 ` Chao Liu [this message]
2026-07-24 16:17 ` Chao Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=amNlh-GZO-RcbpiL@ChaodeMacBook-Pro.local \
--to=chao.liu@processmission.com \
--cc=corbet@lwn.net \
--cc=gmonaco@redhat.com \
--cc=lianux.mm@gmail.com \
--cc=lianux.wang@processmission.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=namcao@linutronix.de \
--cc=rostedt@goodmis.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox