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

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

commit c12abd0190f38ea4c9bbd8e4839d6a01673a9d3c
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Oct 28 10:46:12 2026 +0100

    sched/timer: Queue one signal of a POSIX timer at a time.
    
    POSIX: "Only a single signal shall be queued to the process for a given
    timer at any point in time.  When a timer for which a signal is still
    pending expires, no signal shall be queued, and a timer overrun shall
    occur."  NuttX queued one more signal at each expiration.  A blocked
    real-time signal and a signal for a handler of a thread that does not
    run are not merged, so the pending signals grew with each expiration.
    The timer runs in the watchdog interrupt, which cannot allocate more:
    when the preallocated ones ran out, nxsig_dispatch() failed with EAGAIN
    and the DEBUGVERIFY() of timer_signotify() stopped the system.
    
    The pending and the queued signal entries now keep their source (the
    timer, or NULL), which nxsig_tcbdispatch(), nxsig_dispatch(),
    nxsig_notification_source() and group_signal() pass on, also when a
    pending signal is unmasked.  At an expiration the timer checks with
    nxsig_source_queued() whether its last signal is still pending or
    queued (the same source and signal number): if so, or if no signal can
    be queued, the expiration is an overrun.  The overrun count starts again
    with each signal that is queued, and the periods that the watchdog
    missed add to it; timer_getoverrun() gives it, at most DELAYTIMER_MAX.
    The other callers of nxsig_tcbdispatch() and nxsig_dispatch() pass
    NULL; nxsig_notification(), which drivers use, keeps its arguments and
    passes NULL.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 arch/xtensa/src/esp32s3/esp32s3_isolation.c |   2 +-
 arch/xtensa/src/esp32s3/esp32s3_userfault.c |   2 +-
 sched/group/group.h                         |   3 +-
 sched/group/group_signal.c                  |  12 ++-
 sched/pthread/pthread_sigqueue.c            |   2 +-
 sched/signal/sig_dispatch.c                 | 128 ++++++++++++++++++++++++++--
 sched/signal/sig_kill.c                     |   2 +-
 sched/signal/sig_notification.c             |  25 +++++-
 sched/signal/sig_queue.c                    |   2 +-
 sched/signal/sig_tgkill.c                   |   2 +-
 sched/signal/sig_unmaskpendingsignal.c      |   8 +-
 sched/signal/signal.h                       |  18 +++-
 sched/task/task_exithook.c                  |   4 +-
 sched/timer/timer.h                         |   2 +-
 sched/timer/timer_settime.c                 |  61 +++++++++++--
 15 files changed, 234 insertions(+), 39 deletions(-)

diff --git a/arch/xtensa/src/esp32s3/esp32s3_isolation.c 
b/arch/xtensa/src/esp32s3/esp32s3_isolation.c
index b3a651faaab..a655e7c82d4 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_isolation.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_isolation.c
@@ -220,7 +220,7 @@ static int IRAM_ATTR pms_violation_isr(int cpuint, void 
*context, void *arg)
       info.si_errno           = 0;
       info.si_value.sival_ptr = NULL;
 
-      nxsig_tcbdispatch(tcb, &info, false);
+      nxsig_tcbdispatch(tcb, &info, false, NULL);
       return OK;
     }
 #endif
diff --git a/arch/xtensa/src/esp32s3/esp32s3_userfault.c 
b/arch/xtensa/src/esp32s3/esp32s3_userfault.c
index 99cbd804d19..c065a829369 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_userfault.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_userfault.c
@@ -110,7 +110,7 @@ uint32_t *esp32s3_userfault_abort(int exccause, uint32_t 
*regs)
   info.si_errno           = 0;
   info.si_value.sival_ptr = (FAR void *)regs[REG_EXCVADDR];
 
-  nxsig_tcbdispatch(tcb, &info, false);
+  nxsig_tcbdispatch(tcb, &info, false, NULL);
 
   regs          = tcb->xcp.regs;
   tcb->xcp.regs = NULL;
diff --git a/sched/group/group.h b/sched/group/group.h
index 915997b19f5..d2130b1ac8d 100644
--- a/sched/group/group.h
+++ b/sched/group/group.h
@@ -89,7 +89,8 @@ FAR struct task_group_s *task_getgroup(pid_t pid);
 
 /* Signaling group members */
 
-int group_signal(FAR struct task_group_s *group, FAR siginfo_t *siginfo);
+int group_signal(FAR struct task_group_s *group, FAR siginfo_t *siginfo,
+                 FAR const void *source);
 
 /* Parent/child data management */
 
diff --git a/sched/group/group_signal.c b/sched/group/group_signal.c
index 09e557318be..17e3ccf0232 100644
--- a/sched/group/group_signal.c
+++ b/sched/group/group_signal.c
@@ -46,6 +46,7 @@
 struct group_signal_s
 {
   FAR siginfo_t *siginfo; /* Signal to be dispatched */
+  FAR const void *source; /* The POSIX timer of the signal, or NULL */
   FAR struct tcb_s *dtcb; /* Default, valid TCB */
   FAR struct tcb_s *utcb; /* TCB with this signal unblocked */
   FAR struct tcb_s *atcb; /* This TCB was awakened */
@@ -111,7 +112,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
        * receive the signal.
        */
 
-      ret = nxsig_tcbdispatch(tcb, info->siginfo, true);
+      ret = nxsig_tcbdispatch(tcb, info->siginfo, true, info->source);
       if (ret < 0)
         {
           return ret;
@@ -153,7 +154,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
            * blocking the signal will receive the signal.
            */
 
-          ret = nxsig_tcbdispatch(tcb, info->siginfo, true);
+          ret = nxsig_tcbdispatch(tcb, info->siginfo, true, info->source);
           if (ret < 0)
             {
               return ret;
@@ -198,7 +199,8 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
  *
  ****************************************************************************/
 
-int group_signal(FAR struct task_group_s *group, FAR siginfo_t *siginfo)
+int group_signal(FAR struct task_group_s *group, FAR siginfo_t *siginfo,
+                 FAR const void *source)
 {
 #ifdef HAVE_GROUP_MEMBERS
   struct group_signal_s info;
@@ -208,6 +210,7 @@ int group_signal(FAR struct task_group_s *group, FAR 
siginfo_t *siginfo)
   DEBUGASSERT(group && siginfo);
 
   info.siginfo = siginfo;
+  info.source  = source;
   info.dtcb    = NULL;     /* Default, valid TCB */
   info.utcb    = NULL;     /* TCB with this signal unblocked */
   info.atcb    = NULL;     /* This TCB was awakened */
@@ -261,7 +264,7 @@ int group_signal(FAR struct task_group_s *group, FAR 
siginfo_t *siginfo)
 
       /* Now deliver the signal to the selected group member */
 
-      ret = nxsig_tcbdispatch(tcb, siginfo, true);
+      ret = nxsig_tcbdispatch(tcb, siginfo, true, source);
     }
 
 errout:
@@ -276,6 +279,7 @@ errout:
 
   UNUSED(group);
   UNUSED(siginfo);
+  UNUSED(source);
   return -ENOSYS;
 
 #endif
diff --git a/sched/pthread/pthread_sigqueue.c b/sched/pthread/pthread_sigqueue.c
index a5ab56c1411..655f8130cce 100644
--- a/sched/pthread/pthread_sigqueue.c
+++ b/sched/pthread/pthread_sigqueue.c
@@ -73,7 +73,7 @@ int pthread_sigqueue(pthread_t thread, int sig, const union 
sigval value)
 
   /* Send the signal */
 
-  err = nxsig_dispatch((pid_t)thread, &info, true);
+  err = nxsig_dispatch((pid_t)thread, &info, true, NULL);
   if (err < 0)
     {
       return -err;
diff --git a/sched/signal/sig_dispatch.c b/sched/signal/sig_dispatch.c
index cc3fe67af3d..7fbfa3cfd88 100644
--- a/sched/signal/sig_dispatch.c
+++ b/sched/signal/sig_dispatch.c
@@ -36,6 +36,7 @@
 
 #include <nuttx/debug.h>
 #include <nuttx/irq.h>
+#include <nuttx/nuttx.h>
 #include <nuttx/arch.h>
 #include <nuttx/signal.h>
 #include <nuttx/queue.h>
@@ -114,6 +115,7 @@ static int sig_handler(FAR void *cookie)
 static int nxsig_queue_action(FAR struct tcb_s *stcb,
                               FAR sigactq_t *sigact,
                               FAR siginfo_t *info,
+                              FAR const void *source,
                               FAR bool *deliver)
 {
   FAR sigq_t    *sigq;
@@ -150,6 +152,7 @@ static int nxsig_queue_action(FAR struct tcb_s *stcb,
 
           memcpy(&sigq->info, info, sizeof(siginfo_t));
           sigq->info.si_user = sigact->act.sa_user;
+          sigq->source = source;
 
           /* Put it at the end of the pending signals list */
 
@@ -314,7 +317,8 @@ nxsig_find_pendingsignal(FAR struct task_group_s *group, 
int signo)
 
 static FAR sigpendq_t *nxsig_add_pendingsignal(FAR struct tcb_s *stcb,
                                                FAR siginfo_t *info,
-                                               bool group_dispatch)
+                                               bool group_dispatch,
+                                               FAR const void *source)
 {
   FAR struct task_group_s *group;
   FAR sigpendq_t *sigpend;
@@ -331,6 +335,7 @@ static FAR sigpendq_t *nxsig_add_pendingsignal(FAR struct 
tcb_s *stcb,
       /* The signal is already pending... retain only one copy */
 
       memcpy(&sigpend->info, info, sizeof(siginfo_t));
+      sigpend->source = source;
     }
 
   /* No... There is nothing pending in the group for this signo */
@@ -345,6 +350,7 @@ static FAR sigpendq_t *nxsig_add_pendingsignal(FAR struct 
tcb_s *stcb,
           /* Put the signal information into the allocated structure */
 
           memcpy(&sigpend->info, info, sizeof(siginfo_t));
+          sigpend->source = source;
 
           /* Mark the tcb which need to receive the signal. If any
            * thread in the group may receive it, set it to NULL
@@ -464,6 +470,38 @@ static int nxsig_alloc_dyn_pending(FAR irqstate_t *flags)
   return ret;
 }
 
+/****************************************************************************
+ * Name: nxsig_action_queued
+ *
+ * Description:
+ *   Return true if a signal signo of source is queued for a handler of tcb.
+ *
+ * Assumptions:
+ *   Called in a critical section.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+static bool nxsig_action_queued(FAR struct tcb_s *tcb,
+                                FAR const void *source, int signo)
+{
+  FAR sq_entry_t *entry;
+
+  for (entry = tcb->sigpendactionq.head; entry != NULL;
+       entry = entry->flink)
+    {
+      FAR sigq_t *sigq = (FAR sigq_t *)entry;
+
+      if (sigq->source == source && sigq->info.si_signo == signo)
+        {
+          return true;
+        }
+    }
+
+  return false;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -485,13 +523,17 @@ static int nxsig_alloc_dyn_pending(FAR irqstate_t *flags)
  *   to dispatch signals since it will *not* follow the group signal
  *   deliver algorithms.
  *
+ *   source is the POSIX timer that sends the signal, or NULL.  It goes into
+ *   the pending or queued entry, so that the timer can see that its signal
+ *   is still queued (nxsig_source_queued()).
+ *
  * Returned Value:
  *   Returns 0 (OK) on success or a negated errno value on failure.
  *
  ****************************************************************************/
 
-int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
-                      bool group_dispatch)
+int nxsig_tcbdispatch(FAR struct tcb_s *stcb, FAR siginfo_t *info,
+                      bool group_dispatch, FAR const void *source)
 {
   FAR struct tcb_s *rtcb = this_task();
   irqstate_t flags;
@@ -630,7 +672,8 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
           if (masked == 0 && !ignored)
             {
-              sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch);
+              sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch,
+                                                source);
             }
 #endif
         }
@@ -641,7 +684,8 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
       else if (!ignored)
         {
-          sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch);
+          sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch,
+                                            source);
         }
     }
 
@@ -656,7 +700,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
       /* Queue any sigaction's requested by this task. */
 
-      ret = nxsig_queue_action(stcb, sigact, info, &deliver);
+      ret = nxsig_queue_action(stcb, sigact, info, source, &deliver);
 #endif
       /* Deliver of the signal must be performed in a critical section */
 
@@ -835,12 +879,15 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
  *     - Get the TCB associated with the pid.
  *     - Call nxsig_tcbdispatch with the TCB
  *
+ *   source is the POSIX timer that sends the signal, or NULL.
+ *
  * Returned Value:
  *   Returns 0 (OK) on success or a negated errno value on failure.
  *
  ****************************************************************************/
 
-int nxsig_dispatch(pid_t pid, FAR siginfo_t *info, bool thread)
+int nxsig_dispatch(pid_t pid, FAR siginfo_t *info, bool thread,
+                   FAR const void *source)
 {
 #ifdef HAVE_GROUP_MEMBERS
   if (!thread)
@@ -853,7 +900,7 @@ int nxsig_dispatch(pid_t pid, FAR siginfo_t *info, bool 
thread)
 
       if (group != NULL)
         {
-          return group_signal(group, info);
+          return group_signal(group, info, source);
         }
     }
   else
@@ -865,9 +912,72 @@ int nxsig_dispatch(pid_t pid, FAR siginfo_t *info, bool 
thread)
 
       if (stcb != NULL)
         {
-          return nxsig_tcbdispatch(stcb, info, false);
+          return nxsig_tcbdispatch(stcb, info, false, source);
         }
     }
 
   return -ESRCH;
 }
+
+/****************************************************************************
+ * Name: nxsig_source_queued
+ *
+ * Description:
+ *   Return true if a signal signo of source (a POSIX timer) is still
+ *   pending or queued for a signal handler in the task group of pid.  A
+ *   signal that a handler runs for, or that sigwaitinfo() accepted, is not
+ *   queued any more.  signo tells the timer from a deleted timer that had
+ *   the same address.
+ *
+ * Assumptions:
+ *   May be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+bool nxsig_source_queued(pid_t pid, FAR const void *source, int signo)
+{
+  FAR struct task_group_s *group;
+  FAR struct tcb_s *tcb;
+  FAR sq_entry_t *entry;
+  irqstate_t flags;
+  bool found = false;
+
+  flags = enter_critical_section();
+  tcb = nxsched_get_tcb(pid);
+  group = tcb != NULL ? tcb->group : NULL;
+  if (group == NULL)
+    {
+      leave_critical_section(flags);
+      return false;
+    }
+
+  /* The pending signals of the group, then the signals queued for a
+   * handler of each thread.  tg_lock also keeps the list of the threads.
+   */
+
+  spin_lock(&group->tg_lock);
+  for (entry = group->tg_sigpendingq.head; entry != NULL && !found;
+       entry = entry->flink)
+    {
+      FAR sigpendq_t *sigpend = (FAR sigpendq_t *)entry;
+
+      found = sigpend->source == source && sigpend->info.si_signo == signo;
+    }
+
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+#  ifdef HAVE_GROUP_MEMBERS
+  for (entry = group->tg_members.head; entry != NULL && !found;
+       entry = entry->flink)
+    {
+      found = nxsig_action_queued(container_of(entry, struct tcb_s, member),
+                                  source, signo);
+    }
+#  else
+  found = found || nxsig_action_queued(tcb, source, signo);
+#  endif
+#endif
+
+  spin_unlock(&group->tg_lock);
+  leave_critical_section(flags);
+  return found;
+}
diff --git a/sched/signal/sig_kill.c b/sched/signal/sig_kill.c
index 1f0f4119286..75bbc5f2661 100644
--- a/sched/signal/sig_kill.c
+++ b/sched/signal/sig_kill.c
@@ -121,7 +121,7 @@ int nxsig_kill(pid_t pid, int signo)
 
   /* Send the signal */
 
-  return nxsig_dispatch(pid, &info, false);
+  return nxsig_dispatch(pid, &info, false, NULL);
 #endif
 }
 
diff --git a/sched/signal/sig_notification.c b/sched/signal/sig_notification.c
index b4389cdffde..1a87ccc7d59 100644
--- a/sched/signal/sig_notification.c
+++ b/sched/signal/sig_notification.c
@@ -138,7 +138,7 @@ int nxsig_event_valid(FAR const struct sigevent *event)
 }
 
 /****************************************************************************
- * Name: nxsig_notification
+ * Name: nxsig_notification_source
  *
  * Description:
  *   Notify a client an event via either a signal or function call
@@ -152,6 +152,7 @@ int nxsig_event_valid(FAR const struct sigevent *event)
  *   work  - The work structure to queue.  Must be non-NULL if
  *           event->sigev_notify == SIGEV_THREAD.  Ignored if
  *           CONFIG_SIG_EVTHREAD is not defined.
+ *   source - The POSIX timer that sends the notification, or NULL
  *
  * Returned Value:
  *   This is an internal OS interface and should not be used by applications.
@@ -160,8 +161,9 @@ int nxsig_event_valid(FAR const struct sigevent *event)
  *
  ****************************************************************************/
 
-int nxsig_notification(pid_t pid, FAR struct sigevent *event,
-                       int code, FAR struct sigwork_s *work)
+int nxsig_notification_source(pid_t pid, FAR struct sigevent *event,
+                              int code, FAR struct sigwork_s *work,
+                              FAR const void *source)
 {
   sinfo("pid=%" PRIu16 " signo=%d code=%d sival_ptr=%p\n",
         pid, event->sigev_signo, code, event->sigev_value.sival_ptr);
@@ -203,7 +205,7 @@ int nxsig_notification(pid_t pid, FAR struct sigevent 
*event,
 
       /* Send the signal */
 
-      return nxsig_dispatch(pid, &info, thread);
+      return nxsig_dispatch(pid, &info, thread, source);
     }
 
 #ifdef CONFIG_SIG_EVTHREAD
@@ -250,3 +252,18 @@ void nxsig_cancel_notification(FAR struct sigwork_s *work)
   work_cancel_sync(SIG_EVTHREAD_WORK, &work->work);
 }
 #endif
+
+/****************************************************************************
+ * Name: nxsig_notification
+ *
+ * Description:
+ *   nxsig_notification_source() for a notification that no POSIX timer
+ *   sends.
+ *
+ ****************************************************************************/
+
+int nxsig_notification(pid_t pid, FAR struct sigevent *event,
+                       int code, FAR struct sigwork_s *work)
+{
+  return nxsig_notification_source(pid, event, code, work, NULL);
+}
diff --git a/sched/signal/sig_queue.c b/sched/signal/sig_queue.c
index e89992da673..cfc9a998f14 100644
--- a/sched/signal/sig_queue.c
+++ b/sched/signal/sig_queue.c
@@ -108,7 +108,7 @@ int nxsig_queue(int pid, int signo, union sigval value)
 
   /* Send the signal */
 
-  return nxsig_dispatch(pid, &info, false);
+  return nxsig_dispatch(pid, &info, false, NULL);
 }
 
 /****************************************************************************
diff --git a/sched/signal/sig_tgkill.c b/sched/signal/sig_tgkill.c
index 0a4c188502a..ac049443e35 100644
--- a/sched/signal/sig_tgkill.c
+++ b/sched/signal/sig_tgkill.c
@@ -112,7 +112,7 @@ int nxsig_tgkill(pid_t pid, pid_t tid, int signo)
   info.si_status          = OK;
 #endif
 
-  ret = nxsig_dispatch(tid, &info, pid == (pid_t)-1);
+  ret = nxsig_dispatch(tid, &info, pid == (pid_t)-1, NULL);
 
 errout:
   return ret;
diff --git a/sched/signal/sig_unmaskpendingsignal.c 
b/sched/signal/sig_unmaskpendingsignal.c
index 54d4ecf2fd8..00a42307da9 100644
--- a/sched/signal/sig_unmaskpendingsignal.c
+++ b/sched/signal/sig_unmaskpendingsignal.c
@@ -51,6 +51,7 @@ static bool nxsig_dispatch_unmasked(FAR struct tcb_s *rtcb)
 {
   sigset_t unmaskedset;
   FAR sigpendq_t *pendingsig;
+  FAR const void *source;
   siginfo_t info;
   bool group;
   int signo;
@@ -103,8 +104,9 @@ static bool nxsig_dispatch_unmasked(FAR struct tcb_s *rtcb)
                * nxsig_tcbdispatch() does not return.
                */
 
-              info  = pendingsig->info;
-              group = pendingsig->tcb == NULL;
+              info   = pendingsig->info;
+              group  = pendingsig->tcb == NULL;
+              source = pendingsig->source;
               nxsig_release_pendingsignal(pendingsig);
 
               /* Process it like a normal signal.  Since the signal was
@@ -113,7 +115,7 @@ static bool nxsig_dispatch_unmasked(FAR struct tcb_s *rtcb)
                * other recipient for the signal other than this thread.
                */
 
-              nxsig_tcbdispatch(rtcb, &info, group);
+              nxsig_tcbdispatch(rtcb, &info, group, source);
             }
         }
     }
diff --git a/sched/signal/signal.h b/sched/signal/signal.h
index 8c43270512f..c1d3eb85b24 100644
--- a/sched/signal/signal.h
+++ b/sched/signal/signal.h
@@ -89,6 +89,7 @@ struct sigpendq
 {
   FAR struct sigpendq *flink;    /* Forward link */
   FAR struct tcb_s *tcb;         /* TCB of thread to deliver to */
+  FAR const void *source;        /* The POSIX timer of the signal, or NULL */
   siginfo_t info;                /* Signal information */
   uint8_t   type;                /* (Used to manage allocations) */
 };
@@ -107,6 +108,7 @@ struct sigq_s
   } action;                      /* Signal action */
   sigset_t  mask;                /* Additional signals to mask while the
                                   * the signal-catching function executes */
+  FAR const void *source;        /* The POSIX timer of the signal, or NULL */
   siginfo_t info;                /* Signal information */
   uint8_t   type;                /* (Used to manage allocations) */
 };
@@ -163,6 +165,7 @@ extern sq_queue_t  g_sigpendingirqsignal;
 /* Forward references */
 
 struct task_group_s;
+struct sigwork_s;
 
 /* sig_initializee.c */
 
@@ -188,9 +191,20 @@ int                nxsig_default_initialize(FAR struct 
tcb_s *tcb);
 
 int                nxsig_tcbdispatch(FAR struct tcb_s *stcb,
                                      FAR siginfo_t *info,
-                                     bool group_dispatch);
+                                     bool group_dispatch,
+                                     FAR const void *source);
 int                nxsig_dispatch(pid_t pid, FAR siginfo_t *info,
-                                  bool thread);
+                                  bool thread, FAR const void *source);
+bool               nxsig_source_queued(pid_t pid, FAR const void *source,
+                                       int signo);
+
+/* sig_notification.c */
+
+int                nxsig_notification_source(pid_t pid,
+                                             FAR struct sigevent *event,
+                                             int code,
+                                             FAR struct sigwork_s *work,
+                                             FAR const void *source);
 
 /* sig_cleanup.c */
 
diff --git a/sched/task/task_exithook.c b/sched/task/task_exithook.c
index e1852aab872..0ff68926c8c 100644
--- a/sched/task/task_exithook.c
+++ b/sched/task/task_exithook.c
@@ -205,7 +205,7 @@ static inline void nxtask_sigchild(pid_t ppid, FAR struct 
tcb_s *ctcb,
 
       /* Send the signal to one thread in the group */
 
-      group_signal(pgrp, &info);
+      group_signal(pgrp, &info, NULL);
     }
 }
 
@@ -261,7 +261,7 @@ static inline void nxtask_sigchild(FAR struct tcb_s *ptcb,
        * can provide the correct si_code value with the signal.
        */
 
-      nxsig_tcbdispatch(ptcb, &info, true);
+      nxsig_tcbdispatch(ptcb, &info, true, NULL);
     }
 }
 
diff --git a/sched/timer/timer.h b/sched/timer/timer.h
index 013c82576f5..baa7e5571bd 100644
--- a/sched/timer/timer.h
+++ b/sched/timer/timer.h
@@ -59,7 +59,7 @@ struct posix_timer_s
   uint8_t          pt_flags;       /* See PT_FLAGS_* definitions */
   uint8_t          pt_crefs;       /* Reference count */
   pid_t            pt_owner;       /* Creator of timer */
-  int              pt_overrun;     /* Overrun time */
+  int              pt_overrun;     /* Overruns since the last signal */
   clock_t          pt_delay;       /* If non-zero, used to reset repetitive 
timers */
   clock_t          pt_expected;    /* Expected absolute time */
   struct wdog_s    pt_wdog;        /* The watchdog that provides the timing */
diff --git a/sched/timer/timer_settime.c b/sched/timer/timer_settime.c
index 136f00ab0a1..68c9f8d1479 100644
--- a/sched/timer/timer_settime.c
+++ b/sched/timer/timer_settime.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <limits.h>
 #include <stdint.h>
 #include <time.h>
 #include <string.h>
@@ -35,6 +36,7 @@
 #include <nuttx/irq.h>
 
 #include "clock/clock.h"
+#include "signal/signal.h"
 #include "timer/timer.h"
 
 #ifndef CONFIG_DISABLE_POSIX_TIMERS
@@ -52,12 +54,38 @@ static void timer_timeout(wdparm_t itimer);
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: timer_overrun
+ *
+ * Description:
+ *   Count n more overruns of the timer, up to DELAYTIMER_MAX.
+ *
+ ****************************************************************************/
+
+static inline void timer_overrun(FAR struct posix_timer_s *timer, clock_t n)
+{
+  if (n >= (clock_t)(DELAYTIMER_MAX - timer->pt_overrun))
+    {
+      timer->pt_overrun = DELAYTIMER_MAX;
+    }
+  else
+    {
+      timer->pt_overrun += (int)n;
+    }
+}
+
 /****************************************************************************
  * Name: timer_signotify
  *
  * Description:
  *   This function basically re-implements nxsig_queue() so that the si_code
- *   can be correctly set to SI_TIMER
+ *   can be correctly set to SI_TIMER.
+ *
+ *   POSIX queues one signal of a timer at a time: while the last one is
+ *   still pending or queued for a signal handler, an expiration is only an
+ *   overrun.  An expiration whose signal cannot be queued (no free pending
+ *   signal in an interrupt handler) is an overrun too.  The overrun count
+ *   starts again with each signal that is queued (timer_getoverrun()).
  *
  * Input Parameters:
  *   timer - A reference to the POSIX timer that just timed out
@@ -72,13 +100,32 @@ static void timer_timeout(wdparm_t itimer);
 
 static inline void timer_signotify(FAR struct posix_timer_s *timer)
 {
+  pid_t pid = timer->pt_owner;
+  int ret;
+
+  if ((timer->pt_event.sigev_notify & SIGEV_THREAD_ID) != 0)
+    {
+      pid = timer->pt_event.sigev_notify_thread_id;
+    }
+
+  if (nxsig_source_queued(pid, timer, timer->pt_event.sigev_signo))
+    {
+      timer_overrun(timer, 1);
+      return;
+    }
+
+  timer->pt_overrun = 0;
 #ifdef CONFIG_SIG_EVTHREAD
-  DEBUGVERIFY(nxsig_notification(timer->pt_owner, &timer->pt_event,
-                                 SI_TIMER, &timer->pt_work));
+  ret = nxsig_notification_source(timer->pt_owner, &timer->pt_event,
+                                  SI_TIMER, &timer->pt_work, timer);
 #else
-  DEBUGVERIFY(nxsig_notification(timer->pt_owner, &timer->pt_event,
-                                 SI_TIMER, NULL));
+  ret = nxsig_notification_source(timer->pt_owner, &timer->pt_event,
+                                  SI_TIMER, NULL, timer);
 #endif
+  if (ret < 0)
+    {
+      timer_overrun(timer, 1);
+    }
 }
 
 /****************************************************************************
@@ -121,14 +168,14 @@ static inline void timer_restart(FAR struct posix_timer_s 
*timer,
        *  |   pt_delay   |   pt_delay   |   pt_delay   | ... |
        *  ^ pt_expected                    ^ ticks     ^ next pt_expected
        * In this case, frame equals 3.
-       * Then, pt_overrun <- frame - 1 and
+       * Then, pt_overrun <- pt_overrun + frame - 1 and
        * the next pt_expected <- pt_expected + frame * pt_delay.
        * Assumption of correctness:
        * (delay + timer->pt_delay) should not overflow.
        */
 
       frame = (delay + timer->pt_delay) / timer->pt_delay;
-      timer->pt_overrun   = (int)(frame - 1u);
+      timer_overrun(timer, frame - 1u);
       timer->pt_expected += frame * timer->pt_delay;
 
       wd_start_abstick(&timer->pt_wdog, timer->pt_expected,

Reply via email to