This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 7e5bf155b53d6e9598e8c7f16747a9ee0a65afbd
Author: raiden00pl <[email protected]>
AuthorDate: Tue Sep 8 10:23:27 2026 +0200

    arch/intel64: don't clear the oneshot handler from the HPET ISR
    
    intel64_oneshot_handler() cleared oneshot->handler and oneshot->arg
    after picking them up, without holding g_oneshot_spin, while
    intel64_oneshot_start() re-arms the timer under that lock from another
    CPU.  Now that the HPET ISR stays attached across a re-arm, a stale
    interrupt can interleave with start(): it reads the freshly installed
    handler, clears it, and start() then sets running = true again, so the
    genuine expiry that follows finds running == true with a NULL handler
    and jumps to address zero from interrupt context (page fault at RIP 0
    in the CPU0 IDLE task while the LTP lio_listio tests were running), or
    the alarm is simply lost and the tickless system stops.
    
    The handler and its argument are owned by start() and cancel(); the ISR
    only needs to read them.  Leave them alone in the ISR and skip the call
    if none is installed.  The remaining effect of a stale interrupt is an
    early invocation of the alarm callback, which is harmless: the tickless
    scheduler re-evaluates its expirations and re-arms the timer.
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <[email protected]>
---
 arch/x86_64/src/intel64/intel64_oneshot.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/arch/x86_64/src/intel64/intel64_oneshot.c 
b/arch/x86_64/src/intel64/intel64_oneshot.c
index eb907eaed17..27168a329f8 100644
--- a/arch/x86_64/src/intel64/intel64_oneshot.c
+++ b/arch/x86_64/src/intel64/intel64_oneshot.c
@@ -100,18 +100,21 @@ static int intel64_oneshot_handler(int irg_num, void * 
context, void *arg)
       INTEL64_TIM_ACKINT(oneshot->tch, oneshot->chan);
 #endif
 
-      /* The timer is no longer running */
+      /* The timer is no longer running.  Only pick up the handler here;
+       * it is owned by intel64_oneshot_start()/cancel(), which may be
+       * re-arming the timer on another CPU right now.  Clearing it from
+       * the ISR could leave a re-armed timer without a handler, and the
+       * next expiry would then jump through a NULL pointer.
+       */
 
       oneshot->running = false;
-
-      /* Forward the event, clearing out any vestiges */
-
       oneshot_handler  = (oneshot_handler_t)oneshot->handler;
-      oneshot->handler = NULL;
       oneshot_arg      = (void *)oneshot->arg;
-      oneshot->arg     = NULL;
 
-      oneshot_handler(oneshot_arg);
+      if (oneshot_handler != NULL)
+        {
+          oneshot_handler(oneshot_arg);
+        }
     }
   else
     {

Reply via email to