The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/itimer.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/kernel/itimer.c
    3  *
    4  * Copyright (C) 1992 Darren Senn
    5  */
    6 
    7 /* These are all the functions necessary to implement itimers */
    8 
    9 #include <linux/mm.h>
   10 #include <linux/interrupt.h>
   11 #include <linux/syscalls.h>
   12 #include <linux/time.h>
   13 #include <linux/posix-timers.h>
   14 #include <linux/hrtimer.h>
   15 #include <trace/events/timer.h>
   16 
   17 #include <asm/uaccess.h>
   18 
   19 /**
   20  * itimer_get_remtime - get remaining time for the timer
   21  *
   22  * @timer: the timer to read
   23  *
   24  * Returns the delta between the expiry time and now, which can be
   25  * less than zero or 1usec for an pending expired timer
   26  */
   27 static struct timeval itimer_get_remtime(struct hrtimer *timer)
   28 {
   29         ktime_t rem = hrtimer_get_remaining(timer);
   30 
   31         /*
   32          * Racy but safe: if the itimer expires after the above
   33          * hrtimer_get_remtime() call but before this condition
   34          * then we return 0 - which is correct.
   35          */
   36         if (hrtimer_active(timer)) {
   37                 if (rem.tv64 <= 0)
   38                         rem.tv64 = NSEC_PER_USEC;
   39         } else
   40                 rem.tv64 = 0;
   41 
   42         return ktime_to_timeval(rem);
   43 }
   44 
   45 static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
   46                            struct itimerval *const value)
   47 {
   48         cputime_t cval, cinterval;
   49         struct cpu_itimer *it = &tsk->signal->it[clock_id];
   50 
   51         spin_lock_irq(&tsk->sighand->siglock);
   52 
   53         cval = it->expires;
   54         cinterval = it->incr;
   55         if (cval) {
   56                 struct task_cputime cputime;
   57                 cputime_t t;
   58 
   59                 thread_group_cputimer(tsk, &cputime);
   60                 if (clock_id == CPUCLOCK_PROF)
   61                         t = cputime.utime + cputime.stime;
   62                 else
   63                         /* CPUCLOCK_VIRT */
   64                         t = cputime.utime;
   65 
   66                 if (cval < t)
   67                         /* about to fire */
   68                         cval = cputime_one_jiffy;
   69                 else
   70                         cval = cval - t;
   71         }
   72 
   73         spin_unlock_irq(&tsk->sighand->siglock);
   74 
   75         cputime_to_timeval(cval, &value->it_value);
   76         cputime_to_timeval(cinterval, &value->it_interval);
   77 }
   78 
   79 int do_getitimer(int which, struct itimerval *value)
   80 {
   81         struct task_struct *tsk = current;
   82 
   83         switch (which) {
   84         case ITIMER_REAL:
   85                 spin_lock_irq(&tsk->sighand->siglock);
   86                 value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
   87                 value->it_interval =
   88                         ktime_to_timeval(tsk->signal->it_real_incr);
   89                 spin_unlock_irq(&tsk->sighand->siglock);
   90                 break;
   91         case ITIMER_VIRTUAL:
   92                 get_cpu_itimer(tsk, CPUCLOCK_VIRT, value);
   93                 break;
   94         case ITIMER_PROF:
   95                 get_cpu_itimer(tsk, CPUCLOCK_PROF, value);
   96                 break;
   97         default:
   98                 return(-EINVAL);
   99         }
  100         return 0;
  101 }
  102 
  103 SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
  104 {
  105         int error = -EFAULT;
  106         struct itimerval get_buffer;
  107 
  108         if (value) {
  109                 error = do_getitimer(which, &get_buffer);
  110                 if (!error &&
  111                     copy_to_user(value, &get_buffer, sizeof(get_buffer)))
  112                         error = -EFAULT;
  113         }
  114         return error;
  115 }
  116 
  117 
  118 /*
  119  * The timer is automagically restarted, when interval != 0
  120  */
  121 enum hrtimer_restart it_real_fn(struct hrtimer *timer)
  122 {
  123         struct signal_struct *sig =
  124                 container_of(timer, struct signal_struct, real_timer);
  125 
  126         trace_itimer_expire(ITIMER_REAL, sig->leader_pid, 0);
  127         kill_pid_info(SIGALRM, SEND_SIG_PRIV, sig->leader_pid);
  128 
  129         return HRTIMER_NORESTART;
  130 }
  131 
  132 static inline u32 cputime_sub_ns(cputime_t ct, s64 real_ns)
  133 {
  134         struct timespec ts;
  135         s64 cpu_ns;
  136 
  137         cputime_to_timespec(ct, &ts);
  138         cpu_ns = timespec_to_ns(&ts);
  139 
  140         return (cpu_ns <= real_ns) ? 0 : cpu_ns - real_ns;
  141 }
  142 
  143 static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
  144                            const struct itimerval *const value,
  145                            struct itimerval *const ovalue)
  146 {
  147         cputime_t cval, nval, cinterval, ninterval;
  148         s64 ns_ninterval, ns_nval;
  149         u32 error, incr_error;
  150         struct cpu_itimer *it = &tsk->signal->it[clock_id];
  151 
  152         nval = timeval_to_cputime(&value->it_value);
  153         ns_nval = timeval_to_ns(&value->it_value);
  154         ninterval = timeval_to_cputime(&value->it_interval);
  155         ns_ninterval = timeval_to_ns(&value->it_interval);
  156 
  157         error = cputime_sub_ns(nval, ns_nval);
  158         incr_error = cputime_sub_ns(ninterval, ns_ninterval);
  159 
  160         spin_lock_irq(&tsk->sighand->siglock);
  161 
  162         cval = it->expires;
  163         cinterval = it->incr;
  164         if (cval || nval) {
  165                 if (nval > 0)
  166                         nval += cputime_one_jiffy;
  167                 set_process_cpu_timer(tsk, clock_id, &nval, &cval);
  168         }
  169         it->expires = nval;
  170         it->incr = ninterval;
  171         it->error = error;
  172         it->incr_error = incr_error;
  173         trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
  174                            ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
  175 
  176         spin_unlock_irq(&tsk->sighand->siglock);
  177 
  178         if (ovalue) {
  179                 cputime_to_timeval(cval, &ovalue->it_value);
  180                 cputime_to_timeval(cinterval, &ovalue->it_interval);
  181         }
  182 }
  183 
  184 /*
  185  * Returns true if the timeval is in canonical form
  186  */
  187 #define timeval_valid(t) \
  188         (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
  189 
  190 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
  191 {
  192         struct task_struct *tsk = current;
  193         struct hrtimer *timer;
  194         ktime_t expires;
  195 
  196         /*
  197          * Validate the timevals in value.
  198          */
  199         if (!timeval_valid(&value->it_value) ||
  200             !timeval_valid(&value->it_interval))
  201                 return -EINVAL;
  202 
  203         switch (which) {
  204         case ITIMER_REAL:
  205 again:
  206                 spin_lock_irq(&tsk->sighand->siglock);
  207                 timer = &tsk->signal->real_timer;
  208                 if (ovalue) {
  209                         ovalue->it_value = itimer_get_remtime(timer);
  210                         ovalue->it_interval
  211                                 = ktime_to_timeval(tsk->signal->it_real_incr);
  212                 }
  213                 /* We are sharing ->siglock with it_real_fn() */
  214                 if (hrtimer_try_to_cancel(timer) < 0) {
  215                         spin_unlock_irq(&tsk->sighand->siglock);
  216                         goto again;
  217                 }
  218                 expires = timeval_to_ktime(value->it_value);
  219                 if (expires.tv64 != 0) {
  220                         tsk->signal->it_real_incr =
  221                                 timeval_to_ktime(value->it_interval);
  222                         hrtimer_start(timer, expires, HRTIMER_MODE_REL);
  223                 } else
  224                         tsk->signal->it_real_incr.tv64 = 0;
  225 
  226                 trace_itimer_state(ITIMER_REAL, value, 0);
  227                 spin_unlock_irq(&tsk->sighand->siglock);
  228                 break;
  229         case ITIMER_VIRTUAL:
  230                 set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, ovalue);
  231                 break;
  232         case ITIMER_PROF:
  233                 set_cpu_itimer(tsk, CPUCLOCK_PROF, value, ovalue);
  234                 break;
  235         default:
  236                 return -EINVAL;
  237         }
  238         return 0;
  239 }
  240 
  241 /**
  242  * alarm_setitimer - set alarm in seconds
  243  *
  244  * @seconds:    number of seconds until alarm
  245  *              0 disables the alarm
  246  *
  247  * Returns the remaining time in seconds of a pending timer or 0 when
  248  * the timer is not active.
  249  *
  250  * On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid
  251  * negative timeval settings which would cause immediate expiry.
  252  */
  253 unsigned int alarm_setitimer(unsigned int seconds)
  254 {
  255         struct itimerval it_new, it_old;
  256 
  257 #if BITS_PER_LONG < 64
  258         if (seconds > INT_MAX)
  259                 seconds = INT_MAX;
  260 #endif
  261         it_new.it_value.tv_sec = seconds;
  262         it_new.it_value.tv_usec = 0;
  263         it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
  264 
  265         do_setitimer(ITIMER_REAL, &it_new, &it_old);
  266 
  267         /*
  268          * We can't return 0 if we have an alarm pending ...  And we'd
  269          * better return too much than too little anyway
  270          */
  271         if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) ||
  272               it_old.it_value.tv_usec >= 500000)
  273                 it_old.it_value.tv_sec++;
  274 
  275         return it_old.it_value.tv_sec;
  276 }
  277 
  278 SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
  279                 struct itimerval __user *, ovalue)
  280 {
  281         struct itimerval set_buffer, get_buffer;
  282         int error;
  283 
  284         if (value) {
  285                 if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
  286                         return -EFAULT;
  287         } else {
  288                 memset(&set_buffer, 0, sizeof(set_buffer));
  289                 printk_once(KERN_WARNING "%s calls setitimer() with new_value NULL pointer."
  290                             " Misfeature support will be removed\n",
  291                             current->comm);
  292         }
  293 
  294         error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
  295         if (error || !ovalue)
  296                 return error;
  297 
  298         if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
  299                 return -EFAULT;
  300         return 0;
  301 }

Cache object: 307eb106145bb8fc4f6211512fee5ff5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.