Release 4.15 kernel/time/itimer.c
// SPDX-License-Identifier: GPL-2.0
/*
* linux/kernel/itimer.c
*
* Copyright (C) 1992 Darren Senn
*/
/* These are all the functions necessary to implement itimers */
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/syscalls.h>
#include <linux/time.h>
#include <linux/sched/signal.h>
#include <linux/sched/cputime.h>
#include <linux/posix-timers.h>
#include <linux/hrtimer.h>
#include <trace/events/timer.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
/**
* itimer_get_remtime - get remaining time for the timer
*
* @timer: the timer to read
*
* Returns the delta between the expiry time and now, which can be
* less than zero or 1usec for an pending expired timer
*/
static struct timeval itimer_get_remtime(struct hrtimer *timer)
{
ktime_t rem = __hrtimer_get_remaining(timer, true);
/*
* Racy but safe: if the itimer expires after the above
* hrtimer_get_remtime() call but before this condition
* then we return 0 - which is correct.
*/
if (hrtimer_active(timer)) {
if (rem <= 0)
rem = NSEC_PER_USEC;
} else
rem = 0;
return ktime_to_timeval(rem);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Gleixner | 28 | 52.83% | 2 | 28.57% |
Linus Torvalds (pre-git) | 19 | 35.85% | 4 | 57.14% |
Roland McGrath | 6 | 11.32% | 1 | 14.29% |
Total | 53 | 100.00% | 7 | 100.00% |
static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
struct itimerval *const value)
{
u64 val, interval;
struct cpu_itimer *it = &tsk->signal->it[clock_id];
spin_lock_irq(&tsk->sighand->siglock);
val = it->expires;
interval = it->incr;
if (val) {
struct task_cputime cputime;
u64 t;
thread_group_cputimer(tsk, &cputime);
if (clock_id == CPUCLOCK_PROF)
t = cputime.utime + cputime.stime;
else
/* CPUCLOCK_VIRT */
t = cputime.utime;
if (val < t)
/* about to fire */
val = TICK_NSEC;
else
val -= t;
}
spin_unlock_irq(&tsk->sighand->siglock);
value->it_value = ns_to_timeval(val);
value->it_interval = ns_to_timeval(interval);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Roland McGrath | 61 | 40.13% | 2 | 16.67% |
Stanislaw Gruszka | 47 | 30.92% | 2 | 16.67% |
Frédéric Weisbecker | 21 | 13.82% | 2 | 16.67% |
Martin Schwidefsky | 10 | 6.58% | 2 | 16.67% |
Frank Mayhar | 8 | 5.26% | 1 | 8.33% |
Linus Torvalds (pre-git) | 3 | 1.97% | 1 | 8.33% |
Peter Zijlstra | 1 | 0.66% | 1 | 8.33% |
Thomas Gleixner | 1 | 0.66% | 1 | 8.33% |
Total | 152 | 100.00% | 12 | 100.00% |
int do_getitimer(int which, struct itimerval *value)
{
struct task_struct *tsk = current;
switch (which) {
case ITIMER_REAL:
spin_lock_irq(&tsk->sighand->siglock);
value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
value->it_interval =
ktime_to_timeval(tsk->signal->it_real_incr);
spin_unlock_irq(&tsk->sighand->siglock);
break;
case ITIMER_VIRTUAL:
get_cpu_itimer(tsk, CPUCLOCK_VIRT, value);
break;
case ITIMER_PROF:
get_cpu_itimer(tsk, CPUCLOCK_PROF, value);
break;
default:
return(-EINVAL);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stanislaw Gruszka | 55 | 48.67% | 1 | 25.00% |
Roland McGrath | 34 | 30.09% | 1 | 25.00% |
Linus Torvalds (pre-git) | 15 | 13.27% | 1 | 25.00% |
Martin Schwidefsky | 9 | 7.96% | 1 | 25.00% |
Total | 113 | 100.00% | 4 | 100.00% |
SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
{
int error = -EFAULT;
struct itimerval get_buffer;
if (value) {
error = do_getitimer(which, &get_buffer);
if (!error &&
copy_to_user(value, &get_buffer, sizeof(get_buffer)))
error = -EFAULT;
}
return error;
}
#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(getitimer, int, which,
struct compat_itimerval __user *, it)
{
struct itimerval kit;
int error = do_getitimer(which, &kit);
if (!error && put_compat_itimerval(it, &kit))
error = -EFAULT;
return error;
}
#endif
/*
* The timer is automagically restarted, when interval != 0
*/
enum hrtimer_restart it_real_fn(struct hrtimer *timer)
{
struct signal_struct *sig =
container_of(timer, struct signal_struct, real_timer);
trace_itimer_expire(ITIMER_REAL, sig->leader_pid, 0);
kill_pid_info(SIGALRM, SEND_SIG_PRIV, sig->leader_pid);
return HRTIMER_NORESTART;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Roland McGrath | 15 | 29.41% | 1 | 12.50% |
Roman Zippel | 15 | 29.41% | 1 | 12.50% |
Xiao Guangrong | 11 | 21.57% | 1 | 12.50% |
Thomas Gleixner | 6 | 11.76% | 2 | 25.00% |
Oleg Nesterov | 2 | 3.92% | 1 | 12.50% |
George Anzinger | 1 | 1.96% | 1 | 12.50% |
Linus Torvalds (pre-git) | 1 | 1.96% | 1 | 12.50% |
Total | 51 | 100.00% | 8 | 100.00% |
static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
const struct itimerval *const value,
struct itimerval *const ovalue)
{
u64 oval, nval, ointerval, ninterval;
struct cpu_itimer *it = &tsk->signal->it[clock_id];
/*
* Use the to_ktime conversion because that clamps the maximum
* value to KTIME_MAX and avoid multiplication overflows.
*/
nval = ktime_to_ns(timeval_to_ktime(value->it_value));
ninterval = ktime_to_ns(timeval_to_ktime(value->it_interval));
spin_lock_irq(&tsk->sighand->siglock);
oval = it->expires;
ointerval = it->incr;
if (oval || nval) {
if (nval > 0)
nval += TICK_NSEC;
set_process_cpu_timer(tsk, clock_id, &nval, &oval);
}
it->expires = nval;
it->incr = ninterval;
trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
spin_unlock_irq(&tsk->sighand->siglock);
if (ovalue) {
ovalue->it_value = ns_to_timeval(oval);
ovalue->it_interval = ns_to_timeval(ointerval);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Roland McGrath | 66 | 34.55% | 2 | 15.38% |
Stanislaw Gruszka | 46 | 24.08% | 2 | 15.38% |
Linus Torvalds (pre-git) | 22 | 11.52% | 2 | 15.38% |
Frédéric Weisbecker | 16 | 8.38% | 1 | 7.69% |
Xiao Guangrong | 15 | 7.85% | 1 | 7.69% |
Thomas Gleixner | 14 | 7.33% | 3 | 23.08% |
Martin Schwidefsky | 12 | 6.28% | 2 | 15.38% |
Total | 191 | 100.00% | 13 | 100.00% |
/*
* Returns true if the timeval is in canonical form
*/
#define timeval_valid(t) \
(((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
struct task_struct *tsk = current;
struct hrtimer *timer;
ktime_t expires;
/*
* Validate the timevals in value.
*/
if (!timeval_valid(&value->it_value) ||
!timeval_valid(&value->it_interval))
return -EINVAL;
switch (which) {
case ITIMER_REAL:
again:
spin_lock_irq(&tsk->sighand->siglock);
timer = &tsk->signal->real_timer;
if (ovalue) {
ovalue->it_value = itimer_get_remtime(timer);
ovalue->it_interval
= ktime_to_timeval(tsk->signal->it_real_incr);
}
/* We are sharing ->siglock with it_real_fn() */
if (hrtimer_try_to_cancel(timer) < 0) {
spin_unlock_irq(&tsk->sighand->siglock);
goto again;
}
expires = timeval_to_ktime(value->it_value);
if (expires != 0) {
tsk->signal->it_real_incr =
timeval_to_ktime(value->it_interval);
hrtimer_start(timer, expires, HRTIMER_MODE_REL);
} else
tsk->signal->it_real_incr = 0;
trace_itimer_state(ITIMER_REAL, value, 0);
spin_unlock_irq(&tsk->sighand->siglock);
break;
case ITIMER_VIRTUAL:
set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, ovalue);
break;
case ITIMER_PROF:
set_cpu_itimer(tsk, CPUCLOCK_PROF, value, ovalue);
break;
default:
return -EINVAL;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stanislaw Gruszka | 148 | 59.92% | 1 | 16.67% |
Roland McGrath | 58 | 23.48% | 1 | 16.67% |
Martin Schwidefsky | 17 | 6.88% | 1 | 16.67% |
Linus Torvalds (pre-git) | 15 | 6.07% | 2 | 33.33% |
Xiao Guangrong | 9 | 3.64% | 1 | 16.67% |
Total | 247 | 100.00% | 6 | 100.00% |
#ifdef __ARCH_WANT_SYS_ALARM
/**
* alarm_setitimer - set alarm in seconds
*
* @seconds: number of seconds until alarm
* 0 disables the alarm
*
* Returns the remaining time in seconds of a pending timer or 0 when
* the timer is not active.
*
* On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid
* negative timeval settings which would cause immediate expiry.
*/
static unsigned int alarm_setitimer(unsigned int seconds)
{
struct itimerval it_new, it_old;
#if BITS_PER_LONG < 64
if (seconds > INT_MAX)
seconds = INT_MAX;
#endif
it_new.it_value.tv_sec = seconds;
it_new.it_value.tv_usec = 0;
it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
do_setitimer(ITIMER_REAL, &it_new, &it_old);
/*
* We can't return 0 if we have an alarm pending ... And we'd
* better return too much than too little anyway
*/
if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) ||
it_old.it_value.tv_usec >= 500000)
it_old.it_value.tv_sec++;
return it_old.it_value.tv_sec;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Gleixner | 114 | 99.13% | 1 | 50.00% |
Nico Pitre | 1 | 0.87% | 1 | 50.00% |
Total | 115 | 100.00% | 2 | 100.00% |
/*
* For backwards compatibility? This can be done in libc so Alpha
* and all newer ports shouldn't need it.
*/
SYSCALL_DEFINE1(alarm, unsigned int, seconds)
{
return alarm_setitimer(seconds);
}
#endif
SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
struct itimerval __user *, ovalue)
{
struct itimerval set_buffer, get_buffer;
int error;
if (value) {
if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
return -EFAULT;
} else {
memset(&set_buffer, 0, sizeof(set_buffer));
printk_once(KERN_WARNING "%s calls setitimer() with new_value NULL pointer."
" Misfeature support will be removed\n",
current->comm);
}
error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
if (error || !ovalue)
return error;
if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
return -EFAULT;
return 0;
}
#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE3(setitimer, int, which,
struct compat_itimerval __user *, in,
struct compat_itimerval __user *, out)
{
struct itimerval kin, kout;
int error;
if (in) {
if (get_compat_itimerval(&kin, in))
return -EFAULT;
} else {
memset(&kin, 0, sizeof(kin));
}
error = do_setitimer(which, &kin, out ? &kout : NULL);
if (error || !out)
return error;
if (put_compat_itimerval(out, &kout))
return -EFAULT;
return 0;
}
#endif
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stanislaw Gruszka | 305 | 22.54% | 2 | 4.08% |
Roland McGrath | 243 | 17.96% | 2 | 4.08% |
Linus Torvalds (pre-git) | 237 | 17.52% | 15 | 30.61% |
Thomas Gleixner | 176 | 13.01% | 8 | 16.33% |
Al Viro | 170 | 12.56% | 1 | 2.04% |
Martin Schwidefsky | 48 | 3.55% | 2 | 4.08% |
Xiao Guangrong | 38 | 2.81% | 1 | 2.04% |
Frédéric Weisbecker | 37 | 2.73% | 2 | 4.08% |
Heiko Carstens | 28 | 2.07% | 2 | 4.08% |
Nico Pitre | 23 | 1.70% | 1 | 2.04% |
Roman Zippel | 15 | 1.11% | 1 | 2.04% |
Frank Mayhar | 8 | 0.59% | 1 | 2.04% |
Ingo Molnar | 6 | 0.44% | 2 | 4.08% |
Sasikantha babu | 6 | 0.44% | 1 | 2.04% |
Arnd Bergmann | 3 | 0.22% | 1 | 2.04% |
Andrew Morton | 3 | 0.22% | 1 | 2.04% |
Linus Torvalds | 2 | 0.15% | 2 | 4.08% |
Oleg Nesterov | 2 | 0.15% | 1 | 2.04% |
George Anzinger | 1 | 0.07% | 1 | 2.04% |
Greg Kroah-Hartman | 1 | 0.07% | 1 | 2.04% |
Peter Zijlstra | 1 | 0.07% | 1 | 2.04% |
Total | 1353 | 100.00% | 49 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.