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