2005-04-17 02:20:36 +04:00
/*
* 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/posix-timers.h>
2006-01-10 07:52:34 +03:00
# include <linux/hrtimer.h>
2009-08-10 06:52:30 +04:00
# include <trace/events/timer.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
2006-01-10 07:52:34 +03:00
/**
* 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 1u sec for an pending expired timer
*/
static struct timeval itimer_get_remtime ( struct hrtimer * timer )
2005-04-17 02:20:36 +04:00
{
2006-01-10 07:52:34 +03:00
ktime_t rem = hrtimer_get_remaining ( timer ) ;
2005-04-17 02:20:36 +04:00
2006-01-10 07:52:34 +03:00
/*
* 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 . tv64 < = 0 )
rem . tv64 = NSEC_PER_USEC ;
} else
rem . tv64 = 0 ;
return ktime_to_timeval ( rem ) ;
2005-04-17 02:20:36 +04:00
}
2009-07-29 14:15:26 +04:00
static void get_cpu_itimer ( struct task_struct * tsk , unsigned int clock_id ,
2009-07-29 14:15:27 +04:00
struct itimerval * const value )
2009-07-29 14:15:26 +04:00
{
cputime_t cval , cinterval ;
struct cpu_itimer * it = & tsk - > signal - > it [ clock_id ] ;
spin_lock_irq ( & tsk - > sighand - > siglock ) ;
cval = it - > expires ;
cinterval = it - > incr ;
2011-12-15 17:56:09 +04:00
if ( cval ) {
2009-07-29 14:15:26 +04:00
struct task_cputime cputime ;
cputime_t t ;
thread_group_cputimer ( tsk , & cputime ) ;
if ( clock_id = = CPUCLOCK_PROF )
2011-12-15 17:56:09 +04:00
t = cputime . utime + cputime . stime ;
2009-07-29 14:15:26 +04:00
else
/* CPUCLOCK_VIRT */
t = cputime . utime ;
2011-12-15 17:56:09 +04:00
if ( cval < t )
2009-07-29 14:15:26 +04:00
/* about to fire */
2009-07-29 14:15:29 +04:00
cval = cputime_one_jiffy ;
2009-07-29 14:15:26 +04:00
else
2011-12-15 17:56:09 +04:00
cval = cval - t ;
2009-07-29 14:15:26 +04:00
}
spin_unlock_irq ( & tsk - > sighand - > siglock ) ;
cputime_to_timeval ( cval , & value - > it_value ) ;
cputime_to_timeval ( cinterval , & value - > it_interval ) ;
}
2005-04-17 02:20:36 +04:00
int do_getitimer ( int which , struct itimerval * value )
{
struct task_struct * tsk = current ;
switch ( which ) {
case ITIMER_REAL :
2006-02-01 14:05:08 +03:00
spin_lock_irq ( & tsk - > sighand - > siglock ) ;
2006-01-10 07:52:34 +03:00
value - > it_value = itimer_get_remtime ( & tsk - > signal - > real_timer ) ;
value - > it_interval =
ktime_to_timeval ( tsk - > signal - > it_real_incr ) ;
2006-02-01 14:05:08 +03:00
spin_unlock_irq ( & tsk - > sighand - > siglock ) ;
2005-04-17 02:20:36 +04:00
break ;
case ITIMER_VIRTUAL :
2009-07-29 14:15:26 +04:00
get_cpu_itimer ( tsk , CPUCLOCK_VIRT , value ) ;
2005-04-17 02:20:36 +04:00
break ;
case ITIMER_PROF :
2009-07-29 14:15:26 +04:00
get_cpu_itimer ( tsk , CPUCLOCK_PROF , value ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
return ( - EINVAL ) ;
}
return 0 ;
}
2009-01-14 16:14:06 +03:00
SYSCALL_DEFINE2 ( getitimer , int , which , struct itimerval __user * , value )
2005-04-17 02:20:36 +04:00
{
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 ;
}
2006-01-10 07:52:34 +03:00
/*
* The timer is automagically restarted , when interval ! = 0
*/
2007-02-16 12:27:49 +03:00
enum hrtimer_restart it_real_fn ( struct hrtimer * timer )
2005-04-17 02:20:36 +04:00
{
2006-03-26 13:38:12 +04:00
struct signal_struct * sig =
2007-10-18 14:06:11 +04:00
container_of ( timer , struct signal_struct , real_timer ) ;
2005-04-17 02:20:36 +04:00
2009-08-10 06:52:30 +04:00
trace_itimer_expire ( ITIMER_REAL , sig - > leader_pid , 0 ) ;
2008-02-08 15:19:19 +03:00
kill_pid_info ( SIGALRM , SEND_SIG_PRIV , sig - > leader_pid ) ;
2006-01-10 07:52:34 +03:00
return HRTIMER_NORESTART ;
2005-04-17 02:20:36 +04:00
}
2009-07-29 14:15:27 +04:00
static inline u32 cputime_sub_ns ( cputime_t ct , s64 real_ns )
{
struct timespec ts ;
s64 cpu_ns ;
cputime_to_timespec ( ct , & ts ) ;
cpu_ns = timespec_to_ns ( & ts ) ;
return ( cpu_ns < = real_ns ) ? 0 : cpu_ns - real_ns ;
}
2009-07-29 14:15:26 +04:00
static void set_cpu_itimer ( struct task_struct * tsk , unsigned int clock_id ,
2009-07-29 14:15:27 +04:00
const struct itimerval * const value ,
struct itimerval * const ovalue )
2009-07-29 14:15:26 +04:00
{
2009-07-29 14:15:27 +04:00
cputime_t cval , nval , cinterval , ninterval ;
s64 ns_ninterval , ns_nval ;
2009-11-18 01:14:12 +03:00
u32 error , incr_error ;
2009-07-29 14:15:26 +04:00
struct cpu_itimer * it = & tsk - > signal - > it [ clock_id ] ;
nval = timeval_to_cputime ( & value - > it_value ) ;
2009-07-29 14:15:27 +04:00
ns_nval = timeval_to_ns ( & value - > it_value ) ;
2009-07-29 14:15:26 +04:00
ninterval = timeval_to_cputime ( & value - > it_interval ) ;
2009-07-29 14:15:27 +04:00
ns_ninterval = timeval_to_ns ( & value - > it_interval ) ;
2009-11-18 01:14:12 +03:00
error = cputime_sub_ns ( nval , ns_nval ) ;
incr_error = cputime_sub_ns ( ninterval , ns_ninterval ) ;
2009-07-29 14:15:26 +04:00
spin_lock_irq ( & tsk - > sighand - > siglock ) ;
cval = it - > expires ;
cinterval = it - > incr ;
2011-12-15 17:56:09 +04:00
if ( cval | | nval ) {
if ( nval > 0 )
nval + = cputime_one_jiffy ;
2009-07-29 14:15:26 +04:00
set_process_cpu_timer ( tsk , clock_id , & nval , & cval ) ;
}
it - > expires = nval ;
it - > incr = ninterval ;
2009-11-18 01:14:12 +03:00
it - > error = error ;
it - > incr_error = incr_error ;
2009-08-10 06:52:30 +04:00
trace_itimer_state ( clock_id = = CPUCLOCK_VIRT ?
ITIMER_VIRTUAL : ITIMER_PROF , value , nval ) ;
2009-07-29 14:15:26 +04:00
spin_unlock_irq ( & tsk - > sighand - > siglock ) ;
if ( ovalue ) {
cputime_to_timeval ( cval , & ovalue - > it_value ) ;
cputime_to_timeval ( cinterval , & ovalue - > it_interval ) ;
}
}
2006-03-25 14:06:35 +03: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 ) )
2005-04-17 02:20:36 +04:00
int do_setitimer ( int which , struct itimerval * value , struct itimerval * ovalue )
{
struct task_struct * tsk = current ;
2006-01-10 07:52:34 +03:00
struct hrtimer * timer ;
ktime_t expires ;
2005-04-17 02:20:36 +04:00
2006-03-25 14:06:35 +03:00
/*
* Validate the timevals in value .
*/
2007-05-08 11:30:49 +04:00
if ( ! timeval_valid ( & value - > it_value ) | |
! timeval_valid ( & value - > it_interval ) )
return - EINVAL ;
2006-03-25 14:06:35 +03:00
2005-04-17 02:20:36 +04:00
switch ( which ) {
case ITIMER_REAL :
2006-02-01 14:05:08 +03:00
again :
spin_lock_irq ( & tsk - > sighand - > siglock ) ;
2006-01-10 07:52:34 +03:00
timer = & tsk - > signal - > real_timer ;
2005-04-17 02:20:36 +04:00
if ( ovalue ) {
2006-01-10 07:52:34 +03:00
ovalue - > it_value = itimer_get_remtime ( timer ) ;
ovalue - > it_interval
= ktime_to_timeval ( tsk - > signal - > it_real_incr ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-01 14:05:09 +03:00
/* We are sharing ->siglock with it_real_fn() */
if ( hrtimer_try_to_cancel ( timer ) < 0 ) {
spin_unlock_irq ( & tsk - > sighand - > siglock ) ;
goto again ;
}
2006-01-10 07:52:34 +03:00
expires = timeval_to_ktime ( value - > it_value ) ;
2007-02-16 12:28:12 +03:00
if ( expires . tv64 ! = 0 ) {
tsk - > signal - > it_real_incr =
timeval_to_ktime ( value - > it_interval ) ;
2007-02-16 12:27:49 +03:00
hrtimer_start ( timer , expires , HRTIMER_MODE_REL ) ;
2007-02-16 12:28:12 +03:00
} else
tsk - > signal - > it_real_incr . tv64 = 0 ;
2009-08-10 06:52:30 +04:00
trace_itimer_state ( ITIMER_REAL , value , 0 ) ;
2006-02-01 14:05:08 +03:00
spin_unlock_irq ( & tsk - > sighand - > siglock ) ;
2005-04-17 02:20:36 +04:00
break ;
case ITIMER_VIRTUAL :
2009-07-29 14:15:26 +04:00
set_cpu_itimer ( tsk , CPUCLOCK_VIRT , value , ovalue ) ;
2005-04-17 02:20:36 +04:00
break ;
case ITIMER_PROF :
2009-07-29 14:15:26 +04:00
set_cpu_itimer ( tsk , CPUCLOCK_PROF , value , ovalue ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2006-03-25 14:06:33 +03:00
/**
* 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 .
*/
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 ;
}
2009-01-14 16:14:07 +03:00
SYSCALL_DEFINE3 ( setitimer , int , which , struct itimerval __user * , value ,
struct itimerval __user * , ovalue )
2005-04-17 02:20:36 +04:00
{
struct itimerval set_buffer , get_buffer ;
int error ;
if ( value ) {
if ( copy_from_user ( & set_buffer , value , sizeof ( set_buffer ) ) )
return - EFAULT ;
2012-03-21 18:40:54 +04:00
} else {
2012-04-10 12:50:55 +04:00
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 ) ;
2012-03-21 18:40:54 +04:00
}
2005-04-17 02:20:36 +04:00
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 ) ) )
2007-10-18 14:06:11 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
return 0 ;
}