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

um: Define timers on a per-CPU basis

Define timers on a per-CPU basis to enable each CPU to have its
own timer. This is a preparation for adding SMP support.

Signed-off-by: Tiwei Bie <tiwei.btw@antgroup.com>
Link: https://patch.msgid.link/20251027001815.1666872-5-tiwei.bie@linux.dev
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Tiwei Bie and committed by
Johannes Berg
9c82de55 2670917c

+69 -31
+3
arch/um/include/linux/time-internal.h
··· 90 90 * which is intentional since we really shouldn't link it in that case. 91 91 */ 92 92 void time_travel_ndelay(unsigned long nsec); 93 + 94 + int um_setup_timer(void); 95 + 93 96 #endif /* __TIMER_INTERNAL_H__ */
+3 -3
arch/um/include/shared/os.h
··· 269 269 /* time.c */ 270 270 extern void os_idle_sleep(void); 271 271 extern int os_timer_create(void); 272 - extern int os_timer_set_interval(unsigned long long nsecs); 273 - extern int os_timer_one_shot(unsigned long long nsecs); 274 - extern void os_timer_disable(void); 272 + extern int os_timer_set_interval(int cpu, unsigned long long nsecs); 273 + extern int os_timer_one_shot(int cpu, unsigned long long nsecs); 274 + extern void os_timer_disable(int cpu); 275 275 extern long long os_persistent_clock_emulation(void); 276 276 extern long long os_nsecs(void); 277 277
+1 -1
arch/um/kernel/irq.c
··· 683 683 { 684 684 int i; 685 685 686 - irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_edge_irq); 686 + irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_percpu_irq); 687 687 688 688 for (i = 1; i < UM_LAST_SIGNAL_IRQ; i++) 689 689 irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
+41 -17
arch/um/kernel/time.c
··· 625 625 * controller application. 626 626 */ 627 627 unsigned long long next = S64_MAX; 628 + int cpu = raw_smp_processor_id(); 628 629 629 630 if (time_travel_mode == TT_MODE_BASIC) 630 - os_timer_disable(); 631 + os_timer_disable(cpu); 631 632 632 633 time_travel_update_time(next, true); 633 634 ··· 639 638 * This is somewhat wrong - we should get the first 640 639 * one sooner like the os_timer_one_shot() below... 641 640 */ 642 - os_timer_set_interval(time_travel_timer_interval); 641 + os_timer_set_interval(cpu, time_travel_timer_interval); 643 642 } else { 644 - os_timer_one_shot(time_travel_timer_event.time - next); 643 + os_timer_one_shot(cpu, time_travel_timer_event.time - next); 645 644 } 646 645 } 647 646 } ··· 759 758 #define time_travel_del_event(e) do { } while (0) 760 759 #endif 761 760 761 + static struct clock_event_device timer_clockevent[NR_CPUS]; 762 + 762 763 void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 763 764 { 764 765 unsigned long flags; ··· 783 780 784 781 static int itimer_shutdown(struct clock_event_device *evt) 785 782 { 783 + int cpu = evt - &timer_clockevent[0]; 784 + 786 785 if (time_travel_mode != TT_MODE_OFF) 787 786 time_travel_del_event(&time_travel_timer_event); 788 787 789 788 if (time_travel_mode != TT_MODE_INFCPU && 790 789 time_travel_mode != TT_MODE_EXTERNAL) 791 - os_timer_disable(); 790 + os_timer_disable(cpu); 792 791 793 792 return 0; 794 793 } ··· 798 793 static int itimer_set_periodic(struct clock_event_device *evt) 799 794 { 800 795 unsigned long long interval = NSEC_PER_SEC / HZ; 796 + int cpu = evt - &timer_clockevent[0]; 801 797 802 798 if (time_travel_mode != TT_MODE_OFF) { 803 799 time_travel_del_event(&time_travel_timer_event); ··· 811 805 812 806 if (time_travel_mode != TT_MODE_INFCPU && 813 807 time_travel_mode != TT_MODE_EXTERNAL) 814 - os_timer_set_interval(interval); 808 + os_timer_set_interval(cpu, interval); 815 809 816 810 return 0; 817 811 } ··· 831 825 832 826 if (time_travel_mode != TT_MODE_INFCPU && 833 827 time_travel_mode != TT_MODE_EXTERNAL) 834 - return os_timer_one_shot(delta); 828 + return os_timer_one_shot(raw_smp_processor_id(), delta); 835 829 836 830 return 0; 837 831 } ··· 841 835 return itimer_next_event(0, evt); 842 836 } 843 837 844 - static struct clock_event_device timer_clockevent = { 838 + static struct clock_event_device _timer_clockevent = { 845 839 .name = "posix-timer", 846 840 .rating = 250, 847 - .cpumask = cpu_possible_mask, 848 841 .features = CLOCK_EVT_FEAT_PERIODIC | 849 842 CLOCK_EVT_FEAT_ONESHOT, 850 843 .set_state_shutdown = itimer_shutdown, ··· 861 856 862 857 static irqreturn_t um_timer(int irq, void *dev) 863 858 { 859 + int cpu = raw_smp_processor_id(); 860 + struct clock_event_device *evt = &timer_clockevent[cpu]; 861 + 864 862 /* 865 863 * Interrupt the (possibly) running userspace process, technically this 866 864 * should only happen if userspace is currently executing. ··· 875 867 get_current()->mm) 876 868 os_alarm_process(get_current()->mm->context.id.pid); 877 869 878 - (*timer_clockevent.event_handler)(&timer_clockevent); 870 + evt->event_handler(evt); 879 871 880 872 return IRQ_HANDLED; 881 873 } ··· 912 904 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 913 905 }; 914 906 915 - static void __init um_timer_setup(void) 907 + int um_setup_timer(void) 908 + { 909 + int cpu = raw_smp_processor_id(); 910 + struct clock_event_device *evt = &timer_clockevent[cpu]; 911 + int err; 912 + 913 + err = os_timer_create(); 914 + if (err) 915 + return err; 916 + 917 + memcpy(evt, &_timer_clockevent, sizeof(*evt)); 918 + evt->cpumask = cpumask_of(cpu); 919 + clockevents_register_device(evt); 920 + 921 + return 0; 922 + } 923 + 924 + static void __init um_timer_init(void) 916 925 { 917 926 int err; 918 927 ··· 938 913 printk(KERN_ERR "register_timer : request_irq failed - " 939 914 "errno = %d\n", -err); 940 915 941 - err = os_timer_create(); 942 - if (err != 0) { 916 + err = um_setup_timer(); 917 + if (err) { 943 918 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); 944 919 return; 945 920 } ··· 949 924 printk(KERN_ERR "clocksource_register_hz returned %d\n", err); 950 925 return; 951 926 } 952 - clockevents_register_device(&timer_clockevent); 953 927 } 954 928 955 929 void read_persistent_clock64(struct timespec64 *ts) ··· 969 945 void __init time_init(void) 970 946 { 971 947 timer_set_signal_handler(); 972 - late_time_init = um_timer_setup; 948 + late_time_init = um_timer_init; 973 949 } 974 950 975 951 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT ··· 985 961 { 986 962 if (strcmp(str, "=inf-cpu") == 0) { 987 963 time_travel_mode = TT_MODE_INFCPU; 988 - timer_clockevent.name = "time-travel-timer-infcpu"; 964 + _timer_clockevent.name = "time-travel-timer-infcpu"; 989 965 timer_clocksource.name = "time-travel-clock"; 990 966 return 1; 991 967 } 992 968 993 969 if (strncmp(str, "=ext:", 5) == 0) { 994 970 time_travel_mode = TT_MODE_EXTERNAL; 995 - timer_clockevent.name = "time-travel-timer-external"; 971 + _timer_clockevent.name = "time-travel-timer-external"; 996 972 timer_clocksource.name = "time-travel-clock-external"; 997 973 return time_travel_connect_external(str + 5); 998 974 } 999 975 1000 976 if (!*str) { 1001 977 time_travel_mode = TT_MODE_BASIC; 1002 - timer_clockevent.name = "time-travel-timer"; 978 + _timer_clockevent.name = "time-travel-timer"; 1003 979 timer_clocksource.name = "time-travel-clock"; 1004 980 return 1; 1005 981 }
+1 -1
arch/um/os-Linux/main.c
··· 171 171 */ 172 172 173 173 /* stop timers and set timer signal to be ignored */ 174 - os_timer_disable(); 174 + os_timer_disable(0); 175 175 176 176 /* disable SIGIO for the fds and set SIGIO to be ignored */ 177 177 err = deactivate_all_fds();
+20 -9
arch/um/os-Linux/time.c
··· 17 17 #include <string.h> 18 18 #include "internal.h" 19 19 20 - static timer_t event_high_res_timer = 0; 20 + static timer_t event_high_res_timer[CONFIG_NR_CPUS] = { 0 }; 21 21 22 22 static inline long long timespec_to_ns(const struct timespec *ts) 23 23 { ··· 32 32 return timespec_to_ns(&realtime_tp); 33 33 } 34 34 35 + #ifndef sigev_notify_thread_id 36 + #define sigev_notify_thread_id _sigev_un._tid 37 + #endif 38 + 35 39 /** 36 40 * os_timer_create() - create an new posix (interval) timer 37 41 */ 38 42 int os_timer_create(void) 39 43 { 40 - timer_t *t = &event_high_res_timer; 44 + timer_t *t = &event_high_res_timer[0]; 45 + struct sigevent sev = { 46 + .sigev_notify = SIGEV_THREAD_ID, 47 + .sigev_signo = SIGALRM, 48 + .sigev_value.sival_ptr = t, 49 + .sigev_notify_thread_id = gettid(), 50 + }; 41 51 42 - if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1) 52 + if (timer_create(CLOCK_MONOTONIC, &sev, t) == -1) 43 53 return -1; 44 54 45 55 return 0; 46 56 } 47 57 48 - int os_timer_set_interval(unsigned long long nsecs) 58 + int os_timer_set_interval(int cpu, unsigned long long nsecs) 49 59 { 50 60 struct itimerspec its; 51 61 ··· 65 55 its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC; 66 56 its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC; 67 57 68 - if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1) 58 + if (timer_settime(event_high_res_timer[cpu], 0, &its, NULL) == -1) 69 59 return -errno; 70 60 71 61 return 0; 72 62 } 73 63 74 - int os_timer_one_shot(unsigned long long nsecs) 64 + int os_timer_one_shot(int cpu, unsigned long long nsecs) 75 65 { 76 66 struct itimerspec its = { 77 67 .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC, ··· 81 71 .it_interval.tv_nsec = 0, // we cheat here 82 72 }; 83 73 84 - timer_settime(event_high_res_timer, 0, &its, NULL); 74 + timer_settime(event_high_res_timer[cpu], 0, &its, NULL); 85 75 return 0; 86 76 } 87 77 88 78 /** 89 79 * os_timer_disable() - disable the posix (interval) timer 80 + * @cpu: the CPU for which the timer is to be disabled 90 81 */ 91 - void os_timer_disable(void) 82 + void os_timer_disable(int cpu) 92 83 { 93 84 struct itimerspec its; 94 85 95 86 memset(&its, 0, sizeof(struct itimerspec)); 96 - timer_settime(event_high_res_timer, 0, &its, NULL); 87 + timer_settime(event_high_res_timer[cpu], 0, &its, NULL); 97 88 } 98 89 99 90 long long os_nsecs(void)