Commit d912d1ff218195c248c770eb677726695e07aa40
Committed by
Linus Torvalds
1 parent
b7343f01e3
Exists in
master
and in
4 other branches
[PATCH] itimer fixes
Fix the recent off-by-one fix in the itimer code: 1. The repeating timer is figured using the requested time (not +1 as we know where we are in the jiffie). 2. The tests for interval too large are left to the time_val to jiffie code. Signed-off-by: George Anzinger <george@mvista.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 16 additions and 21 deletions Side-by-side Diff
kernel/itimer.c
... | ... | @@ -112,28 +112,11 @@ |
112 | 112 | return error; |
113 | 113 | } |
114 | 114 | |
115 | -/* | |
116 | - * Called with P->sighand->siglock held and P->signal->real_timer inactive. | |
117 | - * If interval is nonzero, arm the timer for interval ticks from now. | |
118 | - */ | |
119 | -static inline void it_real_arm(struct task_struct *p, unsigned long interval) | |
120 | -{ | |
121 | - p->signal->it_real_value = interval; /* XXX unnecessary field?? */ | |
122 | - if (interval == 0) | |
123 | - return; | |
124 | - if (interval > (unsigned long) LONG_MAX) | |
125 | - interval = LONG_MAX; | |
126 | - /* the "+ 1" below makes sure that the timer doesn't go off before | |
127 | - * the interval requested. This could happen if | |
128 | - * time requested % (usecs per jiffy) is more than the usecs left | |
129 | - * in the current jiffy */ | |
130 | - p->signal->real_timer.expires = jiffies + interval + 1; | |
131 | - add_timer(&p->signal->real_timer); | |
132 | -} | |
133 | 115 | |
134 | 116 | void it_real_fn(unsigned long __data) |
135 | 117 | { |
136 | 118 | struct task_struct * p = (struct task_struct *) __data; |
119 | + unsigned long inc = p->signal->it_real_incr; | |
137 | 120 | |
138 | 121 | send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p); |
139 | 122 | |
140 | 123 | |
141 | 124 | |
... | ... | @@ -141,14 +124,23 @@ |
141 | 124 | * Now restart the timer if necessary. We don't need any locking |
142 | 125 | * here because do_setitimer makes sure we have finished running |
143 | 126 | * before it touches anything. |
127 | + * Note, we KNOW we are (or should be) at a jiffie edge here so | |
128 | + * we don't need the +1 stuff. Also, we want to use the prior | |
129 | + * expire value so as to not "slip" a jiffie if we are late. | |
130 | + * Deal with requesting a time prior to "now" here rather than | |
131 | + * in add_timer. | |
144 | 132 | */ |
145 | - it_real_arm(p, p->signal->it_real_incr); | |
133 | + if (!inc) | |
134 | + return; | |
135 | + while (time_before_eq(p->signal->real_timer.expires, jiffies)) | |
136 | + p->signal->real_timer.expires += inc; | |
137 | + add_timer(&p->signal->real_timer); | |
146 | 138 | } |
147 | 139 | |
148 | 140 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) |
149 | 141 | { |
150 | 142 | struct task_struct *tsk = current; |
151 | - unsigned long val, interval; | |
143 | + unsigned long val, interval, expires; | |
152 | 144 | cputime_t cval, cinterval, nval, ninterval; |
153 | 145 | |
154 | 146 | switch (which) { |
... | ... | @@ -164,7 +156,10 @@ |
164 | 156 | } |
165 | 157 | tsk->signal->it_real_incr = |
166 | 158 | timeval_to_jiffies(&value->it_interval); |
167 | - it_real_arm(tsk, timeval_to_jiffies(&value->it_value)); | |
159 | + expires = timeval_to_jiffies(&value->it_value); | |
160 | + if (expires) | |
161 | + mod_timer(&tsk->signal->real_timer, | |
162 | + jiffies + 1 + expires); | |
168 | 163 | spin_unlock_irq(&tsk->sighand->siglock); |
169 | 164 | if (ovalue) { |
170 | 165 | jiffies_to_timeval(val, &ovalue->it_value); |