itimer.c 6.5 KB

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