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