Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tiwei Bie and committed by
Johannes Berg
2670917c 9e5a9f1c

+26 -6
+1
arch/um/include/shared/kern_util.h
··· 51 51 extern int get_current_pid(void); 52 52 extern int copy_from_user_proc(void *to, void *from, int size); 53 53 extern char *uml_strdup(const char *string); 54 + int uml_need_resched(void); 54 55 55 56 extern unsigned long to_irq_stack(unsigned long *mask_out); 56 57 extern unsigned long from_irq_stack(int nested);
+5
arch/um/kernel/process.c
··· 223 223 /* Is in_interrupt() really needed? */ 224 224 } 225 225 226 + int uml_need_resched(void) 227 + { 228 + return need_resched(); 229 + } 230 + 226 231 extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; 227 232 228 233 void do_uml_exitcalls(void)
+5
arch/um/os-Linux/internal.h
··· 16 16 void check_tmpexec(void); 17 17 18 18 /* 19 + * signal.c 20 + */ 21 + int timer_alarm_pending(void); 22 + 23 + /* 19 24 * skas/process.c 20 25 */ 21 26 void wait_stub_done(int pid);
+6
arch/um/os-Linux/signal.c
··· 20 20 #include <um_malloc.h> 21 21 #include <sys/ucontext.h> 22 22 #include <timetravel.h> 23 + #include "internal.h" 23 24 24 25 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *mc) = { 25 26 [SIGTRAP] = relay_signal, ··· 158 157 void timer_set_signal_handler(void) 159 158 { 160 159 set_handler(SIGALRM); 160 + } 161 + 162 + int timer_alarm_pending(void) 163 + { 164 + return !!(signals_pending & SIGALRM_MASK); 161 165 } 162 166 163 167 void set_sigstack(void *sig_stack, int size)
+9 -6
arch/um/os-Linux/time.c
··· 15 15 #include <kern_util.h> 16 16 #include <os.h> 17 17 #include <string.h> 18 + #include "internal.h" 18 19 19 20 static timer_t event_high_res_timer = 0; 20 21 ··· 99 98 */ 100 99 void os_idle_sleep(void) 101 100 { 102 - struct itimerspec its; 103 101 sigset_t set, old; 104 102 105 - /* block SIGALRM while we analyze the timer state */ 103 + /* Block SIGALRM while performing the need_resched check. */ 106 104 sigemptyset(&set); 107 105 sigaddset(&set, SIGALRM); 108 106 sigprocmask(SIG_BLOCK, &set, &old); 109 107 110 - /* check the timer, and if it'll fire then wait for it */ 111 - timer_gettime(event_high_res_timer, &its); 112 - if (its.it_value.tv_sec || its.it_value.tv_nsec) 108 + /* 109 + * Because disabling IRQs does not block SIGALRM, it is also 110 + * necessary to check for any pending timer alarms. 111 + */ 112 + if (!uml_need_resched() && !timer_alarm_pending()) 113 113 sigsuspend(&old); 114 - /* either way, restore the signal mask */ 114 + 115 + /* Restore the signal mask. */ 115 116 sigprocmask(SIG_UNBLOCK, &set, NULL); 116 117 }