/* * linux/kernel/itimer.c * * Copyright (C) 1992 Darren Senn */ /* These are all the functions necessary to implement itimers */ #include <linux/mm.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <asm/uaccess.h> /* * change timeval to jiffies, trying to avoid the * most obvious overflows.. * * The tv_*sec values are signed, but nothing seems to * indicate whether we really should use them as signed values * when doing itimers. POSIX doesn't mention this (but if * alarm() uses itimers without checking, we have to use unsigned * arithmetic). */ 25 static unsigned long tvtojiffies(struct timeval *value) { unsigned long sec = (unsigned) value->tv_sec; unsigned long usec = (unsigned) value->tv_usec; 30 if (sec > (ULONG_MAX / HZ)) 31 return ULONG_MAX; usec += 1000000 / HZ - 1; usec /= 1000000 / HZ; 34 return HZ*sec+usec; } 37 static void jiffiestotv(unsigned long jiffies, struct timeval *value) { value->tv_usec = (jiffies % HZ) * (1000000 / HZ); value->tv_sec = jiffies / HZ; } 43 int do_getitimer(int which, struct itimerval *value) { register unsigned long val, interval; 47 switch (which) { 48 case ITIMER_REAL: interval = current->it_real_incr; val = 0; /* * FIXME! This needs to be atomic, in case the kernel timer happens! */ 54 if (timer_pending(¤t->real_timer)) { val = current->real_timer.expires - jiffies; /* look out for negative/zero itimer.. */ 58 if ((long) val <= 0) val = 1; } 61 break; 62 case ITIMER_VIRTUAL: val = current->it_virt_value; interval = current->it_virt_incr; 65 break; 66 case ITIMER_PROF: val = current->it_prof_value; interval = current->it_prof_incr; 69 break; 70 default: 71 return(-EINVAL); } jiffiestotv(val, &value->it_value); jiffiestotv(interval, &value->it_interval); 75 return 0; } /* SMP: Only we modify our itimer values. */ 79 asmlinkage long sys_getitimer(int which, struct itimerval *value) { int error = -EFAULT; struct itimerval get_buffer; 84 if (value) { error = do_getitimer(which, &get_buffer); if (!error && 87 copy_to_user(value, &get_buffer, sizeof(get_buffer))) error = -EFAULT; } 90 return error; } 93 void it_real_fn(unsigned long __data) { struct task_struct * p = (struct task_struct *) __data; unsigned long interval; send_sig(SIGALRM, p, 1); interval = p->it_real_incr; 100 if (interval) { 101 if (interval > (unsigned long) LONG_MAX) interval = LONG_MAX; p->real_timer.expires = jiffies + interval; add_timer(&p->real_timer); } } 108 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) { register unsigned long i, j; int k; i = tvtojiffies(&value->it_interval); j = tvtojiffies(&value->it_value); 115 if (ovalue && (k = do_getitimer(which, ovalue)) < 0) 116 return k; 117 switch (which) { 118 case ITIMER_REAL: del_timer_sync(¤t->real_timer); current->it_real_value = j; current->it_real_incr = i; 122 if (!j) 123 break; 124 if (j > (unsigned long) LONG_MAX) j = LONG_MAX; i = j + jiffies; current->real_timer.expires = i; add_timer(¤t->real_timer); 129 break; 130 case ITIMER_VIRTUAL: 131 if (j) j++; current->it_virt_value = j; current->it_virt_incr = i; 135 break; 136 case ITIMER_PROF: 137 if (j) j++; current->it_prof_value = j; current->it_prof_incr = i; 141 break; 142 default: 143 return -EINVAL; } 145 return 0; } /* SMP: Again, only we play with our itimers, and signals are SMP safe * now so that is not an issue at all anymore. */ 151 asmlinkage long sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) { struct itimerval set_buffer, get_buffer; int error; 157 if (value) { 158 if(copy_from_user(&set_buffer, value, sizeof(set_buffer))) 159 return -EFAULT; 160 } else memset((char *) &set_buffer, 0, sizeof(set_buffer)); error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); 164 if (error || !ovalue) 165 return error; 167 if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer))) 168 return -EFAULT; 169 return 0; }