aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/itimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/itimer.c')
-rw-r--r--kernel/itimer.c37
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 */
119static 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
134void it_real_fn(unsigned long __data) 116void 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
148int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) 140int 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);