Since Linux 4.18, there's an option CONFIG_COMPAT_32BIT_TIME that allows to ultimately test libc and userland programs if they are using the latest available syscall variants, time64 variants in particular. With this option turned off, old time32 syscalls don't get compiled at all. The same applies to some deprecated syscalls such as nanosleep. Unfortunately, on 32-bit systems Musl fails on this hardly with at least non-working sleeps, signal and sockets. That's because Musl currently uses time64 variants only as "fallbacks" when some of the arguments exceeds 32-bit width. Moreover, Musl currently prefers deprecated adjtimex over clock_adjtime, ipc over semtimedop, nanosleep over clock_nanosleep etc. As for me, libc should always use the latest available syscalls, especially when it comes to y2038, and get back to fallbacks only in case of -ENOSYS (on older systems). Newer systems might just don't get deprecated stuff compiled in, as it is with mentioned Kconfig option. BTW, code size savings from excluding deprecated syscalls are quite nice (bloat-o-meter): add/remove: 0/39 grow/shrink: 8/4 up/down: 3464/-10480 (-7016) Function old new delta sys_timerfd_settime 180 1604 +1424 sys_rt_sigtimedwait 236 884 +648 sys_timerfd_gettime 116 724 +608 sys_pselect6 128 356 +228 sys_timer_settime 256 472 +216 sys_timer_gettime 116 268 +152 sys_sched_rr_get_interval 108 260 +152 do_nanosleep.constprop 424 460 +36 sys_futimesat_time32 8 - -8 sys_clock_adjtime32 8 - -8 sys_adjtimex_time32 8 - -8 sys_utimes_time32 16 - -16 nanosleep_copyout 104 76 -28 poll_select_finish 600 564 -36 sock_gettstamp 524 480 -44 ksys_ipc 828 784 -44 sys_time32 80 - -80 put_old_itimerspec32 80 - -80 sys_sched_rr_get_interval_time32 108 - -108 sys_timerfd_gettime32 116 - -116 sys_timer_gettime32 116 - -116 __put_old_timespec32 124 - -124 sys_pselect6_time32 128 - -128 __do_sys_adjtimex_time32 144 - -144 sys_stime32 164 - -164 sys_timerfd_settime32 180 - -180 compat_ksys_semtimedop 188 - -188 sys_utime32 196 - -196 get_old_itimerspec32 204 - -204 sys_utimensat_time32 216 - -216 sys_clock_gettime32 224 - -224 sys_clock_getres_time32 232 - -232 sys_rt_sigtimedwait_time32 236 - -236 sys_clock_settime32 236 - -236 sys_ppoll_time32 244 - -244 do_timer_gettime 252 - -252 sys_timer_settime32 256 - -256 sys_recvmmsg_time32 256 - -256 sched_rr_get_interval 256 - -256 __do_sys_clock_adjtime32 260 - -260 sys_nanosleep_time32 276 - -276 do_compat_futimesat 300 - -300 put_old_timex32 316 - -316 do_pselect 316 - -316 do_timer_settime.part 320 - -320 sys_clock_nanosleep_time32 340 - -340 sys_futex_time32 480 - -480 get_old_timex32 480 - -480 do_sigtimedwait 696 - -696 do_timerfd_gettime 708 - -708 do_timerfd_settime 1560 - -1560 Total: Before=4538992, After=4531976, chg -0.15% This set ensures that all 18 syscalls are being run as follows: 1. time64 variant. 2. -ENOSYS? time32 variant. 3. -ENOSYS again? Any old stuff (adjtimex, ipc, nanosleep). With this set, all syscalls and userspace programs work as expected with CONFIG_COMPAT_32BIT_TIME turned off, just by using time64 variants. Tested on MIPS32R2 (OABI), Linux 5.11-rc1 (pre) + Musl latest git snapshot. Alexander Lobakin (18): clock_gettime: prefer time64 variant if available clock_settime: prefer time64 variant if available clock_adjtime: try adjtimex at last clock_getres: use time64 variant by default clock_nanosleep: prefer time64 variant if available timer_gettime: prefer time64 variant if available timer_settime: prefer time64 variant if available timerfd_gettime: prefer time64 variant if available timerfd_settime: prefer time64 variant if available utimensat: prefer time64 variant if available pselect, select: prefer time64 variant of pselect6 if available poll, ppoll: prefer time64 variant of ppoll if available mq_timedsend: prefer time64 variant if available mq_timedreceive: prefer time64 variant if available semtimedop: prefer time64 variant of semtimedop if available [rt_]sigtimedwait: prefer time64 variant if available futex: prefer time64 variant if available sched_rr_get_interval: use time64 variant if available src/internal/pthread_impl.h | 22 +++++++++++++++++---- src/ipc/semtimedop.c | 20 +++++++++---------- src/linux/clock_adjtime.c | 12 ++++++----- src/linux/ppoll.c | 8 +++----- src/linux/timerfd.c | 11 +++-------- src/mq/mq_timedreceive.c | 6 ++---- src/mq/mq_timedsend.c | 6 ++---- src/sched/sched_rr_get_interval.c | 21 ++++++++++---------- src/select/poll.c | 23 +++++++++++++++++----- src/select/pselect.c | 6 ++---- src/select/select.c | 22 +++++++++++---------- src/signal/sigtimedwait.c | 6 ++---- src/stat/utimensat.c | 6 ++---- src/thread/__timedwait.c | 6 ++---- src/thread/__wait.c | 4 ++-- src/thread/pthread_barrier_wait.c | 6 +++--- src/thread/pthread_cond_timedwait.c | 10 +++++----- src/thread/pthread_mutex_timedlock.c | 8 +++----- src/thread/pthread_mutex_trylock.c | 2 +- src/thread/pthread_mutex_unlock.c | 2 +- src/thread/pthread_mutexattr_setprotocol.c | 2 +- src/time/clock_getres.c | 21 ++++++++++---------- src/time/clock_gettime.c | 4 +--- src/time/clock_nanosleep.c | 22 +++++++++++---------- src/time/clock_settime.c | 6 ++---- src/time/timer_gettime.c | 4 +--- src/time/timer_settime.c | 7 ++----- 27 files changed, 137 insertions(+), 136 deletions(-) -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/time/clock_gettime.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c index 3e1d0975b122..ec8d08c010cf 100644 --- a/src/time/clock_gettime.c +++ b/src/time/clock_gettime.c @@ -73,9 +73,7 @@ int __clock_gettime(clockid_t clk, struct timespec *ts) #endif #ifdef SYS_clock_gettime64 - r = -ENOSYS; - if (sizeof(time_t) > 4) - r = __syscall(SYS_clock_gettime64, clk, ts); + r = __syscall(SYS_clock_gettime64, clk, ts); if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS) return __syscall_ret(r); long ts32[2]; -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/time/clock_settime.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/time/clock_settime.c b/src/time/clock_settime.c index 1004ed152846..b6dbef04fad1 100644 --- a/src/time/clock_settime.c +++ b/src/time/clock_settime.c @@ -9,10 +9,8 @@ int clock_settime(clockid_t clk, const struct timespec *ts) #ifdef SYS_clock_settime64 time_t s = ts->tv_sec; long ns = ts->tv_nsec; - int r = -ENOSYS; - if (SYS_clock_settime == SYS_clock_settime64 || !IS32BIT(s)) - r = __syscall(SYS_clock_settime64, clk, - ((long long[]){s, ns})); + int r = __syscall(SYS_clock_settime64, clk, + ((long long[]){s, ns})); if (SYS_clock_settime == SYS_clock_settime64 || r!=-ENOSYS) return __syscall_ret(r); if (!IS32BIT(s)) -- 2.29.2
Try to use deprecated adjtimex only after clock_adjtime_time64 or clock_adjtime fail with -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/linux/clock_adjtime.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/linux/clock_adjtime.c b/src/linux/clock_adjtime.c index d4d03d24df40..5a21d5625e59 100644 --- a/src/linux/clock_adjtime.c +++ b/src/linux/clock_adjtime.c @@ -114,11 +114,11 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx) .stbcnt = utx->stbcnt, .tai = utx->tai, }; + r = __syscall(SYS_clock_adjtime, clock_id, &ktx); #ifdef SYS_adjtimex - if (clock_id==CLOCK_REALTIME) r = __syscall(SYS_adjtimex, &ktx); - else + if (r == -ENOSYS && clock_id == CLOCK_REALTIME) + r = __syscall(SYS_adjtimex, &ktx); #endif - r = __syscall(SYS_clock_adjtime, clock_id, &ktx); if (r>=0) { utx->modes = ktx.modes; utx->offset = ktx.offset; @@ -144,8 +144,10 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx) } return __syscall_ret(r); } + r = __syscall(SYS_clock_adjtime, clock_id, utx); #ifdef SYS_adjtimex - if (clock_id==CLOCK_REALTIME) return syscall(SYS_adjtimex, utx); + if (r == -ENOSYS && clock_id == CLOCK_REALTIME) + r = __syscall(SYS_adjtimex, utx); #endif - return syscall(SYS_clock_adjtime, clock_id, utx); + return __syscall_ret(r); } -- 2.29.2
Use the new time64 variant as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/time/clock_getres.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/time/clock_getres.c b/src/time/clock_getres.c index 81c6703761d4..eb563509b420 100644 --- a/src/time/clock_getres.c +++ b/src/time/clock_getres.c @@ -4,18 +4,17 @@ int clock_getres(clockid_t clk, struct timespec *ts) { #ifdef SYS_clock_getres_time64 - /* On a 32-bit arch, use the old syscall if it exists. */ - if (SYS_clock_getres != SYS_clock_getres_time64) { - long ts32[2]; - int r = __syscall(SYS_clock_getres, clk, ts32); - if (!r && ts) { - ts->tv_sec = ts32[0]; - ts->tv_nsec = ts32[1]; - } + int r = __syscall(SYS_clock_getres_time64, clk, ts); + if (SYS_clock_getres == SYS_clock_getres_time64 || r != -ENOSYS) return __syscall_ret(r); + long ts32[2]; + r = __syscall(SYS_clock_getres, clk, ts32); + if (!r && ts) { + ts->tv_sec = ts32[0]; + ts->tv_nsec = ts32[1]; } -#endif - /* If reaching this point, it's a 64-bit arch or time64-only - * 32-bit arch and we can get result directly into timespec. */ + return __syscall_ret(r); +#else return syscall(SYS_clock_getres, clk, ts); +#endif } -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Also use deprecated nanosleep only as a last chance. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/time/clock_nanosleep.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/time/clock_nanosleep.c b/src/time/clock_nanosleep.c index e195499cc072..ea090eb8c313 100644 --- a/src/time/clock_nanosleep.c +++ b/src/time/clock_nanosleep.c @@ -11,27 +11,29 @@ int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, stru #ifdef SYS_clock_nanosleep_time64 time_t s = req->tv_sec; long ns = req->tv_nsec; - int r = -ENOSYS; - if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_clock_nanosleep_time64, clk, flags, - ((long long[]){s, ns}), rem); + int r = __syscall_cp(SYS_clock_nanosleep_time64, clk, flags, + ((long long[]){s, ns}), rem); if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || r!=-ENOSYS) return -r; long long extra = s - CLAMP(s); long ts32[2] = { CLAMP(s), ns }; - if (clk == CLOCK_REALTIME && !flags) + r = __syscall_cp(SYS_clock_nanosleep, clk, flags, &ts32, &ts32); +#ifdef SYS_nanosleep + if (r == -ENOSYS && clk == CLOCK_REALTIME && !flags) r = __syscall_cp(SYS_nanosleep, &ts32, &ts32); - else - r = __syscall_cp(SYS_clock_nanosleep, clk, flags, &ts32, &ts32); +#endif if (r==-EINTR && rem && !(flags & TIMER_ABSTIME)) { rem->tv_sec = ts32[0] + extra; rem->tv_nsec = ts32[1]; } return -r; #else - if (clk == CLOCK_REALTIME && !flags) - return -__syscall_cp(SYS_nanosleep, req, rem); - return -__syscall_cp(SYS_clock_nanosleep, clk, flags, req, rem); + int r = __syscall_cp(SYS_clock_nanosleep, clk, flags, req, rem); +#ifdef SYS_nanosleep + if (r == -ENOSYS && clk == CLOCK_REALTIME && !flags) + r = __syscall_cp(SYS_nanosleep, req, rem); +#endif + return -r; #endif } -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/time/timer_gettime.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/time/timer_gettime.c b/src/time/timer_gettime.c index 21c9d32c3fe5..4f197f9a973c 100644 --- a/src/time/timer_gettime.c +++ b/src/time/timer_gettime.c @@ -9,9 +9,7 @@ int timer_gettime(timer_t t, struct itimerspec *val) t = (void *)(uintptr_t)(td->timer_id & INT_MAX); } #ifdef SYS_timer_gettime64 - int r = -ENOSYS; - if (sizeof(time_t) > 4) - r = __syscall(SYS_timer_gettime64, t, val); + int r = __syscall(SYS_timer_gettime64, t, val); if (SYS_timer_gettime == SYS_timer_gettime64 || r!=-ENOSYS) return __syscall_ret(r); long val32[4]; -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/time/timer_settime.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/time/timer_settime.c b/src/time/timer_settime.c index 373f00ced7f2..9a576cd55fbe 100644 --- a/src/time/timer_settime.c +++ b/src/time/timer_settime.c @@ -13,11 +13,8 @@ int timer_settime(timer_t t, int flags, const struct itimerspec *restrict val, s #ifdef SYS_timer_settime64 time_t is = val->it_interval.tv_sec, vs = val->it_value.tv_sec; long ins = val->it_interval.tv_nsec, vns = val->it_value.tv_nsec; - int r = -ENOSYS; - if (SYS_timer_settime == SYS_timer_settime64 - || !IS32BIT(is) || !IS32BIT(vs) || (sizeof(time_t)>4 && old)) - r = __syscall(SYS_timer_settime64, t, flags, - ((long long[]){is, ins, vs, vns}), old); + int r = __syscall(SYS_timer_settime64, t, flags, + ((long long[]){is, ins, vs, vns}), old); if (SYS_timer_settime == SYS_timer_settime64 || r!=-ENOSYS) return __syscall_ret(r); if (!IS32BIT(is) || !IS32BIT(vs)) -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/linux/timerfd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/linux/timerfd.c b/src/linux/timerfd.c index 5bdfaf165691..d26371cc1182 100644 --- a/src/linux/timerfd.c +++ b/src/linux/timerfd.c @@ -40,9 +40,7 @@ int timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itim int timerfd_gettime(int fd, struct itimerspec *cur) { #ifdef SYS_timerfd_gettime64 - int r = -ENOSYS; - if (sizeof(time_t) > 4) - r = __syscall(SYS_timerfd_gettime64, fd, cur); + int r = __syscall(SYS_timerfd_gettime64, fd, cur); if (SYS_timerfd_gettime == SYS_timerfd_gettime64 || r!=-ENOSYS) return __syscall_ret(r); long cur32[4]; -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/linux/timerfd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/linux/timerfd.c b/src/linux/timerfd.c index d26371cc1182..bfaae1daf675 100644 --- a/src/linux/timerfd.c +++ b/src/linux/timerfd.c @@ -14,11 +14,8 @@ int timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itim #ifdef SYS_timerfd_settime64 time_t is = new->it_interval.tv_sec, vs = new->it_value.tv_sec; long ins = new->it_interval.tv_nsec, vns = new->it_value.tv_nsec; - int r = -ENOSYS; - if (SYS_timerfd_settime == SYS_timerfd_settime64 - || !IS32BIT(is) || !IS32BIT(vs) || (sizeof(time_t)>4 && old)) - r = __syscall(SYS_timerfd_settime64, fd, flags, - ((long long[]){is, ins, vs, vns}), old); + int r = __syscall(SYS_timerfd_settime64, fd, flags, + ((long long[]){is, ins, vs, vns}), old); if (SYS_timerfd_settime == SYS_timerfd_settime64 || r!=-ENOSYS) return __syscall_ret(r); if (!IS32BIT(is) || !IS32BIT(vs)) -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/stat/utimensat.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/stat/utimensat.c b/src/stat/utimensat.c index 730723a9ea70..e3fda06faa01 100644 --- a/src/stat/utimensat.c +++ b/src/stat/utimensat.c @@ -13,7 +13,6 @@ int utimensat(int fd, const char *path, const struct timespec times[2], int flag if (times && times[0].tv_nsec==UTIME_NOW && times[1].tv_nsec==UTIME_NOW) times = 0; #ifdef SYS_utimensat_time64 - r = -ENOSYS; time_t s0=0, s1=0; long ns0=0, ns1=0; if (times) { @@ -22,9 +21,8 @@ int utimensat(int fd, const char *path, const struct timespec times[2], int flag if (!NS_SPECIAL(ns0)) s0 = times[0].tv_sec; if (!NS_SPECIAL(ns1)) s1 = times[1].tv_sec; } - if (SYS_utimensat == SYS_utimensat_time64 || !IS32BIT(s0) || !IS32BIT(s1)) - r = __syscall(SYS_utimensat_time64, fd, path, times ? - ((long long[]){s0, ns0, s1, ns1}) : 0, flags); + r = __syscall(SYS_utimensat_time64, fd, path, times ? + ((long long[]){s0, ns0, s1, ns1}) : 0, flags); if (SYS_utimensat == SYS_utimensat_time64 || r!=-ENOSYS) return __syscall_ret(r); if (!IS32BIT(s0) || !IS32BIT(s1)) -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Also use deprecated select only as a last chance. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/select/pselect.c | 6 ++---- src/select/select.c | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/select/pselect.c b/src/select/pselect.c index 54cfb291bba2..f68616a247de 100644 --- a/src/select/pselect.c +++ b/src/select/pselect.c @@ -13,10 +13,8 @@ int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restric time_t s = ts ? ts->tv_sec : 0; long ns = ts ? ts->tv_nsec : 0; #ifdef SYS_pselect6_time64 - int r = -ENOSYS; - if (SYS_pselect6 == SYS_pselect6_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds, - ts ? ((long long[]){s, ns}) : 0, data); + int r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds, + ts ? ((long long[]){s, ns}) : 0, data); if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS) return __syscall_ret(r); s = CLAMP(s); diff --git a/src/select/select.c b/src/select/select.c index 8a7868840304..d2dbb7b08362 100644 --- a/src/select/select.c +++ b/src/select/select.c @@ -13,6 +13,7 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict suseconds_t us = tv ? tv->tv_usec : 0; long ns; const time_t max_time = (1ULL<<8*sizeof(time_t)-1)-1; + int r = -ENOSYS; if (s<0 || us<0) return __syscall_ret(-EINVAL); if (us/1000000 > max_time - s) { @@ -26,19 +27,20 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict } #ifdef SYS_pselect6_time64 - int r = -ENOSYS; - if (SYS_pselect6 == SYS_pselect6_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds, - tv ? ((long long[]){s, ns}) : 0, - ((syscall_arg_t[]){ 0, _NSIG/8 })); + r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds, + tv ? ((long long[]){s, ns}) : 0, + ((syscall_arg_t[]){ 0, _NSIG/8 })); if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS) return __syscall_ret(r); #endif -#ifdef SYS_select - return syscall_cp(SYS_select, n, rfds, wfds, efds, - tv ? ((long[]){s, us}) : 0); -#else - return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, +#ifdef SYS_pselect6 + r = __syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? ((long[]){s, ns}) : 0, ((syscall_arg_t[]){ 0, _NSIG/8 })); #endif +#ifdef SYS_select + if (r == -ENOSYS) + r = __syscall_cp(SYS_select, n, rfds, wfds, efds, + tv ? ((long[]){s, us}) : 0); +#endif + return __syscall_ret(r); } -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Also use ppoll as a default for poll and fallback to poll only at last. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/linux/ppoll.c | 8 +++----- src/select/poll.c | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/linux/ppoll.c b/src/linux/ppoll.c index e614600ab8b7..88a5b91a47b5 100644 --- a/src/linux/ppoll.c +++ b/src/linux/ppoll.c @@ -12,11 +12,9 @@ int ppoll(struct pollfd *fds, nfds_t n, const struct timespec *to, const sigset_ time_t s = to ? to->tv_sec : 0; long ns = to ? to->tv_nsec : 0; #ifdef SYS_ppoll_time64 - int r = -ENOSYS; - if (SYS_ppoll == SYS_ppoll_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_ppoll_time64, fds, n, - to ? ((long long[]){s, ns}) : 0, - mask, _NSIG/8); + int r = __syscall_cp(SYS_ppoll_time64, fds, n, + to ? ((long long[]){s, ns}) : 0, + mask, _NSIG/8); if (SYS_ppoll == SYS_ppoll_time64 || r != -ENOSYS) return __syscall_ret(r); s = CLAMP(s); diff --git a/src/select/poll.c b/src/select/poll.c index c84c8a999ccc..e6b737081939 100644 --- a/src/select/poll.c +++ b/src/select/poll.c @@ -5,11 +5,24 @@ int poll(struct pollfd *fds, nfds_t n, int timeout) { + time_t s = timeout >= 0 ? timeout / 1000 : 0; + long ns = timeout >= 0 ? timeout % 1000 * 1000000 : 0; + int r = -ENOSYS; +#ifdef SYS_ppoll_time64 + int r = __syscall_cp(SYS_ppoll_time64, fds, n, + timeout >= 0 ? ((long long[]){s, ns}) : 0, + 0, _NSIG / 8); + if (SYS_ppoll == SYS_ppoll_time64 || r != -ENOSYS) + return __syscall_ret(r); +#endif +#ifdef SYS_ppoll + r = __syscall_cp(SYS_ppoll, fds, n, + timeout >= 0 ? ((long[]){s, ns}) : 0, + 0, _NSIG / 8); +#endif #ifdef SYS_poll - return syscall_cp(SYS_poll, fds, n, timeout); -#else - return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ? - &((struct timespec){ .tv_sec = timeout/1000, - .tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8); + if (r == -ENOSYS) + r = __syscall_cp(SYS_poll, fds, n, timeout); #endif + return __syscall_ret(r); } -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/mq/mq_timedsend.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mq/mq_timedsend.c b/src/mq/mq_timedsend.c index 56cfcbb833ed..f85d9f7dd07a 100644 --- a/src/mq/mq_timedsend.c +++ b/src/mq/mq_timedsend.c @@ -10,10 +10,8 @@ int mq_timedsend(mqd_t mqd, const char *msg, size_t len, unsigned prio, const st #ifdef SYS_mq_timedsend_time64 time_t s = at ? at->tv_sec : 0; long ns = at ? at->tv_nsec : 0; - long r = -ENOSYS; - if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_mq_timedsend_time64, mqd, msg, len, prio, - at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0); + long r = __syscall_cp(SYS_mq_timedsend_time64, mqd, msg, len, prio, + at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0); if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || r != -ENOSYS) return __syscall_ret(r); return syscall_cp(SYS_mq_timedsend, mqd, msg, len, prio, -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/mq/mq_timedreceive.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mq/mq_timedreceive.c b/src/mq/mq_timedreceive.c index f41b6642f822..f43de195de3f 100644 --- a/src/mq/mq_timedreceive.c +++ b/src/mq/mq_timedreceive.c @@ -10,10 +10,8 @@ ssize_t mq_timedreceive(mqd_t mqd, char *restrict msg, size_t len, unsigned *res #ifdef SYS_mq_timedreceive_time64 time_t s = at ? at->tv_sec : 0; long ns = at ? at->tv_nsec : 0; - long r = -ENOSYS; - if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_mq_timedreceive_time64, mqd, msg, len, prio, - at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0); + long r = __syscall_cp(SYS_mq_timedreceive_time64, mqd, msg, len, prio, + at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0); if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || r != -ENOSYS) return __syscall_ret(r); return syscall_cp(SYS_mq_timedreceive, mqd, msg, len, prio, -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Also use deprecated ipc syscall only as a last chance. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/ipc/semtimedop.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ipc/semtimedop.c b/src/ipc/semtimedop.c index 1632e7b03f38..703bf0cd6f4d 100644 --- a/src/ipc/semtimedop.c +++ b/src/ipc/semtimedop.c @@ -15,21 +15,21 @@ int semtimedop(int id, struct sembuf *buf, size_t n, const struct timespec *ts) { + int r = -ENOSYS; #ifdef SYS_semtimedop_time64 time_t s = ts ? ts->tv_sec : 0; long ns = ts ? ts->tv_nsec : 0; - int r = -ENOSYS; - if (NO_TIME32 || !IS32BIT(s)) - r = __syscall(SYS_semtimedop_time64, id, buf, n, - ts ? ((long long[]){s, ns}) : 0); + r = __syscall(SYS_semtimedop_time64, id, buf, n, + ts ? ((long long[]){s, ns}) : 0); if (NO_TIME32 || r!=-ENOSYS) return __syscall_ret(r); ts = ts ? (void *)(long[]){CLAMP(s), ns} : 0; #endif -#if defined(SYS_ipc) - return syscall(SYS_ipc, IPCOP_semtimedop, id, n, 0, buf, ts); -#elif defined(SYS_semtimedop) - return syscall(SYS_semtimedop, id, buf, n, ts); -#else - return __syscall_ret(-ENOSYS); +#ifdef SYS_semtimedop + r = __syscall(SYS_semtimedop, id, buf, n, ts); +#endif +#ifdef SYS_ipc + if (r == -ENOSYS) + r = __syscall(SYS_ipc, IPCOP_semtimedop, id, n, 0, buf, ts); #endif + return __syscall_ret(r); } -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/signal/sigtimedwait.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/signal/sigtimedwait.c b/src/signal/sigtimedwait.c index 1287174ebafd..603ba912f78f 100644 --- a/src/signal/sigtimedwait.c +++ b/src/signal/sigtimedwait.c @@ -10,10 +10,8 @@ static int do_sigtimedwait(const sigset_t *restrict mask, siginfo_t *restrict si #ifdef SYS_rt_sigtimedwait_time64 time_t s = ts ? ts->tv_sec : 0; long ns = ts ? ts->tv_nsec : 0; - int r = -ENOSYS; - if (SYS_rt_sigtimedwait == SYS_rt_sigtimedwait_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_rt_sigtimedwait_time64, mask, si, - ts ? ((long long[]){s, ns}) : 0, _NSIG/8); + int r = __syscall_cp(SYS_rt_sigtimedwait_time64, mask, si, + ts ? ((long long[]){s, ns}) : 0, _NSIG/8); if (SYS_rt_sigtimedwait == SYS_rt_sigtimedwait_time64 || r!=-ENOSYS) return r; return __syscall_cp(SYS_rt_sigtimedwait, mask, si, -- 2.29.2
Instead of using time64 variant "only when needed", use it as a default and fallback to time32 only on -ENOSYS. This also introduces a new shorthand, __futexcall(), for futex calls without timespec argument. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/internal/pthread_impl.h | 22 ++++++++++++++++++---- src/thread/__timedwait.c | 6 ++---- src/thread/__wait.c | 4 ++-- src/thread/pthread_barrier_wait.c | 6 +++--- src/thread/pthread_cond_timedwait.c | 10 +++++----- src/thread/pthread_mutex_timedlock.c | 8 +++----- src/thread/pthread_mutex_trylock.c | 2 +- src/thread/pthread_mutex_unlock.c | 2 +- src/thread/pthread_mutexattr_setprotocol.c | 2 +- 9 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index de2b9d8b477e..abb2a9a074a0 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -165,18 +165,32 @@ hidden void __unmapself(void *, size_t); hidden int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int); hidden int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int); hidden void __wait(volatile int *, volatile int *, int, int); + +#ifdef SYS_futex_time64 +#define __futexcall(...) ({ \ + int __r = __syscall(SYS_futex_time64, ##__VA_ARGS__); \ + if (!(SYS_futex == SYS_futex_time64 || __r != -ENOSYS)) \ + __r = __syscall(SYS_futex, ##__VA_ARGS__); \ + __r; \ +}) +#else +#define __futexcall(...) ({ \ + __syscall(SYS_futex, ##__VA_ARGS__); \ +}) +#endif + static inline void __wake(volatile void *addr, int cnt, int priv) { if (priv) priv = FUTEX_PRIVATE; if (cnt<0) cnt = INT_MAX; - __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || - __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); + __futexcall(addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || + __futexcall(addr, FUTEX_WAKE, cnt); } static inline void __futexwait(volatile void *addr, int val, int priv) { if (priv) priv = FUTEX_PRIVATE; - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || - __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); + __futexcall(addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || + __futexcall(addr, FUTEX_WAIT, val, 0); } hidden void __acquire_ptc(void); diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c index 666093be9851..38d326834c14 100644 --- a/src/thread/__timedwait.c +++ b/src/thread/__timedwait.c @@ -14,10 +14,8 @@ static int __futex4_cp(volatile void *addr, int op, int val, const struct timesp #ifdef SYS_futex_time64 time_t s = to ? to->tv_sec : 0; long ns = to ? to->tv_nsec : 0; - r = -ENOSYS; - if (SYS_futex == SYS_futex_time64 || !IS32BIT(s)) - r = __syscall_cp(SYS_futex_time64, addr, op, val, - to ? ((long long[]){s, ns}) : 0); + r = __syscall_cp(SYS_futex_time64, addr, op, val, + to ? ((long long[]){s, ns}) : 0); if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r; to = to ? (void *)(long[]){CLAMP(s), ns} : 0; #endif diff --git a/src/thread/__wait.c b/src/thread/__wait.c index dc33c1a30992..ba6397207649 100644 --- a/src/thread/__wait.c +++ b/src/thread/__wait.c @@ -10,8 +10,8 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) } if (waiters) a_inc(waiters); while (*addr==val) { - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS - || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); + __futexcall(addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS + || __futexcall(addr, FUTEX_WAIT, val, 0); } if (waiters) a_dec(waiters); } diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c index cc2a8bbf58a9..7e0b8cc9cbe2 100644 --- a/src/thread/pthread_barrier_wait.c +++ b/src/thread/pthread_barrier_wait.c @@ -33,7 +33,7 @@ static int pshared_barrier_wait(pthread_barrier_t *b) while ((v=b->_b_count)) __wait(&b->_b_count, &b->_b_waiters2, v, 0); } - + /* Perform a recursive unlock suitable for self-sync'd destruction */ do { v = b->_b_lock; @@ -84,8 +84,8 @@ int pthread_barrier_wait(pthread_barrier_t *b) a_spin(); a_inc(&inst->finished); while (inst->finished == 1) - __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS - || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0); + __futexcall(&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS + || __futexcall(&inst->finished,FUTEX_WAIT,1,0); return PTHREAD_BARRIER_SERIAL_THREAD; } diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c index 6b761455c47f..a4386761479b 100644 --- a/src/thread/pthread_cond_timedwait.c +++ b/src/thread/pthread_cond_timedwait.c @@ -49,8 +49,8 @@ static inline void unlock_requeue(volatile int *l, volatile int *r, int w) { a_store(l, 0); if (w) __wake(l, 1, 1); - else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS - || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r); + else __futexcall(l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS + || __futexcall(l, FUTEX_REQUEUE, 0, 1, r); } enum { @@ -121,12 +121,12 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri * via the futex notify below. */ lock(&c->_c_lock); - + if (c->_c_head == &node) c->_c_head = node.next; else if (node.prev) node.prev->next = node.next; if (c->_c_tail == &node) c->_c_tail = node.prev; else if (node.next) node.next->prev = node.prev; - + unlock(&c->_c_lock); if (node.notify) { @@ -156,7 +156,7 @@ relock: if (val>0) a_cas(&m->_m_lock, val, val|0x80000000); unlock_requeue(&node.prev->barrier, &m->_m_lock, m->_m_type & (8|128)); } else if (!(m->_m_type & 8)) { - a_dec(&m->_m_waiters); + a_dec(&m->_m_waiters); } /* Since a signal was consumed, cancellation is not permitted. */ diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c index 9279fc54308a..1f2f1d862c69 100644 --- a/src/thread/pthread_mutex_timedlock.c +++ b/src/thread/pthread_mutex_timedlock.c @@ -8,10 +8,8 @@ static int __futex4(volatile void *addr, int op, int val, const struct timespec #ifdef SYS_futex_time64 time_t s = to ? to->tv_sec : 0; long ns = to ? to->tv_nsec : 0; - int r = -ENOSYS; - if (SYS_futex == SYS_futex_time64 || !IS32BIT(s)) - r = __syscall(SYS_futex_time64, addr, op, val, - to ? ((long long[]){s, ns}) : 0); + int r = __syscall(SYS_futex_time64, addr, op, val, + to ? ((long long[]){s, ns}) : 0); if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r; to = to ? (void *)(long[]){CLAMP(s), ns} : 0; #endif @@ -66,7 +64,7 @@ int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec if (r != EBUSY) return r; if (type&8) return pthread_mutex_timedlock_pi(m, at); - + int spins = 100; while (spins-- && m->_m_lock && !m->_m_waiters) a_spin(); diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c index a24e7c58ac39..d2a92601b6d3 100644 --- a/src/thread/pthread_mutex_trylock.c +++ b/src/thread/pthread_mutex_trylock.c @@ -43,7 +43,7 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m) success: if ((type&8) && m->_m_waiters) { int priv = (type & 128) ^ 128; - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); + __futexcall(&m->_m_lock, FUTEX_UNLOCK_PI|priv); self->robust_list.pending = 0; return (type&4) ? ENOTRECOVERABLE : EBUSY; } diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c index b66423e6c34f..0b7da563c516 100644 --- a/src/thread/pthread_mutex_unlock.c +++ b/src/thread/pthread_mutex_unlock.c @@ -33,7 +33,7 @@ int __pthread_mutex_unlock(pthread_mutex_t *m) if (type&8) { if (old<0 || a_cas(&m->_m_lock, old, new)!=old) { if (new) a_store(&m->_m_waiters, -1); - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); + __futexcall(&m->_m_lock, FUTEX_UNLOCK_PI|priv); } cont = 0; waiters = 0; diff --git a/src/thread/pthread_mutexattr_setprotocol.c b/src/thread/pthread_mutexattr_setprotocol.c index 8b80c1ce9b14..456fb9f48d2e 100644 --- a/src/thread/pthread_mutexattr_setprotocol.c +++ b/src/thread/pthread_mutexattr_setprotocol.c @@ -14,7 +14,7 @@ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int protocol) r = check_pi_result; if (r < 0) { volatile int lk = 0; - r = -__syscall(SYS_futex, &lk, FUTEX_LOCK_PI, 0, 0); + r = -__futexcall(&lk, FUTEX_LOCK_PI, 0, 0); a_store(&check_pi_result, r); } if (r) return r; -- 2.29.2
Use the new time64 variant of sched_rr_get_interval as a default and fallback to the old one only on -ENOSYS. Signed-off-by: Alexander Lobakin <alobakin@pm.me> --- src/sched/sched_rr_get_interval.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/sched/sched_rr_get_interval.c b/src/sched/sched_rr_get_interval.c index 33a3d1aeed43..bdcba9c57248 100644 --- a/src/sched/sched_rr_get_interval.c +++ b/src/sched/sched_rr_get_interval.c @@ -4,18 +4,17 @@ int sched_rr_get_interval(pid_t pid, struct timespec *ts) { #ifdef SYS_sched_rr_get_interval_time64 - /* On a 32-bit arch, use the old syscall if it exists. */ - if (SYS_sched_rr_get_interval != SYS_sched_rr_get_interval_time64) { - long ts32[2]; - int r = __syscall(SYS_sched_rr_get_interval, pid, ts32); - if (!r) { - ts->tv_sec = ts32[0]; - ts->tv_nsec = ts32[1]; - } + int r = __syscall(SYS_sched_rr_get_interval_time64, pid, ts); + if (SYS_sched_rr_get_interval == SYS_sched_rr_get_interval_time64 || r != -ENOSYS) return __syscall_ret(r); + long ts32[2]; + r = __syscall(SYS_sched_rr_get_interval, pid, ts32); + if (!r) { + ts->tv_sec = ts32[0]; + ts->tv_nsec = ts32[1]; } -#endif - /* If reaching this point, it's a 64-bit arch or time64-only - * 32-bit arch and we can get result directly into timespec. */ + return __syscall_ret(r); +#else return syscall(SYS_sched_rr_get_interval, pid, ts); +#endif } -- 2.29.2
On Sun, Dec 27, 2020 at 06:39:03PM +0000, Alexander Lobakin wrote:
> Since Linux 4.18, there's an option CONFIG_COMPAT_32BIT_TIME that
> allows to ultimately test libc and userland programs if they are
> using the latest available syscall variants, time64 variants in
> particular.
> With this option turned off, old time32 syscalls don't get compiled
> at all. The same applies to some deprecated syscalls such as
> nanosleep.
CONFIG_COMPAT_32BIT_TIME is a violation of kernel stability policy and
was introduced as a bait-and-switch, with an initial promise that it
was a debugging option that would be hidden behind kernel hacking,
that somehow disappeared and ended up getting replaced with a
situation where it's turned off by allnoconfig. It should never be
enabled on any production system, as it precludes running any existing
binaries that depend on the kernel stability policy.
In general musl usually uses the oldest kernel APIs supporting the
needed functionality, and this is very intentional. It avoids costly
fallback procedures and situations where these code paths don't get
tested.
Aside from the principle of the matter, there are fairly large number
of call points where no fallback at all is needed, but one would be
needed if we used the new time64 syscalls first. This is because a lot
of the syscalls that CONFIG_COMPAT_32BIT_TIME=n wrongly removes
(again, in violation of kernel stability policy) are only
time-dependent for an optional timeout, and are usually called without
a timeout. This is particularly the case for futex, where each futex
call point would get considerably heavier if it had to support
fallbacks with a different syscall.
I haven't looked at the specifics of your patches yet to know if they
even got this. I will soon, but I'm pretty sure this is all just going
to have to be a no.
Rich
On Sun, Dec 27, 2020 at 06:40:45PM +0000, Alexander Lobakin wrote:
> Instead of using time64 variant "only when needed", use it as
> a default and fallback to time32 only on -ENOSYS.
>
> Signed-off-by: Alexander Lobakin <alobakin@pm.me>
> ---
> src/time/clock_gettime.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
> index 3e1d0975b122..ec8d08c010cf 100644
> --- a/src/time/clock_gettime.c
> +++ b/src/time/clock_gettime.c
> @@ -73,9 +73,7 @@ int __clock_gettime(clockid_t clk, struct timespec *ts)
> #endif
>
> #ifdef SYS_clock_gettime64
> - r = -ENOSYS;
> - if (sizeof(time_t) > 4)
> - r = __syscall(SYS_clock_gettime64, clk, ts);
> + r = __syscall(SYS_clock_gettime64, clk, ts);
> if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
> return __syscall_ret(r);
> long ts32[2];
> --
> 2.29.2
This change is a functional nop, just removing code that's left from
prior to the time64 switchover. It's probably not objectionable, but
it's not described accurately.
Rich
On Sun, Dec 27, 2020 at 06:41:02PM +0000, Alexander Lobakin wrote:
> Try to use deprecated adjtimex only after clock_adjtime_time64 or
> clock_adjtime fail with -ENOSYS.
>
> Signed-off-by: Alexander Lobakin <alobakin@pm.me>
> ---
> src/linux/clock_adjtime.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/src/linux/clock_adjtime.c b/src/linux/clock_adjtime.c
> index d4d03d24df40..5a21d5625e59 100644
> --- a/src/linux/clock_adjtime.c
> +++ b/src/linux/clock_adjtime.c
> @@ -114,11 +114,11 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx)
> .stbcnt = utx->stbcnt,
> .tai = utx->tai,
> };
> + r = __syscall(SYS_clock_adjtime, clock_id, &ktx);
> #ifdef SYS_adjtimex
> - if (clock_id==CLOCK_REALTIME) r = __syscall(SYS_adjtimex, &ktx);
> - else
> + if (r == -ENOSYS && clock_id == CLOCK_REALTIME)
> + r = __syscall(SYS_adjtimex, &ktx);
> #endif
> - r = __syscall(SYS_clock_adjtime, clock_id, &ktx);
> if (r>=0) {
> utx->modes = ktx.modes;
> utx->offset = ktx.offset;
> @@ -144,8 +144,10 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx)
> }
> return __syscall_ret(r);
> }
> + r = __syscall(SYS_clock_adjtime, clock_id, utx);
> #ifdef SYS_adjtimex
> - if (clock_id==CLOCK_REALTIME) return syscall(SYS_adjtimex, utx);
> + if (r == -ENOSYS && clock_id == CLOCK_REALTIME)
> + r = __syscall(SYS_adjtimex, utx);
> #endif
> - return syscall(SYS_clock_adjtime, clock_id, utx);
> + return __syscall_ret(r);
> }
> --
> 2.29.2
>
This proposed change seems to have nothing to do with supporting
CONFIG_COMPAT_32BIT_TIME=n and makes fallback behavior strictly worse
for old kernels.
Rich
On Sun, Dec 27, 2020 at 06:42:47PM +0000, Alexander Lobakin wrote: > Instead of using time64 variant "only when needed", use it as > a default and fallback to time32 only on -ENOSYS. > This also introduces a new shorthand, __futexcall(), for futex > calls without timespec argument. > > Signed-off-by: Alexander Lobakin <alobakin@pm.me> > --- > src/internal/pthread_impl.h | 22 ++++++++++++++++++---- > src/thread/__timedwait.c | 6 ++---- > src/thread/__wait.c | 4 ++-- > src/thread/pthread_barrier_wait.c | 6 +++--- > src/thread/pthread_cond_timedwait.c | 10 +++++----- > src/thread/pthread_mutex_timedlock.c | 8 +++----- > src/thread/pthread_mutex_trylock.c | 2 +- > src/thread/pthread_mutex_unlock.c | 2 +- > src/thread/pthread_mutexattr_setprotocol.c | 2 +- > 9 files changed, 36 insertions(+), 26 deletions(-) > > diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h > index de2b9d8b477e..abb2a9a074a0 100644 > --- a/src/internal/pthread_impl.h > +++ b/src/internal/pthread_impl.h > @@ -165,18 +165,32 @@ hidden void __unmapself(void *, size_t); > hidden int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int); > hidden int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int); > hidden void __wait(volatile int *, volatile int *, int, int); > + > +#ifdef SYS_futex_time64 > +#define __futexcall(...) ({ \ > + int __r = __syscall(SYS_futex_time64, ##__VA_ARGS__); \ > + if (!(SYS_futex == SYS_futex_time64 || __r != -ENOSYS)) \ > + __r = __syscall(SYS_futex, ##__VA_ARGS__); \ > + __r; \ > +}) > +#else > +#define __futexcall(...) ({ \ > + __syscall(SYS_futex, ##__VA_ARGS__); \ > +}) > +#endif > + > static inline void __wake(volatile void *addr, int cnt, int priv) > { > if (priv) priv = FUTEX_PRIVATE; > if (cnt<0) cnt = INT_MAX; > - __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || > - __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); > + __futexcall(addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || > + __futexcall(addr, FUTEX_WAKE, cnt); > } > static inline void __futexwait(volatile void *addr, int val, int priv) > { > if (priv) priv = FUTEX_PRIVATE; > - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || > - __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); > + __futexcall(addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS || > + __futexcall(addr, FUTEX_WAIT, val, 0); > } If we ever do this, I don't think the above is the right way -- the fallback through SYS_futex_time64 bit without the private bit is an utter waste since that combination can never happen. It's just one extra fallback, not two, that's needed. Note that wake is one of the many cases where it does not make sense to have fallback cost for this at all. Wake is an operation that does not even take a time argument. I've spoken with Arnd about making it so that CONFIG_COMPAT_32BIT_TIME=n does not remove SYS_futex commands that don't use time arguments and I really think this change should be made upstream in the kernel; otherwise we're imposing useless fallback cost for utterly no reason in hot paths. > diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c > index cc2a8bbf58a9..7e0b8cc9cbe2 100644 > --- a/src/thread/pthread_barrier_wait.c > +++ b/src/thread/pthread_barrier_wait.c > @@ -33,7 +33,7 @@ static int pshared_barrier_wait(pthread_barrier_t *b) > while ((v=b->_b_count)) > __wait(&b->_b_count, &b->_b_waiters2, v, 0); > } > - > + > /* Perform a recursive unlock suitable for self-sync'd destruction */ > do { > v = b->_b_lock; > @@ -84,8 +84,8 @@ int pthread_barrier_wait(pthread_barrier_t *b) > a_spin(); > a_inc(&inst->finished); > while (inst->finished == 1) > - __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS > - || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0); > + __futexcall(&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS > + || __futexcall(&inst->finished,FUTEX_WAIT,1,0); > return PTHREAD_BARRIER_SERIAL_THREAD; > } This should probably be refactored not to use SYS_futex directly regardless of whether any other changes are made. It should be able to use __wait. > diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c > index 6b761455c47f..a4386761479b 100644 > --- a/src/thread/pthread_cond_timedwait.c > +++ b/src/thread/pthread_cond_timedwait.c > @@ -49,8 +49,8 @@ static inline void unlock_requeue(volatile int *l, volatile int *r, int w) > { > a_store(l, 0); > if (w) __wake(l, 1, 1); > - else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS > - || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r); > + else __futexcall(l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS > + || __futexcall(l, FUTEX_REQUEUE, 0, 1, r); > } This is also duplicating the time64-without-private wasted fallback case. > enum { > @@ -121,12 +121,12 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri > * via the futex notify below. */ > > lock(&c->_c_lock); > - > + > if (c->_c_head == &node) c->_c_head = node.next; > else if (node.prev) node.prev->next = node.next; > if (c->_c_tail == &node) c->_c_tail = node.prev; > else if (node.next) node.next->prev = node.prev; > - > + > unlock(&c->_c_lock); > > if (node.notify) { > @@ -156,7 +156,7 @@ relock: > if (val>0) a_cas(&m->_m_lock, val, val|0x80000000); > unlock_requeue(&node.prev->barrier, &m->_m_lock, m->_m_type & (8|128)); > } else if (!(m->_m_type & 8)) { > - a_dec(&m->_m_waiters); > + a_dec(&m->_m_waiters); > } > If you want to clean these things up can you send it as a separate patch prior to any functional changes? > diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c > index a24e7c58ac39..d2a92601b6d3 100644 > --- a/src/thread/pthread_mutex_trylock.c > +++ b/src/thread/pthread_mutex_trylock.c > @@ -43,7 +43,7 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m) > success: > if ((type&8) && m->_m_waiters) { > int priv = (type & 128) ^ 128; > - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); > + __futexcall(&m->_m_lock, FUTEX_UNLOCK_PI|priv); > self->robust_list.pending = 0; > return (type&4) ? ENOTRECOVERABLE : EBUSY; This is another place where the operation does not take a time argument and the need for fallback conceptually makes no sense. > } > diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c > index b66423e6c34f..0b7da563c516 100644 > --- a/src/thread/pthread_mutex_unlock.c > +++ b/src/thread/pthread_mutex_unlock.c > @@ -33,7 +33,7 @@ int __pthread_mutex_unlock(pthread_mutex_t *m) > if (type&8) { > if (old<0 || a_cas(&m->_m_lock, old, new)!=old) { > if (new) a_store(&m->_m_waiters, -1); > - __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); > + __futexcall(&m->_m_lock, FUTEX_UNLOCK_PI|priv); > } > cont = 0; > waiters = 0; Same. > diff --git a/src/thread/pthread_mutexattr_setprotocol.c b/src/thread/pthread_mutexattr_setprotocol.c > index 8b80c1ce9b14..456fb9f48d2e 100644 > --- a/src/thread/pthread_mutexattr_setprotocol.c > +++ b/src/thread/pthread_mutexattr_setprotocol.c > @@ -14,7 +14,7 @@ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int protocol) > r = check_pi_result; > if (r < 0) { > volatile int lk = 0; > - r = -__syscall(SYS_futex, &lk, FUTEX_LOCK_PI, 0, 0); > + r = -__futexcall(&lk, FUTEX_LOCK_PI, 0, 0); > a_store(&check_pi_result, r); > } > if (r) return r; Same, but this isn't a hot path anyway. Rich
From: Rich Felker <dalias@aerifal.cx> Date: Sun, 27 Dec 2020 16:52:19 -0500 > On Sun, Dec 27, 2020 at 06:39:03PM +0000, Alexander Lobakin wrote: >> Since Linux 4.18, there's an option CONFIG_COMPAT_32BIT_TIME that >> allows to ultimately test libc and userland programs if they are >> using the latest available syscall variants, time64 variants in >> particular. >> With this option turned off, old time32 syscalls don't get compiled >> at all. The same applies to some deprecated syscalls such as >> nanosleep. > > CONFIG_COMPAT_32BIT_TIME is a violation of kernel stability policy and > was introduced as a bait-and-switch, with an initial promise that it > was a debugging option that would be hidden behind kernel hacking, > that somehow disappeared and ended up getting replaced with a > situation where it's turned off by allnoconfig. It should never be > enabled on any production system, as it precludes running any existing > binaries that depend on the kernel stability policy. > > In general musl usually uses the oldest kernel APIs supporting the > needed functionality, and this is very intentional. It avoids costly > fallback procedures and situations where these code paths don't get > tested. > > Aside from the principle of the matter, there are fairly large number > of call points where no fallback at all is needed, but one would be > needed if we used the new time64 syscalls first. This is because a lot > of the syscalls that CONFIG_COMPAT_32BIT_TIME=n wrongly removes > (again, in violation of kernel stability policy) are only > time-dependent for an optional timeout, and are usually called without > a timeout. This is particularly the case for futex, where each futex > call point would get considerably heavier if it had to support > fallbacks with a different syscall. > > I haven't looked at the specifics of your patches yet to know if they > even got this. I will soon, but I'm pretty sure this is all just going > to have to be a no. So, regarding the entire series, should I continue to work on v2 etc. or it's not worth it since CONFIG_COMPAT_32BIT_TIME is considered _wrong_ -> not the thing that we should rely on? > Rich Thanks, Al