| @@ -23,8 +23,10 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer); · 22 unmodified lines |
| 23 | 23 | void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit) |
| 24 | 24 | { |
| 25 | 25 | posix_cputimers_init(pct); |
| 26 | | − if (cpu_limit != RLIM_INFINITY) |
| 26 | + if (cpu_limit != RLIM_INFINITY) { |
| 27 | 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, · 217 unmodified lines |
| 248 | 250 | void thread_group_sample_cputime(struct task_struct *tsk, u64 *samples) |
| 249 | 251 | { |
| 250 | 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 | 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) · 13 unmodified lines |
| 269 | 272 | static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples) |
| 270 | 273 | { |
| 271 | 274 | struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; |
| 275 | + struct posix_cputimers *pct = &tsk->signal->posix_cputimers; |
| 272 | 276 | |
| 273 | 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 | 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) · 5 unmodified lines |
| 283 | 287 | update_gt_cputime(&cputimer->cputime_atomic, &sum); |
| 284 | 288 | |
| 285 | 289 | /* |
| 286 | | − * We're setting cputimer->running without a lock. Ensure |
| 287 | | − * this only gets written to in one operation. We set |
| 288 | | − * running after update_gt_cputime() as a small optimization, |
| 289 | | − * but barriers are not required because update_gt_cputime() |
| 290 | + * We're setting timers_active without a lock. Ensure this |
| 291 | + * only gets written to in one operation. We set it after |
| 292 | + * update_gt_cputime() as a small optimization, but |
| 293 | + * barriers are not required because update_gt_cputime() |
| 290 | 294 | * can handle concurrent updates. |
| 291 | 295 | */ |
| 292 | | − WRITE_ONCE(cputimer->running, true); |
| 296 | + WRITE_ONCE(pct->timers_active, true); |
| 293 | 297 | } |
| 294 | 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, · 17 unmodified lines |
| 313 | 317 | bool start) |
| 314 | 318 | { |
| 315 | 319 | struct thread_group_cputimer *cputimer = &p->signal->cputimer; |
| 320 | + struct posix_cputimers *pct = &p->signal->posix_cputimers; |
| 316 | 321 | u64 samples[CPUCLOCK_MAX]; |
| 317 | 322 | |
| 318 | | − if (!READ_ONCE(cputimer->running)) { |
| 323 | + if (!READ_ONCE(pct->timers_active)) { |
| 319 | 324 | if (start) |
| 320 | 325 | thread_group_start_cputime(p, samples); |
| 321 | 326 | else |
| @@ -834,10 +839,10 @@ static void check_thread_timers(struct task_struct *tsk, · 512 unmodified lines |
| 834 | 839 | |
| 835 | 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. */ |
| 840 | | − WRITE_ONCE(cputimer->running, false); |
| 844 | + /* Turn off the active flag. This is done without locking. */ |
| 845 | + WRITE_ONCE(pct->timers_active, false); |
| 841 | 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, · 33 unmodified lines |
| 877 | 882 | unsigned long soft; |
| 878 | 883 | |
| 879 | 884 | /* |
| 880 | | − * If cputimer is not running, then there are no active |
| 881 | | − * process wide timers (POSIX 1.b, itimers, RLIMIT_CPU). |
| 885 | + * If there are no active process wide timers (POSIX 1.b, itimers, |
| 886 | + * RLIMIT_CPU) nothing to check. |
| 882 | 887 | */ |
| 883 | | − if (!READ_ONCE(sig->cputimer.running)) |
| 888 | + if (!READ_ONCE(pct->timers_active)) |
| 884 | 889 | return; |
| 885 | 890 | |
| 886 | 891 | /* |
| 887 | 892 | * Signify that a thread is checking for process timers. |
| 888 | 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 | 898 | * Collect the current process totals. Group accounting is active |
| @@ -933,7 +938,7 @@ static void check_process_timers(struct task_struct *tsk, · 39 unmodified lines |
| 933 | 938 | if (expiry_cache_is_inactive(pct)) |
| 934 | 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) · 87 unmodified lines |
| 1027 | 1032 | */ |
| 1028 | 1033 | static inline bool fastpath_timer_check(struct task_struct *tsk) |
| 1029 | 1034 | { |
| 1035 | + struct posix_cputimers *pct = &tsk->posix_cputimers; |
| 1030 | 1036 | struct signal_struct *sig; |
| 1031 | 1037 | |
| 1032 | | − if (!expiry_cache_is_inactive(&tsk->posix_cputimers)) { |
| 1038 | + if (!expiry_cache_is_inactive(pct)) { |
| 1033 | 1039 | u64 samples[CPUCLOCK_MAX]; |
| 1034 | 1040 | |
| 1035 | 1041 | task_sample_cputime(tsk, samples); |
| 1036 | | − if (task_cputimers_expired(samples, &tsk->posix_cputimers)) |
| 1042 | + if (task_cputimers_expired(samples, pct)) |
| 1037 | 1043 | return true; |
| 1038 | 1044 | } |
| 1039 | 1045 | |
| 1040 | 1046 | sig = tsk->signal; |
| 1047 | + pct = &sig->posix_cputimers; |
| 1041 | 1048 | /* |
| 1042 | | − * Check if thread group timers expired when the cputimer is |
| 1043 | | − * running and no other thread in the group is already checking |
| 1044 | | − * for thread group cputimers. These fields are read without the |
| 1045 | | − * sighand lock. However, this is fine because this is meant to |
| 1046 | | − * be a fastpath heuristic to determine whether we should try to |
| 1047 | | − * acquire the sighand lock to check/handle timers. |
| 1049 | + * Check if thread group timers expired when timers are active and |
| 1050 | + * no other thread in the group is already handling expiry for |
| 1051 | + * thread group cputimers. These fields are read without the |
| 1052 | + * sighand lock. However, this is fine because this is meant to be |
| 1053 | + * a fastpath heuristic to determine whether we should try to |
| 1054 | + * acquire the sighand lock to handle timer expiry. |
| 1048 | 1055 | * |
| 1049 | | − * In the worst case scenario, if 'running' or 'checking_timer' gets |
| 1050 | | − * set but the current thread doesn't see the change yet, we'll wait |
| 1051 | | − * until the next thread in the group gets a scheduler interrupt to |
| 1052 | | − * handle the timer. This isn't an issue in practice because these |
| 1053 | | − * types of delays with signals actually getting sent are expected. |
| 1056 | + * In the worst case scenario, if concurrently timers_active is set |
| 1057 | + * or expiry_active is cleared, but the current thread doesn't see |
| 1058 | + * the change yet, the timer checks are delayed until the next |
| 1059 | + * thread in the group gets a scheduler interrupt to handle the |
| 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) && |
| 1056 | | − !READ_ONCE(sig->cputimer.checking_timer)) { |
| 1063 | + if (READ_ONCE(pct->timers_active) && !READ_ONCE(pct->expiry_active)) { |
| 1057 | 1064 | u64 samples[CPUCLOCK_MAX]; |
| 1058 | 1065 | |
| 1059 | 1066 | proc_sample_cputime_atomic(&sig->cputimer.cputime_atomic, |
| 1060 | 1067 | samples); |
| 1061 | 1068 | |
| 1062 | | − if (task_cputimers_expired(samples, &sig->posix_cputimers)) |
| 1069 | + if (task_cputimers_expired(samples, pct)) |
| 1063 | 1070 | return true; |
| 1064 | 1071 | } |
| 1065 | 1072 | |