1 /* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5 * 6 * Copyright (c) 2001 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Emmanuel Dreyfus. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 #if 0 37 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/ucred.h> 44 #include <sys/limits.h> 45 #include <sys/mount.h> 46 #include <sys/mutex.h> 47 #include <sys/resourcevar.h> 48 #include <sys/sdt.h> 49 #include <sys/signal.h> 50 #include <sys/stdint.h> 51 #include <sys/syscallsubr.h> 52 #include <sys/sysproto.h> 53 #include <sys/time.h> 54 #include <sys/systm.h> 55 #include <sys/proc.h> 56 57 #ifdef COMPAT_LINUX32 58 #include <machine/../linux32/linux.h> 59 #include <machine/../linux32/linux32_proto.h> 60 #else 61 #include <machine/../linux/linux.h> 62 #include <machine/../linux/linux_proto.h> 63 #endif 64 65 #include <compat/linux/linux_dtrace.h> 66 #include <compat/linux/linux_misc.h> 67 #include <compat/linux/linux_timer.h> 68 #include <compat/linux/linux_util.h> 69 70 /* DTrace init */ 71 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 72 73 /** 74 * DTrace probes in this module. 75 */ 76 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, 77 "clockid_t"); 78 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, 79 "clockid_t"); 80 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_gettime, conversion_error, "int"); 81 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); 82 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); 83 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 84 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, gettime_error, "int"); 85 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, copyout_error, "int"); 86 #endif 87 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); 88 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, settime_error, "int"); 89 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, conversion_error, "int"); 90 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); 91 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 92 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, conversion_error, "int"); 93 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, copyin_error, "int"); 94 #endif 95 LIN_SDT_PROBE_DEFINE0(time, linux_common_clock_getres, nullcall); 96 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, conversion_error, "int"); 97 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, getres_error, "int"); 98 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); 99 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 100 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres_time64, copyout_error, "int"); 101 #endif 102 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); 103 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); 104 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); 105 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); 106 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_flags, "int"); 107 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_clockid, "int"); 108 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 109 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyout_error, "int"); 110 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyin_error, "int"); 111 #endif 112 113 static int linux_common_clock_gettime(struct thread *, clockid_t, 114 struct timespec *); 115 static int linux_common_clock_settime(struct thread *, clockid_t, 116 struct timespec *); 117 static int linux_common_clock_getres(struct thread *, clockid_t, 118 struct timespec *); 119 static int linux_common_clock_nanosleep(struct thread *, clockid_t, 120 l_int, struct timespec *, struct timespec *); 121 122 int 123 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) 124 { 125 126 #ifdef COMPAT_LINUX32 127 if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN) 128 return (EOVERFLOW); 129 #endif 130 ltp->tv_sec = ntp->tv_sec; 131 ltp->tv_nsec = ntp->tv_nsec; 132 133 return (0); 134 } 135 136 int 137 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) 138 { 139 140 if (!timespecvalid_interval(ltp)) 141 return (EINVAL); 142 ntp->tv_sec = ltp->tv_sec; 143 ntp->tv_nsec = ltp->tv_nsec; 144 145 return (0); 146 } 147 148 int 149 linux_put_timespec(struct timespec *ntp, struct l_timespec *ltp) 150 { 151 struct l_timespec lts; 152 int error; 153 154 error = native_to_linux_timespec(<s, ntp); 155 if (error != 0) 156 return (error); 157 return (copyout(<s, ltp, sizeof(lts))); 158 } 159 160 int 161 linux_get_timespec(struct timespec *ntp, const struct l_timespec *ultp) 162 { 163 struct l_timespec lts; 164 int error; 165 166 error = copyin(ultp, <s, sizeof(lts)); 167 if (error != 0) 168 return (error); 169 return (linux_to_native_timespec(ntp, <s)); 170 } 171 172 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 173 int 174 native_to_linux_timespec64(struct l_timespec64 *ltp64, struct timespec *ntp) 175 { 176 177 ltp64->tv_sec = ntp->tv_sec; 178 ltp64->tv_nsec = ntp->tv_nsec; 179 180 return (0); 181 } 182 183 int 184 linux_to_native_timespec64(struct timespec *ntp, struct l_timespec64 *ltp64) 185 { 186 187 #if defined(__i386__) 188 /* i386 time_t is still 32-bit */ 189 if (ltp64->tv_sec > INT_MAX || ltp64->tv_sec < INT_MIN) 190 return (EOVERFLOW); 191 #endif 192 /* Zero out the padding in compat mode. */ 193 ntp->tv_nsec = ltp64->tv_nsec & 0xFFFFFFFFUL; 194 ntp->tv_sec = ltp64->tv_sec; 195 196 if (!timespecvalid_interval(ntp)) 197 return (EINVAL); 198 199 return (0); 200 } 201 202 int 203 linux_put_timespec64(struct timespec *ntp, struct l_timespec64 *ltp) 204 { 205 struct l_timespec64 lts; 206 int error; 207 208 error = native_to_linux_timespec64(<s, ntp); 209 if (error != 0) 210 return (error); 211 return (copyout(<s, ltp, sizeof(lts))); 212 } 213 214 int 215 linux_get_timespec64(struct timespec *ntp, const struct l_timespec64 *ultp) 216 { 217 struct l_timespec64 lts; 218 int error; 219 220 error = copyin(ultp, <s, sizeof(lts)); 221 if (error != 0) 222 return (error); 223 return (linux_to_native_timespec64(ntp, <s)); 224 } 225 #endif 226 227 int 228 native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp) 229 { 230 int error; 231 232 error = native_to_linux_timespec(<p->it_interval, &ntp->it_interval); 233 if (error == 0) 234 error = native_to_linux_timespec(<p->it_value, &ntp->it_value); 235 return (error); 236 } 237 238 int 239 linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp) 240 { 241 int error; 242 243 error = linux_to_native_timespec(&ntp->it_interval, <p->it_interval); 244 if (error == 0) 245 error = linux_to_native_timespec(&ntp->it_value, <p->it_value); 246 return (error); 247 } 248 249 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 250 int 251 linux_to_native_itimerspec64(struct itimerspec *ntp, struct l_itimerspec64 *ltp) 252 { 253 int error; 254 255 error = linux_to_native_timespec64(&ntp->it_interval, <p->it_interval); 256 if (error == 0) 257 error = linux_to_native_timespec64(&ntp->it_value, <p->it_value); 258 return (error); 259 } 260 261 int 262 native_to_linux_itimerspec64(struct l_itimerspec64 *ltp, struct itimerspec *ntp) 263 { 264 int error; 265 266 error = native_to_linux_timespec64(<p->it_interval, &ntp->it_interval); 267 if (error == 0) 268 error = native_to_linux_timespec64(<p->it_value, &ntp->it_value); 269 return (error); 270 } 271 #endif 272 273 int 274 linux_to_native_clockid(clockid_t *n, clockid_t l) 275 { 276 277 if (l < 0) { 278 /* cpu-clock */ 279 if (LINUX_CPUCLOCK_WHICH(l) == LINUX_CLOCKFD) { 280 LIN_SDT_PROBE1(time, linux_to_native_clockid, 281 unsupported_clockid, l); 282 return (ENOTSUP); 283 } 284 if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD_MASK) 285 return (EINVAL); 286 287 if (LINUX_CPUCLOCK_PERTHREAD(l)) 288 *n = CLOCK_THREAD_CPUTIME_ID; 289 else 290 *n = CLOCK_PROCESS_CPUTIME_ID; 291 return (0); 292 } 293 294 switch (l) { 295 case LINUX_CLOCK_REALTIME: 296 *n = CLOCK_REALTIME; 297 break; 298 case LINUX_CLOCK_MONOTONIC: 299 *n = CLOCK_MONOTONIC; 300 break; 301 case LINUX_CLOCK_PROCESS_CPUTIME_ID: 302 *n = CLOCK_PROCESS_CPUTIME_ID; 303 break; 304 case LINUX_CLOCK_THREAD_CPUTIME_ID: 305 *n = CLOCK_THREAD_CPUTIME_ID; 306 break; 307 case LINUX_CLOCK_REALTIME_COARSE: 308 *n = CLOCK_REALTIME_FAST; 309 break; 310 case LINUX_CLOCK_MONOTONIC_COARSE: 311 case LINUX_CLOCK_MONOTONIC_RAW: 312 *n = CLOCK_MONOTONIC_FAST; 313 break; 314 case LINUX_CLOCK_BOOTTIME: 315 *n = CLOCK_UPTIME; 316 break; 317 case LINUX_CLOCK_REALTIME_ALARM: 318 case LINUX_CLOCK_BOOTTIME_ALARM: 319 case LINUX_CLOCK_SGI_CYCLE: 320 case LINUX_CLOCK_TAI: 321 LIN_SDT_PROBE1(time, linux_to_native_clockid, 322 unsupported_clockid, l); 323 return (ENOTSUP); 324 default: 325 LIN_SDT_PROBE1(time, linux_to_native_clockid, 326 unknown_clockid, l); 327 return (ENOTSUP); 328 } 329 330 return (0); 331 } 332 333 int 334 linux_to_native_timerflags(int *nflags, int flags) 335 { 336 337 if (flags & ~LINUX_TIMER_ABSTIME) 338 return (EINVAL); 339 *nflags = 0; 340 if (flags & LINUX_TIMER_ABSTIME) 341 *nflags |= TIMER_ABSTIME; 342 return (0); 343 } 344 345 static int 346 linux_common_clock_gettime(struct thread *td, clockid_t which, 347 struct timespec *tp) 348 { 349 struct rusage ru; 350 struct thread *targettd; 351 struct proc *p; 352 int error, clockwhich; 353 clockid_t nwhich; 354 pid_t pid; 355 lwpid_t tid; 356 357 error = linux_to_native_clockid(&nwhich, which); 358 if (error != 0) { 359 linux_msg(curthread, 360 "unsupported clock_gettime clockid %d", which); 361 LIN_SDT_PROBE1(time, linux_common_clock_gettime, 362 conversion_error, error); 363 return (error); 364 } 365 366 switch (nwhich) { 367 case CLOCK_PROCESS_CPUTIME_ID: 368 if (which < 0) { 369 clockwhich = LINUX_CPUCLOCK_WHICH(which); 370 pid = LINUX_CPUCLOCK_ID(which); 371 } else { 372 clockwhich = LINUX_CPUCLOCK_SCHED; 373 pid = 0; 374 } 375 if (pid == 0) { 376 p = td->td_proc; 377 PROC_LOCK(p); 378 } else { 379 error = pget(pid, PGET_CANSEE, &p); 380 if (error != 0) 381 return (EINVAL); 382 } 383 switch (clockwhich) { 384 case LINUX_CPUCLOCK_PROF: 385 PROC_STATLOCK(p); 386 calcru(p, &ru.ru_utime, &ru.ru_stime); 387 PROC_STATUNLOCK(p); 388 PROC_UNLOCK(p); 389 timevaladd(&ru.ru_utime, &ru.ru_stime); 390 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 391 break; 392 case LINUX_CPUCLOCK_VIRT: 393 PROC_STATLOCK(p); 394 calcru(p, &ru.ru_utime, &ru.ru_stime); 395 PROC_STATUNLOCK(p); 396 PROC_UNLOCK(p); 397 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 398 break; 399 case LINUX_CPUCLOCK_SCHED: 400 kern_process_cputime(p, tp); 401 PROC_UNLOCK(p); 402 break; 403 default: 404 PROC_UNLOCK(p); 405 return (EINVAL); 406 } 407 408 break; 409 410 case CLOCK_THREAD_CPUTIME_ID: 411 if (which < 0) { 412 clockwhich = LINUX_CPUCLOCK_WHICH(which); 413 tid = LINUX_CPUCLOCK_ID(which); 414 } else { 415 clockwhich = LINUX_CPUCLOCK_SCHED; 416 tid = 0; 417 } 418 p = td->td_proc; 419 if (tid == 0) { 420 targettd = td; 421 PROC_LOCK(p); 422 } else { 423 targettd = linux_tdfind(td, tid, p->p_pid); 424 if (targettd == NULL) 425 return (EINVAL); 426 } 427 switch (clockwhich) { 428 case LINUX_CPUCLOCK_PROF: 429 PROC_STATLOCK(p); 430 thread_lock(targettd); 431 rufetchtd(targettd, &ru); 432 thread_unlock(targettd); 433 PROC_STATUNLOCK(p); 434 PROC_UNLOCK(p); 435 timevaladd(&ru.ru_utime, &ru.ru_stime); 436 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 437 break; 438 case LINUX_CPUCLOCK_VIRT: 439 PROC_STATLOCK(p); 440 thread_lock(targettd); 441 rufetchtd(targettd, &ru); 442 thread_unlock(targettd); 443 PROC_STATUNLOCK(p); 444 PROC_UNLOCK(p); 445 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 446 break; 447 case LINUX_CPUCLOCK_SCHED: 448 if (td == targettd) 449 targettd = NULL; 450 kern_thread_cputime(targettd, tp); 451 PROC_UNLOCK(p); 452 break; 453 default: 454 PROC_UNLOCK(p); 455 return (EINVAL); 456 } 457 break; 458 459 default: 460 error = kern_clock_gettime(td, nwhich, tp); 461 break; 462 } 463 464 return (error); 465 } 466 467 int 468 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) 469 { 470 struct timespec tp; 471 int error; 472 473 error = linux_common_clock_gettime(td, args->which, &tp); 474 if (error != 0) { 475 LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); 476 return (error); 477 } 478 error = linux_put_timespec(&tp, args->tp); 479 if (error != 0) 480 LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); 481 482 return (error); 483 } 484 485 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 486 int 487 linux_clock_gettime64(struct thread *td, struct linux_clock_gettime64_args *args) 488 { 489 struct timespec tp; 490 int error; 491 492 error = linux_common_clock_gettime(td, args->which, &tp); 493 if (error != 0) { 494 LIN_SDT_PROBE1(time, linux_clock_gettime64, gettime_error, error); 495 return (error); 496 } 497 error = linux_put_timespec64(&tp, args->tp); 498 if (error != 0) 499 LIN_SDT_PROBE1(time, linux_clock_gettime64, copyout_error, error); 500 501 return (error); 502 } 503 #endif 504 505 static int 506 linux_common_clock_settime(struct thread *td, clockid_t which, 507 struct timespec *ts) 508 { 509 int error; 510 clockid_t nwhich; 511 512 error = linux_to_native_clockid(&nwhich, which); 513 if (error != 0) { 514 linux_msg(curthread, 515 "unsupported clock_settime clockid %d", which); 516 LIN_SDT_PROBE1(time, linux_common_clock_settime, conversion_error, 517 error); 518 return (error); 519 } 520 521 error = kern_clock_settime(td, nwhich, ts); 522 if (error != 0) 523 LIN_SDT_PROBE1(time, linux_common_clock_settime, 524 settime_error, error); 525 526 return (error); 527 } 528 529 int 530 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) 531 { 532 struct timespec ts; 533 int error; 534 535 error = linux_get_timespec(&ts, args->tp); 536 if (error != 0) { 537 LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); 538 return (error); 539 } 540 return (linux_common_clock_settime(td, args->which, &ts)); 541 } 542 543 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 544 int 545 linux_clock_settime64(struct thread *td, struct linux_clock_settime64_args *args) 546 { 547 struct timespec ts; 548 int error; 549 550 error = linux_get_timespec64(&ts, args->tp); 551 if (error != 0) { 552 LIN_SDT_PROBE1(time, linux_clock_settime64, copyin_error, error); 553 return (error); 554 } 555 return (linux_common_clock_settime(td, args->which, &ts)); 556 } 557 #endif 558 559 static int 560 linux_common_clock_getres(struct thread *td, clockid_t which, 561 struct timespec *ts) 562 { 563 struct proc *p; 564 int error, clockwhich; 565 clockid_t nwhich; 566 pid_t pid; 567 lwpid_t tid; 568 569 error = linux_to_native_clockid(&nwhich, which); 570 if (error != 0) { 571 linux_msg(curthread, 572 "unsupported clock_getres clockid %d", which); 573 LIN_SDT_PROBE1(time, linux_common_clock_getres, 574 conversion_error, error); 575 return (error); 576 } 577 578 /* 579 * Check user supplied clock id in case of per-process 580 * or thread-specific cpu-time clock. 581 */ 582 if (which < 0) { 583 switch (nwhich) { 584 case CLOCK_THREAD_CPUTIME_ID: 585 tid = LINUX_CPUCLOCK_ID(which); 586 if (tid != 0) { 587 p = td->td_proc; 588 if (linux_tdfind(td, tid, p->p_pid) == NULL) 589 return (EINVAL); 590 PROC_UNLOCK(p); 591 } 592 break; 593 case CLOCK_PROCESS_CPUTIME_ID: 594 pid = LINUX_CPUCLOCK_ID(which); 595 if (pid != 0) { 596 error = pget(pid, PGET_CANSEE, &p); 597 if (error != 0) 598 return (EINVAL); 599 PROC_UNLOCK(p); 600 } 601 break; 602 } 603 } 604 605 if (ts == NULL) { 606 LIN_SDT_PROBE0(time, linux_common_clock_getres, nullcall); 607 return (0); 608 } 609 610 switch (nwhich) { 611 case CLOCK_THREAD_CPUTIME_ID: 612 case CLOCK_PROCESS_CPUTIME_ID: 613 clockwhich = LINUX_CPUCLOCK_WHICH(which); 614 /* 615 * In both cases (when the clock id obtained by a call to 616 * clock_getcpuclockid() or using the clock 617 * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision 618 * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock. 619 * 620 * See Linux posix_cpu_clock_getres() implementation. 621 */ 622 if (which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) { 623 ts->tv_sec = 0; 624 ts->tv_nsec = 1; 625 goto out; 626 } 627 628 switch (clockwhich) { 629 case LINUX_CPUCLOCK_PROF: 630 nwhich = CLOCK_PROF; 631 break; 632 case LINUX_CPUCLOCK_VIRT: 633 nwhich = CLOCK_VIRTUAL; 634 break; 635 default: 636 return (EINVAL); 637 } 638 break; 639 640 default: 641 break; 642 } 643 error = kern_clock_getres(td, nwhich, ts); 644 if (error != 0) { 645 LIN_SDT_PROBE1(time, linux_common_clock_getres, 646 getres_error, error); 647 return (error); 648 } 649 650 out: 651 return (error); 652 } 653 654 int 655 linux_clock_getres(struct thread *td, 656 struct linux_clock_getres_args *args) 657 { 658 struct timespec ts; 659 int error; 660 661 error = linux_common_clock_getres(td, args->which, &ts); 662 if (error != 0 || args->tp == NULL) 663 return (error); 664 error = linux_put_timespec(&ts, args->tp); 665 if (error != 0) 666 LIN_SDT_PROBE1(time, linux_clock_getres, 667 copyout_error, error); 668 return (error); 669 } 670 671 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 672 int 673 linux_clock_getres_time64(struct thread *td, 674 struct linux_clock_getres_time64_args *args) 675 { 676 struct timespec ts; 677 int error; 678 679 error = linux_common_clock_getres(td, args->which, &ts); 680 if (error != 0 || args->tp == NULL) 681 return (error); 682 error = linux_put_timespec64(&ts, args->tp); 683 if (error != 0) 684 LIN_SDT_PROBE1(time, linux_clock_getres_time64, 685 copyout_error, error); 686 return (error); 687 } 688 #endif 689 690 int 691 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) 692 { 693 struct timespec *rmtp; 694 struct timespec rqts, rmts; 695 int error, error2; 696 697 error = linux_get_timespec(&rqts, args->rqtp); 698 if (error != 0) { 699 LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); 700 return (error); 701 } 702 if (args->rmtp != NULL) 703 rmtp = &rmts; 704 else 705 rmtp = NULL; 706 707 error = kern_nanosleep(td, &rqts, rmtp); 708 if (error == EINTR && args->rmtp != NULL) { 709 error2 = linux_put_timespec(rmtp, args->rmtp); 710 if (error2 != 0) { 711 LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, 712 error2); 713 return (error2); 714 } 715 } 716 717 return (error); 718 } 719 720 static int 721 linux_common_clock_nanosleep(struct thread *td, clockid_t which, 722 l_int lflags, struct timespec *rqtp, struct timespec *rmtp) 723 { 724 int error, flags; 725 clockid_t clockid; 726 727 error = linux_to_native_timerflags(&flags, lflags); 728 if (error != 0) { 729 LIN_SDT_PROBE1(time, linux_common_clock_nanosleep, 730 unsupported_flags, lflags); 731 return (error); 732 } 733 734 error = linux_to_native_clockid(&clockid, which); 735 if (error != 0) { 736 linux_msg(curthread, 737 "unsupported clock_nanosleep clockid %d", which); 738 LIN_SDT_PROBE1(time, linux_common_clock_nanosleep, 739 unsupported_clockid, which); 740 return (error); 741 } 742 if (clockid == CLOCK_THREAD_CPUTIME_ID) 743 return (ENOTSUP); 744 745 return (kern_clock_nanosleep(td, clockid, flags, rqtp, rmtp)); 746 } 747 748 int 749 linux_clock_nanosleep(struct thread *td, 750 struct linux_clock_nanosleep_args *args) 751 { 752 struct timespec *rmtp; 753 struct timespec rqts, rmts; 754 int error, error2; 755 756 error = linux_get_timespec(&rqts, args->rqtp); 757 if (error != 0) { 758 LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, 759 error); 760 return (error); 761 } 762 if (args->rmtp != NULL) 763 rmtp = &rmts; 764 else 765 rmtp = NULL; 766 767 error = linux_common_clock_nanosleep(td, args->which, args->flags, 768 &rqts, rmtp); 769 if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 && 770 args->rmtp != NULL) { 771 error2 = linux_put_timespec(rmtp, args->rmtp); 772 if (error2 != 0) { 773 LIN_SDT_PROBE1(time, linux_clock_nanosleep, 774 copyout_error, error2); 775 return (error2); 776 } 777 } 778 return (error); 779 } 780 781 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 782 int 783 linux_clock_nanosleep_time64(struct thread *td, 784 struct linux_clock_nanosleep_time64_args *args) 785 { 786 struct timespec *rmtp; 787 struct timespec rqts, rmts; 788 int error, error2; 789 790 error = linux_get_timespec64(&rqts, args->rqtp); 791 if (error != 0) { 792 LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64, 793 copyin_error, error); 794 return (error); 795 } 796 if (args->rmtp != NULL) 797 rmtp = &rmts; 798 else 799 rmtp = NULL; 800 801 error = linux_common_clock_nanosleep(td, args->which, args->flags, 802 &rqts, rmtp); 803 if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 && 804 args->rmtp != NULL) { 805 error2 = linux_put_timespec64(rmtp, args->rmtp); 806 if (error2 != 0) { 807 LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64, 808 copyout_error, error2); 809 return (error2); 810 } 811 } 812 return (error); 813 } 814 #endif 815