diff options
author | George Anzinger <george@mvista.com> | 2005-07-27 14:43:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-27 19:25:51 -0400 |
commit | d912d1ff218195c248c770eb677726695e07aa40 (patch) | |
tree | 6718b67656e3cf0ec0c03b585f43f8815809cdcd /kernel | |
parent | b7343f01e326374e69666ca6001bdb6a7c67e9f7 (diff) |
[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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/itimer.c | 37 |
1 files changed, 16 insertions, 21 deletions
diff --git a/kernel/itimer.c b/kernel/itimer.c index a72cb0e5aa4b..7c1b25e25e47 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c | |||
@@ -112,28 +112,11 @@ asmlinkage long sys_getitimer(int which, struct itimerval __user *value) | |||
112 | return error; | 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 | void it_real_fn(unsigned long __data) | 116 | void it_real_fn(unsigned long __data) |
135 | { | 117 | { |
136 | struct task_struct * p = (struct task_struct *) __data; | 118 | struct task_struct * p = (struct task_struct *) __data; |
119 | unsigned long inc = p->signal->it_real_incr; | ||
137 | 120 | ||
138 | send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p); | 121 | send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p); |
139 | 122 | ||
@@ -141,14 +124,23 @@ void it_real_fn(unsigned long __data) | |||
141 | * Now restart the timer if necessary. We don't need any locking | 124 | * Now restart the timer if necessary. We don't need any locking |
142 | * here because do_setitimer makes sure we have finished running | 125 | * here because do_setitimer makes sure we have finished running |
143 | * before it touches anything. | 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 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) | 140 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) |
149 | { | 141 | { |
150 | struct task_struct *tsk = current; | 142 | struct task_struct *tsk = current; |
151 | unsigned long val, interval; | 143 | unsigned long val, interval, expires; |
152 | cputime_t cval, cinterval, nval, ninterval; | 144 | cputime_t cval, cinterval, nval, ninterval; |
153 | 145 | ||
154 | switch (which) { | 146 | switch (which) { |
@@ -164,7 +156,10 @@ again: | |||
164 | } | 156 | } |
165 | tsk->signal->it_real_incr = | 157 | tsk->signal->it_real_incr = |
166 | timeval_to_jiffies(&value->it_interval); | 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 | spin_unlock_irq(&tsk->sighand->siglock); | 163 | spin_unlock_irq(&tsk->sighand->siglock); |
169 | if (ovalue) { | 164 | if (ovalue) { |
170 | jiffies_to_timeval(val, &ovalue->it_value); | 165 | jiffies_to_timeval(val, &ovalue->it_value); |