diff options
Diffstat (limited to 'kernel/time/posix-cpu-timers.c')
-rw-r--r-- | kernel/time/posix-cpu-timers.c | 87 |
1 files changed, 54 insertions, 33 deletions
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 0075da74abf0..892e3dae0aac 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c | |||
@@ -196,39 +196,62 @@ static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p, | |||
196 | return 0; | 196 | return 0; |
197 | } | 197 | } |
198 | 198 | ||
199 | static void update_gt_cputime(struct task_cputime *a, struct task_cputime *b) | 199 | /* |
200 | * Set cputime to sum_cputime if sum_cputime > cputime. Use cmpxchg | ||
201 | * to avoid race conditions with concurrent updates to cputime. | ||
202 | */ | ||
203 | static inline void __update_gt_cputime(atomic64_t *cputime, u64 sum_cputime) | ||
200 | { | 204 | { |
201 | if (b->utime > a->utime) | 205 | u64 curr_cputime; |
202 | a->utime = b->utime; | 206 | retry: |
207 | curr_cputime = atomic64_read(cputime); | ||
208 | if (sum_cputime > curr_cputime) { | ||
209 | if (atomic64_cmpxchg(cputime, curr_cputime, sum_cputime) != curr_cputime) | ||
210 | goto retry; | ||
211 | } | ||
212 | } | ||
203 | 213 | ||
204 | if (b->stime > a->stime) | 214 | static void update_gt_cputime(struct task_cputime_atomic *cputime_atomic, struct task_cputime *sum) |
205 | a->stime = b->stime; | 215 | { |
216 | __update_gt_cputime(&cputime_atomic->utime, sum->utime); | ||
217 | __update_gt_cputime(&cputime_atomic->stime, sum->stime); | ||
218 | __update_gt_cputime(&cputime_atomic->sum_exec_runtime, sum->sum_exec_runtime); | ||
219 | } | ||
206 | 220 | ||
207 | if (b->sum_exec_runtime > a->sum_exec_runtime) | 221 | /* Sample task_cputime_atomic values in "atomic_timers", store results in "times". */ |
208 | a->sum_exec_runtime = b->sum_exec_runtime; | 222 | static inline void sample_cputime_atomic(struct task_cputime *times, |
223 | struct task_cputime_atomic *atomic_times) | ||
224 | { | ||
225 | times->utime = atomic64_read(&atomic_times->utime); | ||
226 | times->stime = atomic64_read(&atomic_times->stime); | ||
227 | times->sum_exec_runtime = atomic64_read(&atomic_times->sum_exec_runtime); | ||
209 | } | 228 | } |
210 | 229 | ||
211 | void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times) | 230 | void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times) |
212 | { | 231 | { |
213 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; | 232 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; |
214 | struct task_cputime sum; | 233 | struct task_cputime sum; |
215 | unsigned long flags; | ||
216 | 234 | ||
217 | if (!cputimer->running) { | 235 | /* Check if cputimer isn't running. This is accessed without locking. */ |
236 | if (!READ_ONCE(cputimer->running)) { | ||
218 | /* | 237 | /* |
219 | * The POSIX timer interface allows for absolute time expiry | 238 | * The POSIX timer interface allows for absolute time expiry |
220 | * values through the TIMER_ABSTIME flag, therefore we have | 239 | * values through the TIMER_ABSTIME flag, therefore we have |
221 | * to synchronize the timer to the clock every time we start | 240 | * to synchronize the timer to the clock every time we start it. |
222 | * it. | ||
223 | */ | 241 | */ |
224 | thread_group_cputime(tsk, &sum); | 242 | thread_group_cputime(tsk, &sum); |
225 | raw_spin_lock_irqsave(&cputimer->lock, flags); | 243 | update_gt_cputime(&cputimer->cputime_atomic, &sum); |
226 | cputimer->running = 1; | 244 | |
227 | update_gt_cputime(&cputimer->cputime, &sum); | 245 | /* |
228 | } else | 246 | * We're setting cputimer->running without a lock. Ensure |
229 | raw_spin_lock_irqsave(&cputimer->lock, flags); | 247 | * this only gets written to in one operation. We set |
230 | *times = cputimer->cputime; | 248 | * running after update_gt_cputime() as a small optimization, |
231 | raw_spin_unlock_irqrestore(&cputimer->lock, flags); | 249 | * but barriers are not required because update_gt_cputime() |
250 | * can handle concurrent updates. | ||
251 | */ | ||
252 | WRITE_ONCE(cputimer->running, 1); | ||
253 | } | ||
254 | sample_cputime_atomic(times, &cputimer->cputime_atomic); | ||
232 | } | 255 | } |
233 | 256 | ||
234 | /* | 257 | /* |
@@ -582,7 +605,8 @@ bool posix_cpu_timers_can_stop_tick(struct task_struct *tsk) | |||
582 | if (!task_cputime_zero(&tsk->cputime_expires)) | 605 | if (!task_cputime_zero(&tsk->cputime_expires)) |
583 | return false; | 606 | return false; |
584 | 607 | ||
585 | if (tsk->signal->cputimer.running) | 608 | /* Check if cputimer is running. This is accessed without locking. */ |
609 | if (READ_ONCE(tsk->signal->cputimer.running)) | ||
586 | return false; | 610 | return false; |
587 | 611 | ||
588 | return true; | 612 | return true; |
@@ -852,10 +876,10 @@ static void check_thread_timers(struct task_struct *tsk, | |||
852 | /* | 876 | /* |
853 | * Check for the special case thread timers. | 877 | * Check for the special case thread timers. |
854 | */ | 878 | */ |
855 | soft = ACCESS_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_cur); | 879 | soft = READ_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_cur); |
856 | if (soft != RLIM_INFINITY) { | 880 | if (soft != RLIM_INFINITY) { |
857 | unsigned long hard = | 881 | unsigned long hard = |
858 | ACCESS_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_max); | 882 | READ_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_max); |
859 | 883 | ||
860 | if (hard != RLIM_INFINITY && | 884 | if (hard != RLIM_INFINITY && |
861 | tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) { | 885 | tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) { |
@@ -882,14 +906,12 @@ static void check_thread_timers(struct task_struct *tsk, | |||
882 | } | 906 | } |
883 | } | 907 | } |
884 | 908 | ||
885 | static void stop_process_timers(struct signal_struct *sig) | 909 | static inline void stop_process_timers(struct signal_struct *sig) |
886 | { | 910 | { |
887 | struct thread_group_cputimer *cputimer = &sig->cputimer; | 911 | struct thread_group_cputimer *cputimer = &sig->cputimer; |
888 | unsigned long flags; | ||
889 | 912 | ||
890 | raw_spin_lock_irqsave(&cputimer->lock, flags); | 913 | /* Turn off cputimer->running. This is done without locking. */ |
891 | cputimer->running = 0; | 914 | WRITE_ONCE(cputimer->running, 0); |
892 | raw_spin_unlock_irqrestore(&cputimer->lock, flags); | ||
893 | } | 915 | } |
894 | 916 | ||
895 | static u32 onecputick; | 917 | static u32 onecputick; |
@@ -958,11 +980,11 @@ static void check_process_timers(struct task_struct *tsk, | |||
958 | SIGPROF); | 980 | SIGPROF); |
959 | check_cpu_itimer(tsk, &sig->it[CPUCLOCK_VIRT], &virt_expires, utime, | 981 | check_cpu_itimer(tsk, &sig->it[CPUCLOCK_VIRT], &virt_expires, utime, |
960 | SIGVTALRM); | 982 | SIGVTALRM); |
961 | soft = ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur); | 983 | soft = READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur); |
962 | if (soft != RLIM_INFINITY) { | 984 | if (soft != RLIM_INFINITY) { |
963 | unsigned long psecs = cputime_to_secs(ptime); | 985 | unsigned long psecs = cputime_to_secs(ptime); |
964 | unsigned long hard = | 986 | unsigned long hard = |
965 | ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_max); | 987 | READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_max); |
966 | cputime_t x; | 988 | cputime_t x; |
967 | if (psecs >= hard) { | 989 | if (psecs >= hard) { |
968 | /* | 990 | /* |
@@ -1111,12 +1133,11 @@ static inline int fastpath_timer_check(struct task_struct *tsk) | |||
1111 | } | 1133 | } |
1112 | 1134 | ||
1113 | sig = tsk->signal; | 1135 | sig = tsk->signal; |
1114 | if (sig->cputimer.running) { | 1136 | /* Check if cputimer is running. This is accessed without locking. */ |
1137 | if (READ_ONCE(sig->cputimer.running)) { | ||
1115 | struct task_cputime group_sample; | 1138 | struct task_cputime group_sample; |
1116 | 1139 | ||
1117 | raw_spin_lock(&sig->cputimer.lock); | 1140 | sample_cputime_atomic(&group_sample, &sig->cputimer.cputime_atomic); |
1118 | group_sample = sig->cputimer.cputime; | ||
1119 | raw_spin_unlock(&sig->cputimer.lock); | ||
1120 | 1141 | ||
1121 | if (task_cputime_expired(&group_sample, &sig->cputime_expires)) | 1142 | if (task_cputime_expired(&group_sample, &sig->cputime_expires)) |
1122 | return 1; | 1143 | return 1; |
@@ -1157,7 +1178,7 @@ void run_posix_cpu_timers(struct task_struct *tsk) | |||
1157 | * If there are any active process wide timers (POSIX 1.b, itimers, | 1178 | * If there are any active process wide timers (POSIX 1.b, itimers, |
1158 | * RLIMIT_CPU) cputimer must be running. | 1179 | * RLIMIT_CPU) cputimer must be running. |
1159 | */ | 1180 | */ |
1160 | if (tsk->signal->cputimer.running) | 1181 | if (READ_ONCE(tsk->signal->cputimer.running)) |
1161 | check_process_timers(tsk, &firing); | 1182 | check_process_timers(tsk, &firing); |
1162 | 1183 | ||
1163 | /* | 1184 | /* |