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,
