diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c index ad4c006fd..fe2fa23ff 100644 --- a/glib/gthread-posix.c +++ b/glib/gthread-posix.c @@ -1605,12 +1605,16 @@ g_cond_wait_until (GCond *cond, * To get around this problem we * a) check if `futex_time64` is available, which only exists on 32-bit * platforms and always uses 64-bit `time_t`. - * b) otherwise (or if that returns `ENOSYS`), we call the normal `futex` + * b) if `futex_time64` is available, but the Android runtime's API level + * is < 30, `futex_time64` is blocked by seccomp and using it will cause + * the app to be terminated. Skip to c). + * https://android-review.googlesource.com/c/platform/bionic/+/1094758 + * c) otherwise (or if that returns `ENOSYS`), we call the normal `futex` * syscall with the `struct timespec` used by the kernel. By default, we * use `__kernel_long_t` for both its fields, which is equivalent to * `__kernel_old_time_t` and is available in the kernel headers for a * longer time. - * c) With very old headers (~2.6.x), `__kernel_long_t` is not available, and + * d) With very old headers (~2.6.x), `__kernel_long_t` is not available, and * we use an older definition that uses `__kernel_time_t` and `long`. * * Also some 32-bit systems do not define `__NR_futex` at all and only @@ -1620,8 +1624,12 @@ g_cond_wait_until (GCond *cond, sampled = cond->i[0]; g_mutex_unlock (mutex); -#ifdef __NR_futex_time64 +#if defined(HAVE_FUTEX_TIME64) +#if defined(__BIONIC__) + if (__builtin_available (android 30, *)) { +#else { +#endif struct { gint64 tv_sec; @@ -1637,9 +1645,9 @@ g_cond_wait_until (GCond *cond, * normal `futex` syscall. This can happen if newer kernel headers are * used than the kernel that is actually running. */ -# ifdef __NR_futex +# if defined(HAVE_FUTEX) if (res >= 0 || errno != ENOSYS) -# endif /* defined(__NR_futex) */ +# endif /* defined(HAVE_FUTEX) */ { success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE; g_mutex_lock (mutex); @@ -1649,7 +1657,7 @@ g_cond_wait_until (GCond *cond, } #endif -#ifdef __NR_futex +#if defined(HAVE_FUTEX) { # ifdef __kernel_long_t # define KERNEL_SPAN_SEC_TYPE __kernel_long_t @@ -1681,7 +1689,7 @@ g_cond_wait_until (GCond *cond, return success; } # undef KERNEL_SPAN_SEC_TYPE -#endif /* defined(__NR_futex) */ +#endif /* defined(HAVE_FUTEX) */ /* We can't end up here because of the checks above */ g_assert_not_reached (); diff --git a/glib/gthreadprivate.h b/glib/gthreadprivate.h index 61dfdae34..7bc28a834 100644 --- a/glib/gthreadprivate.h +++ b/glib/gthreadprivate.h @@ -64,10 +64,41 @@ struct _GRealThread * with the normal `futex` syscall. This can happen if newer kernel headers * are used than the kernel that is actually running. * + * The `futex_time64` syscall is also skipped in favour of `futex` if the + * Android runtime’s API level is lower than 30, as it’s blocked by seccomp + * there and using it will cause the app to be terminated: + * https://android-review.googlesource.com/c/platform/bionic/+/1094758 + * https://github.com/aosp-mirror/platform_bionic/commit/ee7bc3002dc3127faac110167d28912eb0e86a20 + * * This must not be called with a timeout parameter as that differs * in size between the two syscall variants! */ -#if defined(__NR_futex) && defined(__NR_futex_time64) +#if defined(HAVE_FUTEX) && defined(HAVE_FUTEX_TIME64) +#if defined(__BIONIC__) +#define g_futex_simple(uaddr, futex_op, ...) \ + G_STMT_START \ + { \ + int res = 0; \ + if (__builtin_available (android 30, *)) \ + { \ + res = syscall (__NR_futex_time64, uaddr, (gsize) futex_op, __VA_ARGS__); \ + if (res < 0 && errno == ENOSYS) \ + { \ + errno = saved_errno; \ + res = syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \ + } \ + } \ + else \ + { \ + res = syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \ + } \ + if (res < 0 && errno == EAGAIN) \ + { \ + errno = saved_errno; \ + } \ + } \ + G_STMT_END +#else #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ { \ @@ -84,7 +115,8 @@ struct _GRealThread } \ } \ G_STMT_END -#elif defined(__NR_futex_time64) +#endif /* defined(__BIONIC__) */ +#elif defined(HAVE_FUTEX_TIME64) #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ { \ @@ -96,7 +128,7 @@ struct _GRealThread } \ } \ G_STMT_END -#elif defined(__NR_futex) +#elif defined(HAVE_FUTEX) #define g_futex_simple(uaddr, futex_op, ...) \ G_STMT_START \ { \ @@ -108,9 +140,9 @@ struct _GRealThread } \ } \ G_STMT_END -#else /* !defined(__NR_futex) && !defined(__NR_futex_time64) */ -#error "Neither __NR_futex nor __NR_futex_time64 are defined but were found by meson" -#endif /* defined(__NR_futex) && defined(__NR_futex_time64) */ +#else /* !defined(HAVE_FUTEX) && !defined(HAVE_FUTEX_TIME64) */ +#error "Neither __NR_futex nor __NR_futex_time64 are available" +#endif /* defined(HAVE_FUTEX) && defined(HAVE_FUTEX_TIME64) */ #endif diff --git a/meson.build b/meson.build index 5328adc3a..f0c5e070b 100644 --- a/meson.build +++ b/meson.build @@ -994,7 +994,7 @@ if cc.compiles('''#include int main (int argc, char ** argv) { syscall (__NR_futex_time64, NULL, FUTEX_WAKE, FUTEX_WAIT); return 0; - }''', name : 'futex(2) system call') + }''', name : 'futex_time64(2) system call') glib_conf.set('HAVE_FUTEX_TIME64', 1) endif