itimer.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * linux/kernel/itimer.c
  3. *
  4. * Copyright (C) 1992 Darren Senn
  5. */
  6. /* These are all the functions necessary to implement itimers */
  7. #include <linux/mm.h>
  8. #include <linux/smp_lock.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/syscalls.h>
  11. #include <linux/time.h>
  12. #include <linux/posix-timers.h>
  13. #include <asm/uaccess.h>
  14. static unsigned long it_real_value(struct signal_struct *sig)
  15. {
  16. unsigned long val = 0;
  17. if (timer_pending(&sig->real_timer)) {
  18. val = sig->real_timer.expires - jiffies;
  19. /* look out for negative/zero itimer.. */
  20. if ((long) val <= 0)
  21. val = 1;
  22. }
  23. return val;
  24. }
  25. int do_getitimer(int which, struct itimerval *value)
  26. {
  27. struct task_struct *tsk = current;
  28. unsigned long interval, val;
  29. cputime_t cinterval, cval;
  30. switch (which) {
  31. case ITIMER_REAL:
  32. spin_lock_irq(&tsk->sighand->siglock);
  33. interval = tsk->signal->it_real_incr;
  34. val = it_real_value(tsk->signal);
  35. spin_unlock_irq(&tsk->sighand->siglock);
  36. jiffies_to_timeval(val, &value->it_value);
  37. jiffies_to_timeval(interval, &value->it_interval);
  38. break;
  39. case ITIMER_VIRTUAL:
  40. read_lock(&tasklist_lock);
  41. spin_lock_irq(&tsk->sighand->siglock);
  42. cval = tsk->signal->it_virt_expires;
  43. cinterval = tsk->signal->it_virt_incr;
  44. if (!cputime_eq(cval, cputime_zero)) {
  45. struct task_struct *t = tsk;
  46. cputime_t utime = tsk->signal->utime;
  47. do {
  48. utime = cputime_add(utime, t->utime);
  49. t = next_thread(t);
  50. } while (t != tsk);
  51. if (cputime_le(cval, utime)) { /* about to fire */
  52. cval = jiffies_to_cputime(1);
  53. } else {
  54. cval = cputime_sub(cval, utime);
  55. }
  56. }
  57. spin_unlock_irq(&tsk->sighand->siglock);
  58. read_unlock(&tasklist_lock);
  59. cputime_to_timeval(cval, &value->it_value);
  60. cputime_to_timeval(cinterval, &value->it_interval);
  61. break;
  62. case ITIMER_PROF:
  63. read_lock(&tasklist_lock);
  64. spin_lock_irq(&tsk->sighand->siglock);
  65. cval = tsk->signal->it_prof_expires;
  66. cinterval = tsk->signal->it_prof_incr;
  67. if (!cputime_eq(cval, cputime_zero)) {
  68. struct task_struct *t = tsk;
  69. cputime_t ptime = cputime_add(tsk->signal->utime,
  70. tsk->signal->stime);
  71. do {
  72. ptime = cputime_add(ptime,
  73. cputime_add(t->utime,
  74. t->stime));
  75. t = next_thread(t);
  76. } while (t != tsk);
  77. if (cputime_le(cval, ptime)) { /* about to fire */
  78. cval = jiffies_to_cputime(1);
  79. } else {
  80. cval = cputime_sub(cval, ptime);
  81. }
  82. }
  83. spin_unlock_irq(&tsk->sighand->siglock);
  84. read_unlock(&tasklist_lock);
  85. cputime_to_timeval(cval, &value->it_value);
  86. cputime_to_timeval(cinterval, &value->it_interval);
  87. break;
  88. default:
  89. return(-EINVAL);
  90. }
  91. return 0;
  92. }
  93. asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
  94. {
  95. int error = -EFAULT;
  96. struct itimerval get_buffer;
  97. if (value) {
  98. error = do_getitimer(which, &get_buffer);
  99. if (!error &&
  100. copy_to_user(value, &get_buffer, sizeof(get_buffer)))
  101. error = -EFAULT;
  102. }
  103. return error;
  104. }
  105. /*
  106. * Called with P->sighand->siglock held and P->signal->real_timer inactive.
  107. * If interval is nonzero, arm the timer for interval ticks from now.
  108. */
  109. static inline void it_real_arm(struct task_struct *p, unsigned long interval)
  110. {
  111. p->signal->it_real_value = interval; /* XXX unnecessary field?? */
  112. if (interval == 0)
  113. return;
  114. if (interval > (unsigned long) LONG_MAX)
  115. interval = LONG_MAX;
  116. /* the "+ 1" below makes sure that the timer doesn't go off before
  117. * the interval requested. This could happen if
  118. * time requested % (usecs per jiffy) is more than the usecs left
  119. * in the current jiffy */
  120. p->signal->real_timer.expires = jiffies + interval + 1;
  121. add_timer(&p->signal->real_timer);
  122. }
  123. void it_real_fn(unsigned long __data)
  124. {
  125. struct task_struct * p = (struct task_struct *) __data;
  126. send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
  127. /*
  128. * Now restart the timer if necessary. We don't need any locking
  129. * here because do_setitimer makes sure we have finished running
  130. * before it touches anything.
  131. */
  132. it_real_arm(p, p->signal->it_real_incr);
  133. }
  134. int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
  135. {
  136. struct task_struct *tsk = current;
  137. unsigned long val, interval;
  138. cputime_t cval, cinterval, nval, ninterval;
  139. switch (which) {
  140. case ITIMER_REAL:
  141. again:
  142. spin_lock_irq(&tsk->sighand->siglock);
  143. interval = tsk->signal->it_real_incr;
  144. val = it_real_value(tsk->signal);
  145. /* We are sharing ->siglock with it_real_fn() */
  146. if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
  147. spin_unlock_irq(&tsk->sighand->siglock);
  148. goto again;
  149. }
  150. tsk->signal->it_real_incr =
  151. timeval_to_jiffies(&value->it_interval);
  152. it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
  153. spin_unlock_irq(&tsk->sighand->siglock);
  154. if (ovalue) {
  155. jiffies_to_timeval(val, &ovalue->it_value);
  156. jiffies_to_timeval(interval,
  157. &ovalue->it_interval);
  158. }
  159. break;
  160. case ITIMER_VIRTUAL:
  161. nval = timeval_to_cputime(&value->it_value);
  162. ninterval = timeval_to_cputime(&value->it_interval);
  163. read_lock(&tasklist_lock);
  164. spin_lock_irq(&tsk->sighand->siglock);
  165. cval = tsk->signal->it_virt_expires;
  166. cinterval = tsk->signal->it_virt_incr;
  167. if (!cputime_eq(cval, cputime_zero) ||
  168. !cputime_eq(nval, cputime_zero)) {
  169. if (cputime_gt(nval, cputime_zero))
  170. nval = cputime_add(nval,
  171. jiffies_to_cputime(1));
  172. set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
  173. &nval, &cval);
  174. }
  175. tsk->signal->it_virt_expires = nval;
  176. tsk->signal->it_virt_incr = ninterval;
  177. spin_unlock_irq(&tsk->sighand->siglock);
  178. read_unlock(&tasklist_lock);
  179. if (ovalue) {
  180. cputime_to_timeval(cval, &ovalue->it_value);
  181. cputime_to_timeval(cinterval, &ovalue->it_interval);
  182. }
  183. break;
  184. case ITIMER_PROF:
  185. nval = timeval_to_cputime(&value->it_value);
  186. ninterval = timeval_to_cputime(&value->it_interval);
  187. read_lock(&tasklist_lock);
  188. spin_lock_irq(&tsk->sighand->siglock);
  189. cval = tsk->signal->it_prof_expires;
  190. cinterval = tsk->signal->it_prof_incr;
  191. if (!cputime_eq(cval, cputime_zero) ||
  192. !cputime_eq(nval, cputime_zero)) {
  193. if (cputime_gt(nval, cputime_zero))
  194. nval = cputime_add(nval,
  195. jiffies_to_cputime(1));
  196. set_process_cpu_timer(tsk, CPUCLOCK_PROF,
  197. &nval, &cval);
  198. }
  199. tsk->signal->it_prof_expires = nval;
  200. tsk->signal->it_prof_incr = ninterval;
  201. spin_unlock_irq(&tsk->sighand->siglock);
  202. read_unlock(&tasklist_lock);
  203. if (ovalue) {
  204. cputime_to_timeval(cval, &ovalue->it_value);
  205. cputime_to_timeval(cinterval, &ovalue->it_interval);
  206. }
  207. break;
  208. default:
  209. return -EINVAL;
  210. }
  211. return 0;
  212. }
  213. asmlinkage long sys_setitimer(int which,
  214. struct itimerval __user *value,
  215. struct itimerval __user *ovalue)
  216. {
  217. struct itimerval set_buffer, get_buffer;
  218. int error;
  219. if (value) {
  220. if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
  221. return -EFAULT;
  222. } else
  223. memset((char *) &set_buffer, 0, sizeof(set_buffer));
  224. error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
  225. if (error || !ovalue)
  226. return error;
  227. if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
  228. return -EFAULT;
  229. return 0;
  230. }