1/* Copyright (C) 2003-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18#include <time.h>
19#include <kernel-features.h>
20#include <errno.h>
21
22#include <sysdep-cancel.h>
23#include "kernel-posix-cpu-timers.h"
24
25#include <shlib-compat.h>
26
27/* We can simply use the syscall. The CPU clocks are not supported
28 with this function. */
29int
30__clock_nanosleep_time64 (clockid_t clock_id, int flags, const struct __timespec64 *req,
31 struct __timespec64 *rem)
32{
33 int r;
34
35 if (clock_id == CLOCK_THREAD_CPUTIME_ID)
36 return EINVAL;
37 if (clock_id == CLOCK_PROCESS_CPUTIME_ID)
38 clock_id = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED);
39
40 /* If the call is interrupted by a signal handler or encounters an error,
41 it returns a positive value similar to errno. */
42 INTERNAL_SYSCALL_DECL (err);
43
44#ifdef __ASSUME_TIME64_SYSCALLS
45# ifndef __NR_clock_nanosleep_time64
46# define __NR_clock_nanosleep_time64 __NR_clock_nanosleep
47# endif
48 r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, err, clock_id,
49 flags, req, rem);
50#else
51# ifdef __NR_clock_nanosleep_time64
52 r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, err, clock_id,
53 flags, req, rem);
54
55 if (! INTERNAL_SYSCALL_ERROR_P (r, err))
56 return 0;
57 if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS)
58 return INTERNAL_SYSCALL_ERRNO (r, err);
59# endif /* __NR_clock_nanosleep_time64 */
60
61 if (! in_time_t_range (req->tv_sec))
62 {
63 __set_errno (EOVERFLOW);
64 return -1;
65 }
66
67 struct timespec tr32;
68 struct timespec ts32 = valid_timespec64_to_timespec (*req);
69 r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep, err, clock_id, flags,
70 &ts32, &tr32);
71 if (INTERNAL_SYSCALL_ERROR_P (r, err))
72 {
73 if (INTERNAL_SYSCALL_ERRNO (r, err) == EINTR && rem != NULL
74 && (flags & TIMER_ABSTIME) == 0)
75 *rem = valid_timespec_to_timespec64 (tr32);
76 }
77#endif /* __ASSUME_TIME64_SYSCALLS */
78
79 return (INTERNAL_SYSCALL_ERROR_P (r, err)
80 ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
81}
82
83#if __TIMESIZE != 64
84int
85__clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
86 struct timespec *rem)
87{
88 int r;
89 struct __timespec64 treq64, trem64;
90
91 treq64 = valid_timespec_to_timespec64 (*req);
92 r = __clock_nanosleep_time64 (clock_id, flags, &treq64, &trem64);
93
94 if (r == EINTR && rem != NULL && (flags & TIMER_ABSTIME) == 0)
95 *rem = valid_timespec64_to_timespec (trem64);
96
97 return r;
98}
99#endif
100libc_hidden_def (__clock_nanosleep)
101versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17);
102/* clock_nanosleep moved to libc in version 2.17;
103 old binaries may expect the symbol version it had in librt. */
104#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
105strong_alias (__clock_nanosleep, __clock_nanosleep_2);
106compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2);
107#endif
108