diff options
Diffstat (limited to 'kernel/posix-cpu-timers.c')
| -rw-r--r-- | kernel/posix-cpu-timers.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 479b16b44f79..7c3e1e6dfb5b 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c | |||
| @@ -88,6 +88,19 @@ static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock, | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | /* | 90 | /* |
| 91 | * Divide and limit the result to res >= 1 | ||
| 92 | * | ||
| 93 | * This is necessary to prevent signal delivery starvation, when the result of | ||
| 94 | * the division would be rounded down to 0. | ||
| 95 | */ | ||
| 96 | static inline cputime_t cputime_div_non_zero(cputime_t time, unsigned long div) | ||
| 97 | { | ||
| 98 | cputime_t res = cputime_div(time, div); | ||
| 99 | |||
| 100 | return max_t(cputime_t, res, 1); | ||
| 101 | } | ||
| 102 | |||
| 103 | /* | ||
| 91 | * Update expiry time from increment, and increase overrun count, | 104 | * Update expiry time from increment, and increase overrun count, |
| 92 | * given the current clock sample. | 105 | * given the current clock sample. |
| 93 | */ | 106 | */ |
| @@ -483,8 +496,8 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 483 | BUG(); | 496 | BUG(); |
| 484 | break; | 497 | break; |
| 485 | case CPUCLOCK_PROF: | 498 | case CPUCLOCK_PROF: |
| 486 | left = cputime_div(cputime_sub(expires.cpu, val.cpu), | 499 | left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu), |
| 487 | nthreads); | 500 | nthreads); |
| 488 | do { | 501 | do { |
| 489 | if (likely(!(t->flags & PF_EXITING))) { | 502 | if (likely(!(t->flags & PF_EXITING))) { |
| 490 | ticks = cputime_add(prof_ticks(t), left); | 503 | ticks = cputime_add(prof_ticks(t), left); |
| @@ -498,8 +511,8 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 498 | } while (t != p); | 511 | } while (t != p); |
| 499 | break; | 512 | break; |
| 500 | case CPUCLOCK_VIRT: | 513 | case CPUCLOCK_VIRT: |
| 501 | left = cputime_div(cputime_sub(expires.cpu, val.cpu), | 514 | left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu), |
| 502 | nthreads); | 515 | nthreads); |
| 503 | do { | 516 | do { |
| 504 | if (likely(!(t->flags & PF_EXITING))) { | 517 | if (likely(!(t->flags & PF_EXITING))) { |
| 505 | ticks = cputime_add(virt_ticks(t), left); | 518 | ticks = cputime_add(virt_ticks(t), left); |
| @@ -515,6 +528,7 @@ static void process_timer_rebalance(struct task_struct *p, | |||
| 515 | case CPUCLOCK_SCHED: | 528 | case CPUCLOCK_SCHED: |
| 516 | nsleft = expires.sched - val.sched; | 529 | nsleft = expires.sched - val.sched; |
| 517 | do_div(nsleft, nthreads); | 530 | do_div(nsleft, nthreads); |
| 531 | nsleft = max_t(unsigned long long, nsleft, 1); | ||
| 518 | do { | 532 | do { |
| 519 | if (likely(!(t->flags & PF_EXITING))) { | 533 | if (likely(!(t->flags & PF_EXITING))) { |
| 520 | ns = t->sched_time + nsleft; | 534 | ns = t->sched_time + nsleft; |
| @@ -1159,12 +1173,13 @@ static void check_process_timers(struct task_struct *tsk, | |||
| 1159 | 1173 | ||
| 1160 | prof_left = cputime_sub(prof_expires, utime); | 1174 | prof_left = cputime_sub(prof_expires, utime); |
| 1161 | prof_left = cputime_sub(prof_left, stime); | 1175 | prof_left = cputime_sub(prof_left, stime); |
| 1162 | prof_left = cputime_div(prof_left, nthreads); | 1176 | prof_left = cputime_div_non_zero(prof_left, nthreads); |
| 1163 | virt_left = cputime_sub(virt_expires, utime); | 1177 | virt_left = cputime_sub(virt_expires, utime); |
| 1164 | virt_left = cputime_div(virt_left, nthreads); | 1178 | virt_left = cputime_div_non_zero(virt_left, nthreads); |
| 1165 | if (sched_expires) { | 1179 | if (sched_expires) { |
| 1166 | sched_left = sched_expires - sched_time; | 1180 | sched_left = sched_expires - sched_time; |
| 1167 | do_div(sched_left, nthreads); | 1181 | do_div(sched_left, nthreads); |
| 1182 | sched_left = max_t(unsigned long long, sched_left, 1); | ||
| 1168 | } else { | 1183 | } else { |
| 1169 | sched_left = 0; | 1184 | sched_left = 0; |
| 1170 | } | 1185 | } |
