linux-old/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
  13#include <asm/uaccess.h>
  14
  15/*
  16 * change timeval to jiffies, trying to avoid the 
  17 * most obvious overflows..
  18 *
  19 * The tv_*sec values are signed, but nothing seems to 
  20 * indicate whether we really should use them as signed values
  21 * when doing itimers. POSIX doesn't mention this (but if
  22 * alarm() uses itimers without checking, we have to use unsigned
  23 * arithmetic).
  24 */
  25static unsigned long tvtojiffies(struct timeval *value)
  26{
  27        unsigned long sec = (unsigned) value->tv_sec;
  28        unsigned long usec = (unsigned) value->tv_usec;
  29
  30        if (sec > (ULONG_MAX / HZ))
  31                return ULONG_MAX;
  32        usec += 1000000 / HZ - 1;
  33        usec /= 1000000 / HZ;
  34        return HZ*sec+usec;
  35}
  36
  37static void jiffiestotv(unsigned long jiffies, struct timeval *value)
  38{
  39        value->tv_usec = (jiffies % HZ) * (1000000 / HZ);
  40        value->tv_sec = jiffies / HZ;
  41}
  42
  43int do_getitimer(int which, struct itimerval *value)
  44{
  45        register unsigned long val, interval;
  46
  47        switch (which) {
  48        case ITIMER_REAL:
  49                interval = current->it_real_incr;
  50                val = 0;
  51                /* 
  52                 * FIXME! This needs to be atomic, in case the kernel timer happens!
  53                 */
  54                if (timer_pending(&current->real_timer)) {
  55                        val = current->real_timer.expires - jiffies;
  56
  57                        /* look out for negative/zero itimer.. */
  58                        if ((long) val <= 0)
  59                                val = 1;
  60                }
  61                break;
  62        case ITIMER_VIRTUAL:
  63                val = current->it_virt_value;
  64                interval = current->it_virt_incr;
  65                break;
  66        case ITIMER_PROF:
  67                val = current->it_prof_value;
  68                interval = current->it_prof_incr;
  69                break;
  70        default:
  71                return(-EINVAL);
  72        }
  73        jiffiestotv(val, &value->it_value);
  74        jiffiestotv(interval, &value->it_interval);
  75        return 0;
  76}
  77
  78/* SMP: Only we modify our itimer values. */
  79asmlinkage long sys_getitimer(int which, struct itimerval *value)
  80{
  81        int error = -EFAULT;
  82        struct itimerval get_buffer;
  83
  84        if (value) {
  85                error = do_getitimer(which, &get_buffer);
  86                if (!error &&
  87                    copy_to_user(value, &get_buffer, sizeof(get_buffer)))
  88                        error = -EFAULT;
  89        }
  90        return error;
  91}
  92
  93void it_real_fn(unsigned long __data)
  94{
  95        struct task_struct * p = (struct task_struct *) __data;
  96        unsigned long interval;
  97
  98        send_sig(SIGALRM, p, 1);
  99        interval = p->it_real_incr;
 100        if (interval) {
 101                if (interval > (unsigned long) LONG_MAX)
 102                        interval = LONG_MAX;
 103                p->real_timer.expires = jiffies + interval;
 104                add_timer(&p->real_timer);
 105        }
 106}
 107
 108int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 109{
 110        register unsigned long i, j;
 111        int k;
 112
 113        i = tvtojiffies(&value->it_interval);
 114        j = tvtojiffies(&value->it_value);
 115        if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
 116                return k;
 117        switch (which) {
 118                case ITIMER_REAL:
 119                        del_timer_sync(&current->real_timer);
 120                        current->it_real_value = j;
 121                        current->it_real_incr = i;
 122                        if (!j)
 123                                break;
 124                        if (j > (unsigned long) LONG_MAX)
 125                                j = LONG_MAX;
 126                        i = j + jiffies;
 127                        current->real_timer.expires = i;
 128                        add_timer(&current->real_timer);
 129                        break;
 130                case ITIMER_VIRTUAL:
 131                        if (j)
 132                                j++;
 133                        current->it_virt_value = j;
 134                        current->it_virt_incr = i;
 135                        break;
 136                case ITIMER_PROF:
 137                        if (j)
 138                                j++;
 139                        current->it_prof_value = j;
 140                        current->it_prof_incr = i;
 141                        break;
 142                default:
 143                        return -EINVAL;
 144        }
 145        return 0;
 146}
 147
 148/* SMP: Again, only we play with our itimers, and signals are SMP safe
 149 *      now so that is not an issue at all anymore.
 150 */
 151asmlinkage long sys_setitimer(int which, struct itimerval *value,
 152                              struct itimerval *ovalue)
 153{
 154        struct itimerval set_buffer, get_buffer;
 155        int error;
 156
 157        if (value) {
 158                if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
 159                        return -EFAULT;
 160        } else
 161                memset((char *) &set_buffer, 0, sizeof(set_buffer));
 162
 163        error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
 164        if (error || !ovalue)
 165                return error;
 166
 167        if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
 168                return -EFAULT; 
 169        return 0;
 170}
 171
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.