diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2021-05-21 16:52:43 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2021-05-21 16:52:43 +0000 |
commit | 83b32a91c5bbc0f5765935f9dafe706e66051d95 (patch) | |
tree | d29a468871ba77b3f3655763fe3307cd339a788c /lib | |
parent | 71e2a8f174fc0fcaf9094cddb94e7eca873d683d (diff) |
The implementation of the FUTEX_WAIT option in futex(2) is subtly broken.
Unfortunately libc and libpthread rely on the broken behaviour. Adjust
the code in those libraries such that it works with both the old and the
proposed new behaviour. The kernel changes that fix the issue will be
committed in a week or so to give those who do their own builds a chance
to update these libraries before we make the change.
ok mpi@, deraadt@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/thread/synch.h | 20 | ||||
-rw-r--r-- | lib/librthread/synch.h | 20 |
2 files changed, 28 insertions, 12 deletions
diff --git a/lib/libc/thread/synch.h b/lib/libc/thread/synch.h index aaeb965956a..91b5001c515 100644 --- a/lib/libc/thread/synch.h +++ b/lib/libc/thread/synch.h @@ -1,4 +1,4 @@ -/* $OpenBSD: synch.h,v 1.5 2020/07/06 13:33:06 pirofti Exp $ */ +/* $OpenBSD: synch.h,v 1.6 2021/05/21 16:52:42 kettenis Exp $ */ /* * Copyright (c) 2017 Martin Pieuchot * @@ -29,12 +29,17 @@ static inline int _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *abs) { struct timespec rel; + int error; - if (abs == NULL) - return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL); + if (abs == NULL) { + error = futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL); + if (error == -1) + error = errno; + return error; + } if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel)) - return (EINVAL); + return EINVAL; rel.tv_sec = abs->tv_sec - rel.tv_sec; if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) { @@ -42,9 +47,12 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec * rel.tv_nsec += 1000000000; } if (rel.tv_sec < 0) - return (ETIMEDOUT); + return ETIMEDOUT; - return futex(p, FUTEX_WAIT_PRIVATE, val, &rel, NULL); + error = futex(p, FUTEX_WAIT_PRIVATE, val, &rel, NULL); + if (error == -1) + error = errno; + return error; } static inline int diff --git a/lib/librthread/synch.h b/lib/librthread/synch.h index 381ed1b1749..e5c623e87a0 100644 --- a/lib/librthread/synch.h +++ b/lib/librthread/synch.h @@ -1,4 +1,4 @@ -/* $OpenBSD: synch.h,v 1.6 2019/10/24 12:32:18 sthen Exp $ */ +/* $OpenBSD: synch.h,v 1.7 2021/05/21 16:52:42 kettenis Exp $ */ /* * Copyright (c) 2017 Martin Pieuchot * @@ -36,12 +36,17 @@ static inline int _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *abs) { struct timespec rel; + int error; - if (abs == NULL) - return futex(p, FUTEX_WAIT, val, NULL, NULL); + if (abs == NULL) { + error = futex(p, FUTEX_WAIT, val, NULL, NULL); + if (error == -1) + error = errno; + return error; + } if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel)) - return (EINVAL); + return EINVAL; rel.tv_sec = abs->tv_sec - rel.tv_sec; if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) { @@ -49,9 +54,12 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec * rel.tv_nsec += 1000000000; } if (rel.tv_sec < 0) - return (ETIMEDOUT); + return ETIMEDOUT; - return futex(p, FUTEX_WAIT, val, &rel, NULL); + error = futex(p, FUTEX_WAIT, val, &rel, NULL); + if (error == -1) + error = errno; + return error; } static inline int |