aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2019-08-26 14:22:24 -0400
committerThomas Gleixner <tglx@linutronix.de>2019-08-28 05:50:39 -0400
commit87dc64480fb19a6a0fedbdff1e2557be50673287 (patch)
treea3e0e5cc5769ecc2683bee0e8485a48436206a9e
parent46b883995c88520f2c4de6a64cccc04c69d59f83 (diff)
posix-cpu-timers: Restructure expiry array
Now that the abused struct task_cputime is gone, it's more natural to bundle the expiry cache and the list head of each clock into a struct and have an array of those structs. Follow the hrtimer naming convention of 'bases' and rename the expiry cache to 'nextevt' and adapt all usage sites. Generates also better code .text size shrinks by 80 bytes. Suggested-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1908262021140.1939@nanos.tec.linutronix.de
-rw-r--r--include/linux/posix-timers.h41
-rw-r--r--kernel/time/posix-cpu-timers.c105
2 files changed, 83 insertions, 63 deletions
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index fd9098467d6d..64bd10d251fe 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -63,24 +63,33 @@ static inline int clockid_to_fd(const clockid_t clk)
63} 63}
64 64
65#ifdef CONFIG_POSIX_TIMERS 65#ifdef CONFIG_POSIX_TIMERS
66
66/** 67/**
67 * posix_cputimers - Container for posix CPU timer related data 68 * posix_cputimer_base - Container per posix CPU clock
68 * @expiries: Earliest-expiration cache array based 69 * @nextevt: Earliest-expiration cache
69 * @cpu_timers: List heads to queue posix CPU timers 70 * @cpu_timers: List heads to queue posix CPU timers
71 */
72struct posix_cputimer_base {
73 u64 nextevt;
74 struct list_head cpu_timers;
75};
76
77/**
78 * posix_cputimers - Container for posix CPU timer related data
79 * @bases: Base container for posix CPU clocks
70 * 80 *
71 * Used in task_struct and signal_struct 81 * Used in task_struct and signal_struct
72 */ 82 */
73struct posix_cputimers { 83struct posix_cputimers {
74 u64 expiries[CPUCLOCK_MAX]; 84 struct posix_cputimer_base bases[CPUCLOCK_MAX];
75 struct list_head cpu_timers[CPUCLOCK_MAX];
76}; 85};
77 86
78static inline void posix_cputimers_init(struct posix_cputimers *pct) 87static inline void posix_cputimers_init(struct posix_cputimers *pct)
79{ 88{
80 memset(&pct->expiries, 0, sizeof(pct->expiries)); 89 memset(pct->bases, 0, sizeof(pct->bases));
81 INIT_LIST_HEAD(&pct->cpu_timers[0]); 90 INIT_LIST_HEAD(&pct->bases[0].cpu_timers);
82 INIT_LIST_HEAD(&pct->cpu_timers[1]); 91 INIT_LIST_HEAD(&pct->bases[1].cpu_timers);
83 INIT_LIST_HEAD(&pct->cpu_timers[2]); 92 INIT_LIST_HEAD(&pct->bases[2].cpu_timers);
84} 93}
85 94
86void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit); 95void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit);
@@ -88,19 +97,23 @@ void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit);
88static inline void posix_cputimers_rt_watchdog(struct posix_cputimers *pct, 97static inline void posix_cputimers_rt_watchdog(struct posix_cputimers *pct,
89 u64 runtime) 98 u64 runtime)
90{ 99{
91 pct->expiries[CPUCLOCK_SCHED] = runtime; 100 pct->bases[CPUCLOCK_SCHED].nextevt = runtime;
92} 101}
93 102
94/* Init task static initializer */ 103/* Init task static initializer */
95#define INIT_CPU_TIMERLISTS(c) { \ 104#define INIT_CPU_TIMERBASE(b) { \
96 LIST_HEAD_INIT(c.cpu_timers[0]), \ 105 .cpu_timers = LIST_HEAD_INIT(b.cpu_timers), \
97 LIST_HEAD_INIT(c.cpu_timers[1]), \ 106}
98 LIST_HEAD_INIT(c.cpu_timers[2]), \ 107
108#define INIT_CPU_TIMERBASES(b) { \
109 INIT_CPU_TIMERBASE(b[0]), \
110 INIT_CPU_TIMERBASE(b[1]), \
111 INIT_CPU_TIMERBASE(b[2]), \
99} 112}
100 113
101#define INIT_CPU_TIMERS(s) \ 114#define INIT_CPU_TIMERS(s) \
102 .posix_cputimers = { \ 115 .posix_cputimers = { \
103 .cpu_timers = INIT_CPU_TIMERLISTS(s.posix_cputimers), \ 116 .bases = INIT_CPU_TIMERBASES(s.posix_cputimers.bases), \
104 }, 117 },
105#else 118#else
106struct posix_cputimers { }; 119struct posix_cputimers { };
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index ffd49181e23d..9ac601abc4c4 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -24,13 +24,13 @@ void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit)
24{ 24{
25 posix_cputimers_init(pct); 25 posix_cputimers_init(pct);
26 if (cpu_limit != RLIM_INFINITY) 26 if (cpu_limit != RLIM_INFINITY)
27 pct->expiries[CPUCLOCK_PROF] = cpu_limit * NSEC_PER_SEC; 27 pct->bases[CPUCLOCK_PROF].nextevt = cpu_limit * NSEC_PER_SEC;
28} 28}
29 29
30/* 30/*
31 * Called after updating RLIMIT_CPU to run cpu timer and update 31 * Called after updating RLIMIT_CPU to run cpu timer and update
32 * tsk->signal->posix_cputimers.expiries expiration cache if 32 * tsk->signal->posix_cputimers.bases[clock].nextevt expiration cache if
33 * necessary. Needs siglock protection since other code may update 33 * necessary. Needs siglock protection since other code may update the
34 * expiration cache as well. 34 * expiration cache as well.
35 */ 35 */
36void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new) 36void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
@@ -122,9 +122,11 @@ static void bump_cpu_timer(struct k_itimer *timer, u64 now)
122 } 122 }
123} 123}
124 124
125static inline bool expiry_cache_is_zero(const u64 *ec) 125static inline bool expiry_cache_is_zero(const struct posix_cputimers *pct)
126{ 126{
127 return !(ec[CPUCLOCK_PROF] | ec[CPUCLOCK_VIRT] | ec[CPUCLOCK_SCHED]); 127 return !(pct->bases[CPUCLOCK_PROF].nextevt |
128 pct->bases[CPUCLOCK_VIRT].nextevt |
129 pct->bases[CPUCLOCK_SCHED].nextevt);
128} 130}
129 131
130static int 132static int
@@ -432,9 +434,9 @@ static void cleanup_timers_list(struct list_head *head)
432 */ 434 */
433static void cleanup_timers(struct posix_cputimers *pct) 435static void cleanup_timers(struct posix_cputimers *pct)
434{ 436{
435 cleanup_timers_list(&pct->cpu_timers[CPUCLOCK_PROF]); 437 cleanup_timers_list(&pct->bases[CPUCLOCK_PROF].cpu_timers);
436 cleanup_timers_list(&pct->cpu_timers[CPUCLOCK_VIRT]); 438 cleanup_timers_list(&pct->bases[CPUCLOCK_VIRT].cpu_timers);
437 cleanup_timers_list(&pct->cpu_timers[CPUCLOCK_SCHED]); 439 cleanup_timers_list(&pct->bases[CPUCLOCK_SCHED].cpu_timers);
438} 440}
439 441
440/* 442/*
@@ -464,21 +466,19 @@ static void arm_timer(struct k_itimer *timer)
464{ 466{
465 struct cpu_timer_list *const nt = &timer->it.cpu; 467 struct cpu_timer_list *const nt = &timer->it.cpu;
466 int clkidx = CPUCLOCK_WHICH(timer->it_clock); 468 int clkidx = CPUCLOCK_WHICH(timer->it_clock);
467 u64 *cpuexp, newexp = timer->it.cpu.expires;
468 struct task_struct *p = timer->it.cpu.task; 469 struct task_struct *p = timer->it.cpu.task;
470 u64 newexp = timer->it.cpu.expires;
471 struct posix_cputimer_base *base;
469 struct list_head *head, *listpos; 472 struct list_head *head, *listpos;
470 struct cpu_timer_list *next; 473 struct cpu_timer_list *next;
471 474
472 if (CPUCLOCK_PERTHREAD(timer->it_clock)) { 475 if (CPUCLOCK_PERTHREAD(timer->it_clock))
473 head = p->posix_cputimers.cpu_timers + clkidx; 476 base = p->posix_cputimers.bases + clkidx;
474 cpuexp = p->posix_cputimers.expiries + clkidx; 477 else
475 } else { 478 base = p->signal->posix_cputimers.bases + clkidx;
476 head = p->signal->posix_cputimers.cpu_timers + clkidx;
477 cpuexp = p->signal->posix_cputimers.expiries + clkidx;
478 }
479 479
480 listpos = head; 480 listpos = head = &base->cpu_timers;
481 list_for_each_entry(next, head, entry) { 481 list_for_each_entry(next,head, entry) {
482 if (nt->expires < next->expires) 482 if (nt->expires < next->expires)
483 break; 483 break;
484 listpos = &next->entry; 484 listpos = &next->entry;
@@ -494,8 +494,8 @@ static void arm_timer(struct k_itimer *timer)
494 * for process timers we share expiration cache with itimers 494 * for process timers we share expiration cache with itimers
495 * and RLIMIT_CPU and for thread timers with RLIMIT_RTTIME. 495 * and RLIMIT_CPU and for thread timers with RLIMIT_RTTIME.
496 */ 496 */
497 if (expires_gt(*cpuexp, newexp)) 497 if (expires_gt(base->nextevt, newexp))
498 *cpuexp = newexp; 498 base->nextevt = newexp;
499 499
500 if (CPUCLOCK_PERTHREAD(timer->it_clock)) 500 if (CPUCLOCK_PERTHREAD(timer->it_clock))
501 tick_dep_set_task(p, TICK_DEP_BIT_POSIX_TIMER); 501 tick_dep_set_task(p, TICK_DEP_BIT_POSIX_TIMER);
@@ -783,9 +783,9 @@ static inline void check_dl_overrun(struct task_struct *tsk)
783static void check_thread_timers(struct task_struct *tsk, 783static void check_thread_timers(struct task_struct *tsk,
784 struct list_head *firing) 784 struct list_head *firing)
785{ 785{
786 struct list_head *timers = tsk->posix_cputimers.cpu_timers; 786 struct posix_cputimer_base *base = tsk->posix_cputimers.bases;
787 u64 stime, utime, *expires = tsk->posix_cputimers.expiries;
788 unsigned long soft; 787 unsigned long soft;
788 u64 stime, utime;
789 789
790 if (dl_task(tsk)) 790 if (dl_task(tsk))
791 check_dl_overrun(tsk); 791 check_dl_overrun(tsk);
@@ -794,14 +794,18 @@ static void check_thread_timers(struct task_struct *tsk,
794 * If the expiry cache is zero, then there are no active per thread 794 * If the expiry cache is zero, then there are no active per thread
795 * CPU timers. 795 * CPU timers.
796 */ 796 */
797 if (expiry_cache_is_zero(tsk->posix_cputimers.expiries)) 797 if (expiry_cache_is_zero(&tsk->posix_cputimers))
798 return; 798 return;
799 799
800 task_cputime(tsk, &utime, &stime); 800 task_cputime(tsk, &utime, &stime);
801 801
802 *expires++ = check_timers_list(timers, firing, utime + stime); 802 base->nextevt = check_timers_list(&base->cpu_timers, firing,
803 *expires++ = check_timers_list(++timers, firing, utime); 803 utime + stime);
804 *expires = check_timers_list(++timers, firing, tsk->se.sum_exec_runtime); 804 base++;
805 base->nextevt = check_timers_list(&base->cpu_timers, firing, utime);
806 base++;
807 base->nextevt = check_timers_list(&base->cpu_timers, firing,
808 tsk->se.sum_exec_runtime);
805 809
806 /* 810 /*
807 * Check for the special case thread timers. 811 * Check for the special case thread timers.
@@ -840,7 +844,7 @@ static void check_thread_timers(struct task_struct *tsk,
840 } 844 }
841 } 845 }
842 846
843 if (expiry_cache_is_zero(tsk->posix_cputimers.expiries)) 847 if (expiry_cache_is_zero(&tsk->posix_cputimers))
844 tick_dep_clear_task(tsk, TICK_DEP_BIT_POSIX_TIMER); 848 tick_dep_clear_task(tsk, TICK_DEP_BIT_POSIX_TIMER);
845} 849}
846 850
@@ -884,7 +888,7 @@ static void check_process_timers(struct task_struct *tsk,
884 struct list_head *firing) 888 struct list_head *firing)
885{ 889{
886 struct signal_struct *const sig = tsk->signal; 890 struct signal_struct *const sig = tsk->signal;
887 struct list_head *timers = sig->posix_cputimers.cpu_timers; 891 struct posix_cputimer_base *base = sig->posix_cputimers.bases;
888 u64 utime, ptime, virt_expires, prof_expires; 892 u64 utime, ptime, virt_expires, prof_expires;
889 u64 sum_sched_runtime, sched_expires; 893 u64 sum_sched_runtime, sched_expires;
890 struct task_cputime cputime; 894 struct task_cputime cputime;
@@ -912,9 +916,12 @@ static void check_process_timers(struct task_struct *tsk,
912 ptime = utime + cputime.stime; 916 ptime = utime + cputime.stime;
913 sum_sched_runtime = cputime.sum_exec_runtime; 917 sum_sched_runtime = cputime.sum_exec_runtime;
914 918
915 prof_expires = check_timers_list(timers, firing, ptime); 919 prof_expires = check_timers_list(&base[CPUCLOCK_PROF].cpu_timers,
916 virt_expires = check_timers_list(++timers, firing, utime); 920 firing, ptime);
917 sched_expires = check_timers_list(++timers, firing, sum_sched_runtime); 921 virt_expires = check_timers_list(&base[CPUCLOCK_VIRT].cpu_timers,
922 firing, utime);
923 sched_expires = check_timers_list(&base[CPUCLOCK_SCHED].cpu_timers,
924 firing, sum_sched_runtime);
918 925
919 /* 926 /*
920 * Check for the special case process timers. 927 * Check for the special case process timers.
@@ -959,11 +966,11 @@ static void check_process_timers(struct task_struct *tsk,
959 prof_expires = x; 966 prof_expires = x;
960 } 967 }
961 968
962 sig->posix_cputimers.expiries[CPUCLOCK_PROF] = prof_expires; 969 base[CPUCLOCK_PROF].nextevt = prof_expires;
963 sig->posix_cputimers.expiries[CPUCLOCK_VIRT] = virt_expires; 970 base[CPUCLOCK_VIRT].nextevt = virt_expires;
964 sig->posix_cputimers.expiries[CPUCLOCK_SCHED] = sched_expires; 971 base[CPUCLOCK_SCHED].nextevt = sched_expires;
965 972
966 if (expiry_cache_is_zero(sig->posix_cputimers.expiries)) 973 if (expiry_cache_is_zero(&sig->posix_cputimers))
967 stop_process_timers(sig); 974 stop_process_timers(sig);
968 975
969 sig->cputimer.checking_timer = false; 976 sig->cputimer.checking_timer = false;
@@ -1028,20 +1035,21 @@ unlock:
1028} 1035}
1029 1036
1030/** 1037/**
1031 * task_cputimers_expired - Compare two task_cputime entities. 1038 * task_cputimers_expired - Check whether posix CPU timers are expired
1032 * 1039 *
1033 * @samples: Array of current samples for the CPUCLOCK clocks 1040 * @samples: Array of current samples for the CPUCLOCK clocks
1034 * @expiries: Array of expiry values for the CPUCLOCK clocks 1041 * @pct: Pointer to a posix_cputimers container
1035 * 1042 *
1036 * Returns true if any mmember of @samples is greater than the corresponding 1043 * Returns true if any member of @samples is greater than the corresponding
1037 * member of @expiries if that member is non zero. False otherwise 1044 * member of @pct->bases[CLK].nextevt. False otherwise
1038 */ 1045 */
1039static inline bool task_cputimers_expired(const u64 *sample, const u64 *expiries) 1046static inline bool
1047task_cputimers_expired(const u64 *sample, struct posix_cputimers *pct)
1040{ 1048{
1041 int i; 1049 int i;
1042 1050
1043 for (i = 0; i < CPUCLOCK_MAX; i++) { 1051 for (i = 0; i < CPUCLOCK_MAX; i++) {
1044 if (expiries[i] && sample[i] >= expiries[i]) 1052 if (pct->bases[i].nextevt && sample[i] >= pct->bases[i].nextevt)
1045 return true; 1053 return true;
1046 } 1054 }
1047 return false; 1055 return false;
@@ -1059,14 +1067,13 @@ static inline bool task_cputimers_expired(const u64 *sample, const u64 *expiries
1059 */ 1067 */
1060static inline bool fastpath_timer_check(struct task_struct *tsk) 1068static inline bool fastpath_timer_check(struct task_struct *tsk)
1061{ 1069{
1062 u64 *expiries = tsk->posix_cputimers.expiries;
1063 struct signal_struct *sig; 1070 struct signal_struct *sig;
1064 1071
1065 if (!expiry_cache_is_zero(expiries)) { 1072 if (!expiry_cache_is_zero(&tsk->posix_cputimers)) {
1066 u64 samples[CPUCLOCK_MAX]; 1073 u64 samples[CPUCLOCK_MAX];
1067 1074
1068 task_sample_cputime(tsk, samples); 1075 task_sample_cputime(tsk, samples);
1069 if (task_cputimers_expired(samples, expiries)) 1076 if (task_cputimers_expired(samples, &tsk->posix_cputimers))
1070 return true; 1077 return true;
1071 } 1078 }
1072 1079
@@ -1092,8 +1099,7 @@ static inline bool fastpath_timer_check(struct task_struct *tsk)
1092 proc_sample_cputime_atomic(&sig->cputimer.cputime_atomic, 1099 proc_sample_cputime_atomic(&sig->cputimer.cputime_atomic,
1093 samples); 1100 samples);
1094 1101
1095 if (task_cputimers_expired(samples, 1102 if (task_cputimers_expired(samples, &sig->posix_cputimers))
1096 sig->posix_cputimers.expiries))
1097 return true; 1103 return true;
1098 } 1104 }
1099 1105
@@ -1176,11 +1182,12 @@ void run_posix_cpu_timers(void)
1176void set_process_cpu_timer(struct task_struct *tsk, unsigned int clkid, 1182void set_process_cpu_timer(struct task_struct *tsk, unsigned int clkid,
1177 u64 *newval, u64 *oldval) 1183 u64 *newval, u64 *oldval)
1178{ 1184{
1179 u64 now, *expiry = tsk->signal->posix_cputimers.expiries + clkid; 1185 u64 now, *nextevt;
1180 1186
1181 if (WARN_ON_ONCE(clkid >= CPUCLOCK_SCHED)) 1187 if (WARN_ON_ONCE(clkid >= CPUCLOCK_SCHED))
1182 return; 1188 return;
1183 1189
1190 nextevt = &tsk->signal->posix_cputimers.bases[clkid].nextevt;
1184 now = cpu_clock_sample_group(clkid, tsk, true); 1191 now = cpu_clock_sample_group(clkid, tsk, true);
1185 1192
1186 if (oldval) { 1193 if (oldval) {
@@ -1207,8 +1214,8 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clkid,
1207 * Update expiration cache if this is the earliest timer. CPUCLOCK_PROF 1214 * Update expiration cache if this is the earliest timer. CPUCLOCK_PROF
1208 * expiry cache is also used by RLIMIT_CPU!. 1215 * expiry cache is also used by RLIMIT_CPU!.
1209 */ 1216 */
1210 if (expires_gt(*expiry, *newval)) 1217 if (expires_gt(*nextevt, *newval))
1211 *expiry = *newval; 1218 *nextevt = *newval;
1212 1219
1213 tick_dep_set_signal(tsk->signal, TICK_DEP_BIT_POSIX_TIMER); 1220 tick_dep_set_signal(tsk->signal, TICK_DEP_BIT_POSIX_TIMER);
1214} 1221}