summaryrefslogtreecommitdiff
path: root/arch/um/os-Linux
diff options
context:
space:
mode:
authorTiwei Bie <tiwei.btw@antgroup.com>2025-10-27 08:18:10 +0800
committerJohannes Berg <johannes.berg@intel.com>2025-10-27 16:41:15 +0100
commit2670917c2fc8902558f3aba4f41e5cc5bf6e18fa (patch)
tree257b673beaa85834ea9af4e664ba34c71c40b7ad /arch/um/os-Linux
parent9e5a9f1c9b336871c8e76c1cefd85182c5b58541 (diff)
um: Determine sleep based on need_resched()
With SMP and NO_HZ enabled, the CPU may still need to sleep even if the timer is disarmed. Switch to deciding whether to sleep based on pending resched. Additionally, because disabling IRQs does not block SIGALRM, it is also necessary to check for any pending timer alarms. This is a preparation for adding SMP support. Signed-off-by: Tiwei Bie <tiwei.btw@antgroup.com> Link: https://patch.msgid.link/20251027001815.1666872-4-tiwei.bie@linux.dev Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r--arch/um/os-Linux/internal.h5
-rw-r--r--arch/um/os-Linux/signal.c6
-rw-r--r--arch/um/os-Linux/time.c15
3 files changed, 20 insertions, 6 deletions
diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h
index 5d8d3b0817a9..c2c7a0dc673c 100644
--- a/arch/um/os-Linux/internal.h
+++ b/arch/um/os-Linux/internal.h
@@ -16,6 +16,11 @@ void scan_elf_aux(char **envp);
void check_tmpexec(void);
/*
+ * signal.c
+ */
+int timer_alarm_pending(void);
+
+/*
* skas/process.c
*/
void wait_stub_done(int pid);
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 58da8c6ece98..554a87dd32cc 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -20,6 +20,7 @@
#include <um_malloc.h>
#include <sys/ucontext.h>
#include <timetravel.h>
+#include "internal.h"
void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *mc) = {
[SIGTRAP] = relay_signal,
@@ -159,6 +160,11 @@ void timer_set_signal_handler(void)
set_handler(SIGALRM);
}
+int timer_alarm_pending(void)
+{
+ return !!(signals_pending & SIGALRM_MASK);
+}
+
void set_sigstack(void *sig_stack, int size)
{
stack_t stack = {
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index 4d5591d96d8c..f3d4547e5227 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -15,6 +15,7 @@
#include <kern_util.h>
#include <os.h>
#include <string.h>
+#include "internal.h"
static timer_t event_high_res_timer = 0;
@@ -98,18 +99,20 @@ long long os_nsecs(void)
*/
void os_idle_sleep(void)
{
- struct itimerspec its;
sigset_t set, old;
- /* block SIGALRM while we analyze the timer state */
+ /* Block SIGALRM while performing the need_resched check. */
sigemptyset(&set);
sigaddset(&set, SIGALRM);
sigprocmask(SIG_BLOCK, &set, &old);
- /* check the timer, and if it'll fire then wait for it */
- timer_gettime(event_high_res_timer, &its);
- if (its.it_value.tv_sec || its.it_value.tv_nsec)
+ /*
+ * Because disabling IRQs does not block SIGALRM, it is also
+ * necessary to check for any pending timer alarms.
+ */
+ if (!uml_need_resched() && !timer_alarm_pending())
sigsuspend(&old);
- /* either way, restore the signal mask */
+
+ /* Restore the signal mask. */
sigprocmask(SIG_UNBLOCK, &set, NULL);
}