linux_time.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /* $OpenBSD: linux_time.c,v 1.5 2013/10/25 04:51:39 guenther Exp $ */
  2. /*
  3. * Copyright (c) 2010, 2011 Paul Irofti <pirofti@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/ucred.h>
  19. #include <sys/mount.h>
  20. #include <sys/signal.h>
  21. #include <sys/stdint.h>
  22. #include <sys/time.h>
  23. #include <sys/systm.h>
  24. #include <sys/proc.h>
  25. #include <sys/kernel.h>
  26. #include <sys/syscallargs.h>
  27. #include <compat/linux/linux_types.h>
  28. #include <compat/linux/linux_fcntl.h>
  29. #include <compat/linux/linux_misc.h>
  30. #include <compat/linux/linux_mmap.h>
  31. #include <compat/linux/linux_sched.h>
  32. #include <compat/linux/linux_signal.h>
  33. #include <compat/linux/linux_syscallargs.h>
  34. #include <compat/linux/linux_util.h>
  35. #include <compat/linux/linux_dirent.h>
  36. #include <compat/linux/linux_emuldata.h>
  37. #include <compat/linux/linux_time.h>
  38. #define LINUX_CLOCK_REALTIME 0
  39. #define LINUX_CLOCK_MONOTONIC 1
  40. #define LINUX_CLOCK_PROCESS_CPUTIME_ID 2
  41. #define LINUX_CLOCK_THREAD_CPUTIME_ID 3
  42. int
  43. bsd_to_linux_timespec(struct linux_timespec *ltp, const struct timespec *ntp)
  44. {
  45. if (ntp->tv_sec > LINUX_TIME_MAX)
  46. return EOVERFLOW;
  47. ltp->tv_sec = ntp->tv_sec;
  48. ltp->tv_nsec = ntp->tv_nsec;
  49. return 0;
  50. }
  51. void
  52. linux_to_bsd_timespec(struct timespec *ntp, const struct linux_timespec *ltp)
  53. {
  54. ntp->tv_sec = ltp->tv_sec;
  55. ntp->tv_nsec = ltp->tv_nsec;
  56. }
  57. int
  58. bsd_to_linux_itimerval(struct linux_itimerval *ltp,
  59. const struct itimerval *ntp)
  60. {
  61. int error;
  62. error = bsd_to_linux_timeval(&ltp->it_interval, &ntp->it_interval);
  63. if (error)
  64. return (error);
  65. return (bsd_to_linux_timeval(&ltp->it_value, &ntp->it_value));
  66. }
  67. void
  68. linux_to_bsd_itimerval(struct itimerval *ntp,
  69. const struct linux_itimerval *ltp)
  70. {
  71. linux_to_bsd_timeval(&ntp->it_interval, &ltp->it_interval);
  72. linux_to_bsd_timeval(&ntp->it_value, &ltp->it_value);
  73. }
  74. int
  75. linux_to_bsd_clockid(clockid_t *n, clockid_t l)
  76. {
  77. switch (l) {
  78. case LINUX_CLOCK_REALTIME:
  79. *n = CLOCK_REALTIME;
  80. break;
  81. case LINUX_CLOCK_MONOTONIC:
  82. *n = CLOCK_MONOTONIC;
  83. break;
  84. case LINUX_CLOCK_PROCESS_CPUTIME_ID:
  85. *n = CLOCK_PROCESS_CPUTIME_ID;
  86. break;
  87. case LINUX_CLOCK_THREAD_CPUTIME_ID:
  88. *n = CLOCK_THREAD_CPUTIME_ID;
  89. break;
  90. default:
  91. return (EINVAL);
  92. break;
  93. }
  94. return (0);
  95. }
  96. int
  97. linux_sys_clock_getres(struct proc *p, void *v, register_t *retval)
  98. {
  99. struct linux_sys_clock_getres_args *uap = v;
  100. struct linux_timespec ltp;
  101. clockid_t clockid;
  102. int error;
  103. if (SCARG(uap, tp) == NULL)
  104. return 0;
  105. error = linux_to_bsd_clockid(&clockid, SCARG(uap, which));
  106. if (error != 0)
  107. return error;
  108. /* ahhh, just give a good guess */
  109. ltp.tv_sec = 0;
  110. ltp.tv_nsec = 1000000000 / hz;
  111. return (copyout(&ltp, SCARG(uap, tp), sizeof ltp));
  112. }
  113. int
  114. linux_sys_clock_gettime(struct proc *p, void *v, register_t *retval)
  115. {
  116. struct linux_sys_clock_gettime_args *uap = v;
  117. struct timespec tp;
  118. struct linux_timespec ltp;
  119. clockid_t clockid;
  120. int error;
  121. error = linux_to_bsd_clockid(&clockid, SCARG(uap, which));
  122. if (error != 0)
  123. return error;
  124. error = clock_gettime(p, clockid, &tp);
  125. if (error != 0)
  126. return error;
  127. error = bsd_to_linux_timespec(&ltp, &tp);
  128. if (error != 0)
  129. return error;
  130. return (copyout(&ltp, SCARG(uap, tp), sizeof ltp));
  131. }
  132. int
  133. linux_sys_nanosleep(struct proc *p, void *v, register_t *retval)
  134. {
  135. static int nanowait;
  136. struct linux_sys_nanosleep_args /* {
  137. syscallarg(const struct linux_timespec *) rqtp;
  138. syscallarg(struct linux_timespec *) rmtp;
  139. } */ *uap = v;
  140. struct linux_timespec lts;
  141. struct timespec rqt, rmt;
  142. struct timespec sts, ets;
  143. struct linux_timespec *rmtp;
  144. struct timeval tv;
  145. int error, error1;
  146. rmtp = SCARG(uap, rmtp);
  147. error = copyin(SCARG(uap, rqtp), &lts, sizeof(lts));
  148. if (error)
  149. return (error);
  150. linux_to_bsd_timespec(&rqt, &lts);
  151. TIMESPEC_TO_TIMEVAL(&tv, &rqt);
  152. if (itimerfix(&tv))
  153. return (EINVAL);
  154. if (rmtp)
  155. getnanouptime(&sts);
  156. error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep",
  157. MAX(1, tvtohz(&tv)));
  158. if (error == ERESTART)
  159. error = EINTR;
  160. if (error == EWOULDBLOCK)
  161. error = 0;
  162. if (rmtp) {
  163. getnanouptime(&ets);
  164. timespecsub(&ets, &sts, &sts);
  165. timespecsub(&rqt, &sts, &rmt);
  166. if (rmt.tv_sec < 0)
  167. timespecclear(&rmt);
  168. if ((error1 = bsd_to_linux_timespec(&lts, &rmt)) ||
  169. (error1 = copyout(&lts, rmtp, sizeof(lts))))
  170. error = error1;
  171. }
  172. return error;
  173. }
  174. int
  175. linux_sys_gettimeofday(struct proc *p, void *v, register_t *retval)
  176. {
  177. struct linux_sys_gettimeofday_args /* {
  178. syscallarg(struct linux_timeval *) tp;
  179. syscallarg(struct timezone *) tzp;
  180. } */ *uap = v;
  181. struct timeval atv;
  182. struct linux_timeval latv;
  183. struct linux_timeval *tp;
  184. struct timezone *tzp;
  185. int error = 0;
  186. tp = SCARG(uap, tp);
  187. tzp = SCARG(uap, tzp);
  188. if (tp) {
  189. microtime(&atv);
  190. if ((error = bsd_to_linux_timeval(&latv, &atv)) ||
  191. (error = copyout(&latv, tp, sizeof (latv))))
  192. return (error);
  193. }
  194. if (tzp)
  195. error = copyout(&tz, tzp, sizeof (tz));
  196. return (error);
  197. }
  198. int
  199. linux_sys_getitimer(struct proc *p, void *v, register_t *retval)
  200. {
  201. struct linux_sys_getitimer_args /* {
  202. syscallarg(int) which;
  203. syscallarg(struct linux_itimerval *) itv;
  204. } */ *uap = v;
  205. struct itimerval aitv;
  206. struct linux_itimerval laitv;
  207. int s, which, error;
  208. which = SCARG(uap, which);
  209. if (which < ITIMER_REAL || which > ITIMER_PROF)
  210. return (EINVAL);
  211. s = splclock();
  212. aitv = p->p_p->ps_timer[which];
  213. if (which == ITIMER_REAL) {
  214. struct timeval now;
  215. getmicrouptime(&now);
  216. /*
  217. * Convert from absolute to relative time in .it_value
  218. * part of real time timer. If time for real time timer
  219. * has passed return 0, else return difference between
  220. * current time and time for the timer to go off.
  221. */
  222. if (timerisset(&aitv.it_value)) {
  223. if (timercmp(&aitv.it_value, &now, <))
  224. timerclear(&aitv.it_value);
  225. else
  226. timersub(&aitv.it_value, &now,
  227. &aitv.it_value);
  228. }
  229. }
  230. splx(s);
  231. if ((error = bsd_to_linux_itimerval(&laitv, &aitv)))
  232. return error;
  233. return (copyout(&laitv, SCARG(uap, itv), sizeof(laitv)));
  234. }
  235. int
  236. linux_sys_setitimer(struct proc *p, void *v, register_t *retval)
  237. {
  238. struct linux_sys_setitimer_args /* {
  239. syscallarg(int) which;
  240. syscallarg(const struct linux_itimerval *) itv;
  241. syscallarg(struct linux_itimerval *) oitv;
  242. } */ *uap = v;
  243. struct linux_sys_getitimer_args getargs;
  244. struct itimerval aitv;
  245. struct linux_itimerval laitv;
  246. const struct linux_itimerval *itvp;
  247. struct linux_itimerval *oitv;
  248. struct process *pr = p->p_p;
  249. int error;
  250. int timo;
  251. int which;
  252. which = SCARG(uap, which);
  253. itvp = SCARG(uap, itv);
  254. oitv = SCARG(uap, oitv);
  255. if (which < ITIMER_REAL || which > ITIMER_PROF)
  256. return (EINVAL);
  257. if (itvp && (error = copyin(itvp, &laitv, sizeof(laitv))))
  258. return (error);
  259. if (oitv != NULL) {
  260. SCARG(&getargs, which) = which;
  261. SCARG(&getargs, itv) = oitv;
  262. if ((error = linux_sys_getitimer(p, &getargs, retval)))
  263. return (error);
  264. }
  265. if (itvp == 0)
  266. return (0);
  267. linux_to_bsd_itimerval(&aitv, &laitv);
  268. if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
  269. return (EINVAL);
  270. if (which == ITIMER_REAL) {
  271. struct timeval ctv;
  272. timeout_del(&pr->ps_realit_to);
  273. getmicrouptime(&ctv);
  274. if (timerisset(&aitv.it_value)) {
  275. timo = tvtohz(&aitv.it_value);
  276. timeout_add(&pr->ps_realit_to, timo);
  277. timeradd(&aitv.it_value, &ctv, &aitv.it_value);
  278. }
  279. pr->ps_timer[ITIMER_REAL] = aitv;
  280. } else {
  281. int s;
  282. itimerround(&aitv.it_interval);
  283. s = splclock();
  284. pr->ps_timer[which] = aitv;
  285. splx(s);
  286. }
  287. return (0);
  288. }