itimer.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. void it_real_fn(unsigned long __data)
  106. {
  107. struct task_struct * p = (struct task_struct *) __data;
  108. unsigned long inc = p->signal->it_real_incr;
  109. send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
  110. /*
  111. * Now restart the timer if necessary. We don't need any locking
  112. * here because do_setitimer makes sure we have finished running
  113. * before it touches anything.
  114. * Note, we KNOW we are (or should be) at a jiffie edge here so
  115. * we don't need the +1 stuff. Also, we want to use the prior
  116. * expire value so as to not "slip" a jiffie if we are late.
  117. * Deal with requesting a time prior to "now" here rather than
  118. * in add_timer.
  119. */
  120. if (!inc)
  121. return;
  122. while (time_before_eq(p->signal->real_timer.expires, jiffies))
  123. p->signal->real_timer.expires += inc;
  124. add_timer(&p->signal->real_timer);
  125. }
  126. int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
  127. {
  128. struct task_struct *tsk = current;
  129. unsigned long val, interval, expires;
  130. cputime_t cval, cinterval, nval, ninterval;
  131. switch (which) {
  132. case ITIMER_REAL:
  133. again:
  134. spin_lock_irq(&tsk->sighand->siglock);
  135. interval = tsk->signal->it_real_incr;
  136. val = it_real_value(tsk->signal);
  137. /* We are sharing ->siglock with it_real_fn() */
  138. if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
  139. spin_unlock_irq(&tsk->sighand->siglock);
  140. goto again;
  141. }
  142. tsk->signal->it_real_incr =
  143. timeval_to_jiffies(&value->it_interval);
  144. expires = timeval_to_jiffies(&value->it_value);
  145. if (expires)
  146. mod_timer(&tsk->signal->real_timer,
  147. jiffies + 1 + expires);
  148. spin_unlock_irq(&tsk->sighand->siglock);
  149. if (ovalue) {
  150. jiffies_to_timeval(val, &ovalue->it_value);
  151. jiffies_to_timeval(interval,
  152. &ovalue->it_interval);
  153. }
  154. break;
  155. case ITIMER_VIRTUAL:
  156. nval = timeval_to_cputime(&value->it_value);
  157. ninterval = timeval_to_cputime(&value->it_interval);
  158. read_lock(&tasklist_lock);
  159. spin_lock_irq(&tsk->sighand->siglock);
  160. cval = tsk->signal->it_virt_expires;
  161. cinterval = tsk->signal->it_virt_incr;
  162. if (!cputime_eq(cval, cputime_zero) ||
  163. !cputime_eq(nval, cputime_zero)) {
  164. if (cputime_gt(nval, cputime_zero))
  165. nval = cputime_add(nval,
  166. jiffies_to_cputime(1));
  167. set_process_cpu_timer(tsk, CPUCLOCK_VIRT,
  168. &nval, &cval);
  169. }
  170. tsk->signal->it_virt_expires = nval;
  171. tsk->signal->it_virt_incr = ninterval;
  172. spin_unlock_irq(&tsk->sighand->siglock);
  173. read_unlock(&tasklist_lock);
  174. if (ovalue) {
  175. cputime_to_timeval(cval, &ovalue->it_value);
  176. cputime_to_timeval(cinterval, &ovalue->it_interval);
  177. }
  178. break;
  179. case ITIMER_PROF:
  180. nval = timeval_to_cputime(&value->it_value);
  181. ninterval = timeval_to_cputime(&value->it_interval);
  182. read_lock(&tasklist_lock);
  183. spin_lock_irq(&tsk->sighand->siglock);
  184. cval = tsk->signal->it_prof_expires;
  185. cinterval = tsk->signal->it_prof_incr;
  186. if (!cputime_eq(cval, cputime_zero) ||
  187. !cputime_eq(nval, cputime_zero)) {
  188. if (cputime_gt(nval, cputime_zero))
  189. nval = cputime_add(nval,
  190. jiffies_to_cputime(1));
  191. set_process_cpu_timer(tsk, CPUCLOCK_PROF,
  192. &nval, &cval);
  193. }
  194. tsk->signal->it_prof_expires = nval;
  195. tsk->signal->it_prof_incr = ninterval;
  196. spin_unlock_irq(&tsk->sighand->siglock);
  197. read_unlock(&tasklist_lock);
  198. if (ovalue) {
  199. cputime_to_timeval(cval, &ovalue->it_value);
  200. cputime_to_timeval(cinterval, &ovalue->it_interval);
  201. }
  202. break;
  203. default:
  204. return -EINVAL;
  205. }
  206. return 0;
  207. }
  208. asmlinkage long sys_setitimer(int which,
  209. struct itimerval __user *value,
  210. struct itimerval __user *ovalue)
  211. {
  212. struct itimerval set_buffer, get_buffer;
  213. int error;
  214. if (value) {
  215. if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
  216. return -EFAULT;
  217. } else
  218. memset((char *) &set_buffer, 0, sizeof(set_buffer));
  219. error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
  220. if (error || !ovalue)
  221. return error;
  222. if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
  223. return -EFAULT;
  224. return 0;
  225. }