diff options
| -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,  }  /* + * Divide and limit the result to res >= 1 + * + * This is necessary to prevent signal delivery starvation, when the result of + * the division would be rounded down to 0. + */ +static inline cputime_t cputime_div_non_zero(cputime_t time, unsigned long div) +{ +	cputime_t res = cputime_div(time, div); + +	return max_t(cputime_t, res, 1); +} + +/*   * Update expiry time from increment, and increase overrun count,   * given the current clock sample.   */ @@ -483,8 +496,8 @@ static void process_timer_rebalance(struct task_struct *p,  		BUG();  		break;  	case CPUCLOCK_PROF: -		left = cputime_div(cputime_sub(expires.cpu, val.cpu), -				   nthreads); +		left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu), +				       nthreads);  		do {  			if (likely(!(t->flags & PF_EXITING))) {  				ticks = cputime_add(prof_ticks(t), left); @@ -498,8 +511,8 @@ static void process_timer_rebalance(struct task_struct *p,  		} while (t != p);  		break;  	case CPUCLOCK_VIRT: -		left = cputime_div(cputime_sub(expires.cpu, val.cpu), -				   nthreads); +		left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu), +				       nthreads);  		do {  			if (likely(!(t->flags & PF_EXITING))) {  				ticks = cputime_add(virt_ticks(t), left); @@ -515,6 +528,7 @@ static void process_timer_rebalance(struct task_struct *p,  	case CPUCLOCK_SCHED:  		nsleft = expires.sched - val.sched;  		do_div(nsleft, nthreads); +		nsleft = max_t(unsigned long long, nsleft, 1);  		do {  			if (likely(!(t->flags & PF_EXITING))) {  				ns = t->sched_time + nsleft; @@ -1159,12 +1173,13 @@ static void check_process_timers(struct task_struct *tsk,  		prof_left = cputime_sub(prof_expires, utime);  		prof_left = cputime_sub(prof_left, stime); -		prof_left = cputime_div(prof_left, nthreads); +		prof_left = cputime_div_non_zero(prof_left, nthreads);  		virt_left = cputime_sub(virt_expires, utime); -		virt_left = cputime_div(virt_left, nthreads); +		virt_left = cputime_div_non_zero(virt_left, nthreads);  		if (sched_expires) {  			sched_left = sched_expires - sched_time;  			do_div(sched_left, nthreads); +			sched_left = max_t(unsigned long long, sched_left, 1);  		} else {  			sched_left = 0;  		} | 
