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