RHEL4/kernel/itimer.c
<<
>>
Prefs
   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/smp_lock.h>
  11#include <linux/interrupt.h>
  12#include <linux/time.h>
  13
  14#include <asm/uaccess.h>
  15
  16int do_getitimer(int which, struct itimerval *value)
  17{
  18        register unsigned long val, interval;
  19
  20        switch (which) {
  21        case ITIMER_REAL:
  22                interval = current->it_real_incr;
  23                val = 0;
  24                /* 
  25                 * FIXME! This needs to be atomic, in case the kernel timer happens!
  26                 */
  27                if (timer_pending(&current->real_timer)) {
  28                        val = current->real_timer.expires - jiffies;
  29
  30                        /* look out for negative/zero itimer.. */
  31                        if ((long) val <= 0)
  32                                val = 1;
  33                }
  34                break;
  35        case ITIMER_VIRTUAL:
  36                val = current->it_virt_value;
  37                interval = current->it_virt_incr;
  38                break;
  39        case ITIMER_PROF:
  40                val = current->it_prof_value;
  41                interval = current->it_prof_incr;
  42                break;
  43        default:
  44                return(-EINVAL);
  45        }
  46        jiffies_to_timeval(val, &value->it_value);
  47        jiffies_to_timeval(interval, &value->it_interval);
  48        return 0;
  49}
  50
  51/* SMP: Only we modify our itimer values. */
  52asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
  53{
  54        int error = -EFAULT;
  55        struct itimerval get_buffer;
  56
  57        if (value) {
  58                error = do_getitimer(which, &get_buffer);
  59                if (!error &&
  60                    copy_to_user(value, &get_buffer, sizeof(get_buffer)))
  61                        error = -EFAULT;
  62        }
  63        return error;
  64}
  65
  66void it_real_fn(unsigned long __data)
  67{
  68        struct task_struct * p = (struct task_struct *) __data;
  69        unsigned long interval;
  70
  71        send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
  72        interval = p->it_real_incr;
  73        if (interval) {
  74                if (interval > (unsigned long) LONG_MAX)
  75                        interval = LONG_MAX;
  76                p->real_timer.expires = jiffies + interval;
  77                add_timer(&p->real_timer);
  78        }
  79}
  80
  81int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
  82{
  83        register unsigned long i, j;
  84        int k;
  85
  86        i = timeval_to_jiffies(&value->it_interval);
  87        j = timeval_to_jiffies(&value->it_value);
  88        if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
  89                return k;
  90        switch (which) {
  91                case ITIMER_REAL:
  92                        del_timer_sync(&current->real_timer);
  93                        current->it_real_value = j;
  94                        current->it_real_incr = i;
  95                        if (!j)
  96                                break;
  97                        if (j > (unsigned long) LONG_MAX)
  98                                j = LONG_MAX;
  99                        i = j + jiffies;
 100                        current->real_timer.expires = i;
 101                        add_timer(&current->real_timer);
 102                        break;
 103                case ITIMER_VIRTUAL:
 104                        if (j)
 105                                j++;
 106                        current->it_virt_value = j;
 107                        current->it_virt_incr = i;
 108                        break;
 109                case ITIMER_PROF:
 110                        if (j)
 111                                j++;
 112                        current->it_prof_value = j;
 113                        current->it_prof_incr = i;
 114                        break;
 115                default:
 116                        return -EINVAL;
 117        }
 118        return 0;
 119}
 120
 121/* SMP: Again, only we play with our itimers, and signals are SMP safe
 122 *      now so that is not an issue at all anymore.
 123 */
 124asmlinkage long sys_setitimer(int which,
 125                              struct itimerval __user *value,
 126                              struct itimerval __user *ovalue)
 127{
 128        struct itimerval set_buffer, get_buffer;
 129        int error;
 130
 131        if (value) {
 132                if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
 133                        return -EFAULT;
 134        } else
 135                memset((char *) &set_buffer, 0, sizeof(set_buffer));
 136
 137        error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
 138        if (error || !ovalue)
 139                return error;
 140
 141        if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
 142                return -EFAULT; 
 143        return 0;
 144}
 145