diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2019-08-21 15:09:24 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2019-08-28 05:50:42 -0400 |
commit | 244d49e30653658d4e7e9b2b8427777cbbc5affe (patch) | |
tree | 97754f775acd11c4bc98b43f69234dfb525cb175 | |
parent | 8991afe2640d05a805eba01277856e8549cdc838 (diff) |
posix-cpu-timers: Move state tracking to struct posix_cputimers
Put it where it belongs and clean up the ifdeffery in fork completely.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20190821192922.743229404@linutronix.de
-rw-r--r-- | include/linux/posix-timers.h | 8 | ||||
-rw-r--r-- | include/linux/sched/cputime.h | 9 | ||||
-rw-r--r-- | include/linux/sched/signal.h | 6 | ||||
-rw-r--r-- | init/init_task.c | 2 | ||||
-rw-r--r-- | kernel/fork.c | 6 | ||||
-rw-r--r-- | kernel/time/posix-cpu-timers.c | 73 |
6 files changed, 54 insertions, 50 deletions
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 3ea920e8fe7f..a9e3f69d2db4 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h | |||
@@ -77,15 +77,23 @@ struct posix_cputimer_base { | |||
77 | /** | 77 | /** |
78 | * posix_cputimers - Container for posix CPU timer related data | 78 | * posix_cputimers - Container for posix CPU timer related data |
79 | * @bases: Base container for posix CPU clocks | 79 | * @bases: Base container for posix CPU clocks |
80 | * @timers_active: Timers are queued. | ||
81 | * @expiry_active: Timer expiry is active. Used for | ||
82 | * process wide timers to avoid multiple | ||
83 | * task trying to handle expiry concurrently | ||
80 | * | 84 | * |
81 | * Used in task_struct and signal_struct | 85 | * Used in task_struct and signal_struct |
82 | */ | 86 | */ |
83 | struct posix_cputimers { | 87 | struct posix_cputimers { |
84 | struct posix_cputimer_base bases[CPUCLOCK_MAX]; | 88 | struct posix_cputimer_base bases[CPUCLOCK_MAX]; |
89 | unsigned int timers_active; | ||
90 | unsigned int expiry_active; | ||
85 | }; | 91 | }; |
86 | 92 | ||
87 | static inline void posix_cputimers_init(struct posix_cputimers *pct) | 93 | static inline void posix_cputimers_init(struct posix_cputimers *pct) |
88 | { | 94 | { |
95 | pct->timers_active = 0; | ||
96 | pct->expiry_active = 0; | ||
89 | pct->bases[0].nextevt = U64_MAX; | 97 | pct->bases[0].nextevt = U64_MAX; |
90 | pct->bases[1].nextevt = U64_MAX; | 98 | pct->bases[1].nextevt = U64_MAX; |
91 | pct->bases[2].nextevt = U64_MAX; | 99 | pct->bases[2].nextevt = U64_MAX; |
diff --git a/include/linux/sched/cputime.h b/include/linux/sched/cputime.h index eefa5dff16b4..6c9f19a33865 100644 --- a/include/linux/sched/cputime.h +++ b/include/linux/sched/cputime.h | |||
@@ -70,7 +70,7 @@ void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples); | |||
70 | */ | 70 | */ |
71 | 71 | ||
72 | /** | 72 | /** |
73 | * get_running_cputimer - return &tsk->signal->cputimer if cputimer is running | 73 | * get_running_cputimer - return &tsk->signal->cputimer if cputimers are active |
74 | * | 74 | * |
75 | * @tsk: Pointer to target task. | 75 | * @tsk: Pointer to target task. |
76 | */ | 76 | */ |
@@ -80,8 +80,11 @@ struct thread_group_cputimer *get_running_cputimer(struct task_struct *tsk) | |||
80 | { | 80 | { |
81 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; | 81 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; |
82 | 82 | ||
83 | /* Check if cputimer isn't running. This is accessed without locking. */ | 83 | /* |
84 | if (!READ_ONCE(cputimer->running)) | 84 | * Check whether posix CPU timers are active. If not the thread |
85 | * group accounting is not active either. Lockless check. | ||
86 | */ | ||
87 | if (!READ_ONCE(tsk->signal->posix_cputimers.timers_active)) | ||
85 | return NULL; | 88 | return NULL; |
86 | 89 | ||
87 | /* | 90 | /* |
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 729bd892ee45..88050259c466 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h | |||
@@ -57,18 +57,12 @@ struct task_cputime_atomic { | |||
57 | /** | 57 | /** |
58 | * struct thread_group_cputimer - thread group interval timer counts | 58 | * struct thread_group_cputimer - thread group interval timer counts |
59 | * @cputime_atomic: atomic thread group interval timers. | 59 | * @cputime_atomic: atomic thread group interval timers. |
60 | * @running: true when there are timers running and | ||
61 | * @cputime_atomic receives updates. | ||
62 | * @checking_timer: true when a thread in the group is in the | ||
63 | * process of checking for thread group timers. | ||
64 | * | 60 | * |
65 | * This structure contains the version of task_cputime, above, that is | 61 | * This structure contains the version of task_cputime, above, that is |
66 | * used for thread group CPU timer calculations. | 62 | * used for thread group CPU timer calculations. |
67 | */ | 63 | */ |
68 | struct thread_group_cputimer { | 64 | struct thread_group_cputimer { |
69 | struct task_cputime_atomic cputime_atomic; | 65 | struct task_cputime_atomic cputime_atomic; |
70 | bool running; | ||
71 | bool checking_timer; | ||
72 | }; | 66 | }; |
73 | 67 | ||
74 | struct multiprocess_signals { | 68 | struct multiprocess_signals { |
diff --git a/init/init_task.c b/init/init_task.c index 7ab773b9b3cd..d49692a0ec51 100644 --- a/init/init_task.c +++ b/init/init_task.c | |||
@@ -30,8 +30,6 @@ static struct signal_struct init_signals = { | |||
30 | .posix_timers = LIST_HEAD_INIT(init_signals.posix_timers), | 30 | .posix_timers = LIST_HEAD_INIT(init_signals.posix_timers), |
31 | .cputimer = { | 31 | .cputimer = { |
32 | .cputime_atomic = INIT_CPUTIME_ATOMIC, | 32 | .cputime_atomic = INIT_CPUTIME_ATOMIC, |
33 | .running = false, | ||
34 | .checking_timer = false, | ||
35 | }, | 33 | }, |
36 | #endif | 34 | #endif |
37 | INIT_CPU_TIMERS(init_signals) | 35 | INIT_CPU_TIMERS(init_signals) |
diff --git a/kernel/fork.c b/kernel/fork.c index 52bfe7c20ff6..f1228d9f0b11 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1517,7 +1517,6 @@ void __cleanup_sighand(struct sighand_struct *sighand) | |||
1517 | } | 1517 | } |
1518 | } | 1518 | } |
1519 | 1519 | ||
1520 | #ifdef CONFIG_POSIX_TIMERS | ||
1521 | /* | 1520 | /* |
1522 | * Initialize POSIX timer handling for a thread group. | 1521 | * Initialize POSIX timer handling for a thread group. |
1523 | */ | 1522 | */ |
@@ -1528,12 +1527,7 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig) | |||
1528 | 1527 | ||
1529 | cpu_limit = READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur); | 1528 | cpu_limit = READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur); |
1530 | posix_cputimers_group_init(pct, cpu_limit); | 1529 | posix_cputimers_group_init(pct, cpu_limit); |
1531 | if (cpu_limit != RLIM_INFINITY) | ||
1532 | sig->cputimer.running = true; | ||
1533 | } | 1530 | } |
1534 | #else | ||
1535 | static inline void posix_cpu_timers_init_group(struct signal_struct *sig) { } | ||
1536 | #endif | ||
1537 | 1531 | ||
1538 | static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | 1532 | static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) |
1539 | { | 1533 | { |
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index ef39a7a4a95c..52f4c99c1d60 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c | |||
@@ -23,8 +23,10 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer); | |||
23 | void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit) | 23 | 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->bases[CPUCLOCK_PROF].nextevt = cpu_limit * NSEC_PER_SEC; | 27 | pct->bases[CPUCLOCK_PROF].nextevt = cpu_limit * NSEC_PER_SEC; |
28 | pct->timers_active = true; | ||
29 | } | ||
28 | } | 30 | } |
29 | 31 | ||
30 | /* | 32 | /* |
@@ -248,8 +250,9 @@ static void update_gt_cputime(struct task_cputime_atomic *cputime_atomic, | |||
248 | void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples) | 250 | void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples) |
249 | { | 251 | { |
250 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; | 252 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; |
253 | struct posix_cputimers *pct = &tsk->signal->posix_cputimers; | ||
251 | 254 | ||
252 | WARN_ON_ONCE(!cputimer->running); | 255 | WARN_ON_ONCE(!pct->timers_active); |
253 | 256 | ||
254 | proc_sample_cputime_atomic(&cputimer->cputime_atomic, samples); | 257 | proc_sample_cputime_atomic(&cputimer->cputime_atomic, samples); |
255 | } | 258 | } |
@@ -269,9 +272,10 @@ void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples) | |||
269 | static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples) | 272 | static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples) |
270 | { | 273 | { |
271 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; | 274 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; |
275 | struct posix_cputimers *pct = &tsk->signal->posix_cputimers; | ||
272 | 276 | ||
273 | /* Check if cputimer isn't running. This is accessed without locking. */ | 277 | /* Check if cputimer isn't running. This is accessed without locking. */ |
274 | if (!READ_ONCE(cputimer->running)) { | 278 | if (!READ_ONCE(pct->timers_active)) { |
275 | struct task_cputime sum; | 279 | struct task_cputime sum; |
276 | 280 | ||
277 | /* | 281 | /* |
@@ -283,13 +287,13 @@ static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples) | |||
283 | update_gt_cputime(&cputimer->cputime_atomic, &sum); | 287 | update_gt_cputime(&cputimer->cputime_atomic, &sum); |
284 | 288 | ||
285 | /* | 289 | /* |
286 | * We're setting cputimer->running without a lock. Ensure | 290 | * We're setting timers_active without a lock. Ensure this |
287 | * this only gets written to in one operation. We set | 291 | * only gets written to in one operation. We set it after |
288 | * running after update_gt_cputime() as a small optimization, | 292 | * update_gt_cputime() as a small optimization, but |
289 | * but barriers are not required because update_gt_cputime() | 293 | * barriers are not required because update_gt_cputime() |
290 | * can handle concurrent updates. | 294 | * can handle concurrent updates. |
291 | */ | 295 | */ |
292 | WRITE_ONCE(cputimer->running, true); | 296 | WRITE_ONCE(pct->timers_active, true); |
293 | } | 297 | } |
294 | proc_sample_cputime_atomic(&cputimer->cputime_atomic, samples); | 298 | proc_sample_cputime_atomic(&cputimer->cputime_atomic, samples); |
295 | } | 299 | } |
@@ -313,9 +317,10 @@ static u64 cpu_clock_sample_group(const clockid_t clkid, struct task_struct *p, | |||
313 | bool start) | 317 | bool start) |
314 | { | 318 | { |
315 | struct thread_group_cputimer *cputimer = &p->signal->cputimer; | 319 | struct thread_group_cputimer *cputimer = &p->signal->cputimer; |
320 | struct posix_cputimers *pct = &p->signal->posix_cputimers; | ||
316 | u64 samples[CPUCLOCK_MAX]; | 321 | u64 samples[CPUCLOCK_MAX]; |
317 | 322 | ||
318 | if (!READ_ONCE(cputimer->running)) { | 323 | if (!READ_ONCE(pct->timers_active)) { |
319 | if (start) | 324 | if (start) |
320 | thread_group_start_cputime(p, samples); | 325 | thread_group_start_cputime(p, samples); |
321 | else | 326 | else |
@@ -834,10 +839,10 @@ static void check_thread_timers(struct task_struct *tsk, | |||
834 | 839 | ||
835 | static inline void stop_process_timers(struct signal_struct *sig) | 840 | static inline void stop_process_timers(struct signal_struct *sig) |
836 | { | 841 | { |
837 | struct thread_group_cputimer *cputimer = &sig->cputimer; | 842 | struct posix_cputimers *pct = &sig->posix_cputimers; |
838 | 843 | ||
839 | /* Turn off cputimer->running. This is done without locking. */ | 844 | /* Turn off the active flag. This is done without locking. */ |
840 | WRITE_ONCE(cputimer->running, false); | 845 | WRITE_ONCE(pct->timers_active, false); |
841 | tick_dep_clear_signal(sig, TICK_DEP_BIT_POSIX_TIMER); | 846 | tick_dep_clear_signal(sig, TICK_DEP_BIT_POSIX_TIMER); |
842 | } | 847 | } |
843 | 848 | ||
@@ -877,17 +882,17 @@ static void check_process_timers(struct task_struct *tsk, | |||
877 | unsigned long soft; | 882 | unsigned long soft; |
878 | 883 | ||
879 | /* | 884 | /* |
880 | * If cputimer is not running, then there are no active | 885 | * If there are no active process wide timers (POSIX 1.b, itimers, |
881 | * process wide timers (POSIX 1.b, itimers, RLIMIT_CPU). | 886 | * RLIMIT_CPU) nothing to check. |
882 | */ | 887 | */ |
883 | if (!READ_ONCE(sig->cputimer.running)) | 888 | if (!READ_ONCE(pct->timers_active)) |
884 | return; | 889 | return; |
885 | 890 | ||
886 | /* | 891 | /* |
887 | * Signify that a thread is checking for process timers. | 892 | * Signify that a thread is checking for process timers. |
888 | * Write access to this field is protected by the sighand lock. | 893 | * Write access to this field is protected by the sighand lock. |
889 | */ | 894 | */ |
890 | sig->cputimer.checking_timer = true; | 895 | pct->timers_active = true; |
891 | 896 | ||
892 | /* | 897 | /* |
893 | * Collect the current process totals. Group accounting is active | 898 | * Collect the current process totals. Group accounting is active |
@@ -933,7 +938,7 @@ static void check_process_timers(struct task_struct *tsk, | |||
933 | if (expiry_cache_is_inactive(pct)) | 938 | if (expiry_cache_is_inactive(pct)) |
934 | stop_process_timers(sig); | 939 | stop_process_timers(sig); |
935 | 940 | ||
936 | sig->cputimer.checking_timer = false; | 941 | pct->expiry_active = false; |
937 | } | 942 | } |
938 | 943 | ||
939 | /* | 944 | /* |
@@ -1027,39 +1032,41 @@ task_cputimers_expired(const u64 *sample, struct posix_cputimers *pct) | |||
1027 | */ | 1032 | */ |
1028 | static inline bool fastpath_timer_check(struct task_struct *tsk) | 1033 | static inline bool fastpath_timer_check(struct task_struct *tsk) |
1029 | { | 1034 | { |
1035 | struct posix_cputimers *pct = &tsk->posix_cputimers; | ||
1030 | struct signal_struct *sig; | 1036 | struct signal_struct *sig; |
1031 | 1037 | ||
1032 | if (!expiry_cache_is_inactive(&tsk->posix_cputimers)) { | 1038 | if (!expiry_cache_is_inactive(pct)) { |
1033 | u64 samples[CPUCLOCK_MAX]; | 1039 | u64 samples[CPUCLOCK_MAX]; |
1034 | 1040 | ||
1035 | task_sample_cputime(tsk, samples); | 1041 | task_sample_cputime(tsk, samples); |
1036 | if (task_cputimers_expired(samples, &tsk->posix_cputimers)) | 1042 | if (task_cputimers_expired(samples, pct)) |
1037 | return true; | 1043 | return true; |
1038 | } | 1044 | } |
1039 | 1045 | ||
1040 | sig = tsk->signal; | 1046 | sig = tsk->signal; |
1047 | pct = &sig->posix_cputimers; | ||
1041 | /* | 1048 | /* |
1042 | * Check if thread group timers expired when the cputimer is | 1049 | * Check if thread group timers expired when timers are active and |
1043 | * running and no other thread in the group is already checking | 1050 | * no other thread in the group is already handling expiry for |
1044 | * for thread group cputimers. These fields are read without the | 1051 | * thread group cputimers. These fields are read without the |
1045 | * sighand lock. However, this is fine because this is meant to | 1052 | * sighand lock. However, this is fine because this is meant to be |
1046 | * be a fastpath heuristic to determine whether we should try to | 1053 | * a fastpath heuristic to determine whether we should try to |
1047 | * acquire the sighand lock to check/handle timers. | 1054 | * acquire the sighand lock to handle timer expiry. |
1048 | * | 1055 | * |
1049 | * In the worst case scenario, if 'running' or 'checking_timer' gets | 1056 | * In the worst case scenario, if concurrently timers_active is set |
1050 | * set but the current thread doesn't see the change yet, we'll wait | 1057 | * or expiry_active is cleared, but the current thread doesn't see |
1051 | * until the next thread in the group gets a scheduler interrupt to | 1058 | * the change yet, the timer checks are delayed until the next |
1052 | * handle the timer. This isn't an issue in practice because these | 1059 | * thread in the group gets a scheduler interrupt to handle the |
1053 | * types of delays with signals actually getting sent are expected. | 1060 | * timer. This isn't an issue in practice because these types of |
1061 | * delays with signals actually getting sent are expected. | ||
1054 | */ | 1062 | */ |
1055 | if (READ_ONCE(sig->cputimer.running) && | 1063 | if (READ_ONCE(pct->timers_active) && !READ_ONCE(pct->expiry_active)) { |
1056 | !READ_ONCE(sig->cputimer.checking_timer)) { | ||
1057 | u64 samples[CPUCLOCK_MAX]; | 1064 | u64 samples[CPUCLOCK_MAX]; |
1058 | 1065 | ||
1059 | proc_sample_cputime_atomic(&sig->cputimer.cputime_atomic, | 1066 | proc_sample_cputime_atomic(&sig->cputimer.cputime_atomic, |
1060 | samples); | 1067 | samples); |
1061 | 1068 | ||
1062 | if (task_cputimers_expired(samples, &sig->posix_cputimers)) | 1069 | if (task_cputimers_expired(samples, pct)) |
1063 | return true; | 1070 | return true; |
1064 | } | 1071 | } |
1065 | 1072 | ||