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