introduce the hrtimer_nanosleep() and hrtimer_nanosleep_real() APIs. Not yet used by any code.
Showing the changes to kernel/hrtimer.c (1 of 2 files). Show all
Unified · Split
| @@ -580,6 +580,133 @@ void hrtimer_run_queues(void) · 579 unmodified lines | ||
| 580 | 580 | run_hrtimer_queue(&base[i]); |
| 581 | 581 | } |
| 582 | 582 | |
| 583 | +/* | |
| 584 | + * Sleep related functions: | |
| 585 | + */ | |
| 586 | + | |
| 587 | +/** | |
| 588 | + * schedule_hrtimer - sleep until timeout | |
| 589 | + * | |
| 590 | + * @timer: hrtimer variable initialized with the correct clock base | |
| 591 | + * @mode: timeout value is abs/rel | |
| 592 | + * | |
| 593 | + * Make the current task sleep until @timeout is | |
| 594 | + * elapsed. | |
| 595 | + * | |
| 596 | + * You can set the task state as follows - | |
| 597 | + * | |
| 598 | + * %TASK_UNINTERRUPTIBLE - at least @timeout is guaranteed to | |
| 599 | + * pass before the routine returns. The routine will return 0 | |
| 600 | + * | |
| 601 | + * %TASK_INTERRUPTIBLE - the routine may return early if a signal is | |
| 602 | + * delivered to the current task. In this case the remaining time | |
| 603 | + * will be returned | |
| 604 | + * | |
| 605 | + * The current task state is guaranteed to be TASK_RUNNING when this | |
| 606 | + * routine returns. | |
| 607 | + */ | |
| 608 | +static ktime_t __sched | |
| 609 | +schedule_hrtimer(struct hrtimer *timer, const enum hrtimer_mode mode) | |
| 610 | +{ | |
| 611 | + /* fn stays NULL, meaning single-shot wakeup: */ | |
| 612 | + timer->data = current; | |
| 613 | + | |
| 614 | + hrtimer_start(timer, timer->expires, mode); | |
| 615 | + | |
| 616 | + schedule(); | |
| 617 | + hrtimer_cancel(timer); | |
| 618 | + | |
| 619 | + /* Return the remaining time: */ | |
| 620 | + if (timer->state != HRTIMER_EXPIRED) | |
| 621 | + return ktime_sub(timer->expires, timer->base->get_time()); | |
| 622 | + else | |
| 623 | + return (ktime_t) {.tv64 = 0 }; | |
| 624 | +} | |
| 625 | + | |
| 626 | +static inline ktime_t __sched | |
| 627 | +schedule_hrtimer_interruptible(struct hrtimer *timer, | |
| 628 | + const enum hrtimer_mode mode) | |
| 629 | +{ | |
| 630 | + set_current_state(TASK_INTERRUPTIBLE); | |
| 631 | + | |
| 632 | + return schedule_hrtimer(timer, mode); | |
| 633 | +} | |
| 634 | + | |
| 635 | +static long __sched | |
| 636 | +nanosleep_restart(struct restart_block *restart, clockid_t clockid) | |
| 637 | +{ | |
| 638 | + struct timespec __user *rmtp, tu; | |
| 639 | + void *rfn_save = restart->fn; | |
| 640 | + struct hrtimer timer; | |
| 641 | + ktime_t rem; | |
| 642 | + | |
| 643 | + restart->fn = do_no_restart_syscall; | |
| 644 | + | |
| 645 | + hrtimer_init(&timer, clockid); | |
| 646 | + | |
| 647 | + timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; | |
| 648 | + | |
| 649 | + rem = schedule_hrtimer_interruptible(&timer, HRTIMER_ABS); | |
| 650 | + | |
| 651 | + if (rem.tv64 <= 0) | |
| 652 | + return 0; | |
| 653 | + | |
| 654 | + rmtp = (struct timespec __user *) restart->arg2; | |
| 655 | + tu = ktime_to_timespec(rem); | |
| 656 | + if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu))) | |
| 657 | + return -EFAULT; | |
| 658 | + | |
| 659 | + restart->fn = rfn_save; | |
| 660 | + | |
| 661 | + /* The other values in restart are already filled in */ | |
| 662 | + return -ERESTART_RESTARTBLOCK; | |
| 663 | +} | |
| 664 | + | |
| 665 | +static long __sched nanosleep_restart_mono(struct restart_block *restart) | |
| 666 | +{ | |
| 667 | + return nanosleep_restart(restart, CLOCK_MONOTONIC); | |
| 668 | +} | |
| 669 | + | |
| 670 | +static long __sched nanosleep_restart_real(struct restart_block *restart) | |
| 671 | +{ | |
| 672 | + return nanosleep_restart(restart, CLOCK_REALTIME); | |
| 673 | +} | |
| 674 | + | |
| 675 | +long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |
| 676 | + const enum hrtimer_mode mode, const clockid_t clockid) | |
| 677 | +{ | |
| 678 | + struct restart_block *restart; | |
| 679 | + struct hrtimer timer; | |
| 680 | + struct timespec tu; | |
| 681 | + ktime_t rem; | |
| 682 | + | |
| 683 | + hrtimer_init(&timer, clockid); | |
| 684 | + | |
| 685 | + timer.expires = timespec_to_ktime(*rqtp); | |
| 686 | + | |
| 687 | + rem = schedule_hrtimer_interruptible(&timer, mode); | |
| 688 | + if (rem.tv64 <= 0) | |
| 689 | + return 0; | |
| 690 | + | |
| 691 | + /* Absolute timers do not update the rmtp value: */ | |
| 692 | + if (mode == HRTIMER_ABS) | |
| 693 | + return -ERESTARTNOHAND; | |
| 694 | + | |
| 695 | + tu = ktime_to_timespec(rem); | |
| 696 | + | |
| 697 | + if (rmtp && copy_to_user(rmtp, &tu, sizeof(tu))) | |
| 698 | + return -EFAULT; | |
| 699 | + | |
| 700 | + restart = ¤t_thread_info()->restart_block; | |
| 701 | + restart->fn = (clockid == CLOCK_MONOTONIC) ? | |
| 702 | + nanosleep_restart_mono : nanosleep_restart_real; | |
| 703 | + restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF; | |
| 704 | + restart->arg1 = timer.expires.tv64 >> 32; | |
| 705 | + restart->arg2 = (unsigned long) rmtp; | |
| 706 | + | |
| 707 | + return -ERESTART_RESTARTBLOCK; | |
| 708 | +} | |
| 709 | + | |
| 583 | 710 | /* |
| 584 | 711 | * Functions related to boot-time initialization: |
| 585 | 712 | */ |