From 8d035b56cdf617d5a70cf0a388d27d489e7b991d Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 9 Feb 2022 18:41:06 +0100 Subject: [PATCH 1/2] [Android] Workaround for invalid return value from clock_nanosleep (#64679) There used to be a bug in Android libc implementation of `clock_nanosleep`. The return value should be `errno` on errors but instead in it returns `-1` and sets `errno`. The libc (Bionic) bug [has been fixed](https://android-review.googlesource.com/c/platform/bionic/+/110652/) since Android 6 and newer but it causes problems to [customers who are unable to update Android on their devices](https://github.com/xamarin/xamarin-android/issues/6600#issuecomment-1026023654). Fixes https://github.com/xamarin/xamarin-android/issues/6600 * Account for incorrect implementation of clock_nanosleep in older Android libc * Shorten comments * Add g_clock_nanosleep function * Add remap definition * Fix build * Make sure the extra check runs only on Android * Make Windows builds happy * Try making wasm builds happy --- src/mono/mono/eglib/CMakeLists.txt | 4 ++++ src/mono/mono/eglib/eglib-remap.h | 4 ++++ src/mono/mono/eglib/gclock-nanosleep.c | 31 ++++++++++++++++++++++++++ src/mono/mono/eglib/gdate-unix.c | 2 +- src/mono/mono/eglib/glib.h | 10 +++++++++ src/mono/mono/mini/mini-posix.c | 4 ++-- src/mono/mono/utils/mono-threads.c | 3 ++- 7 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 src/mono/mono/eglib/gclock-nanosleep.c diff --git a/src/mono/mono/eglib/CMakeLists.txt b/src/mono/mono/eglib/CMakeLists.txt index 1325ee6c1126ce..69bf7e188696b1 100644 --- a/src/mono/mono/eglib/CMakeLists.txt +++ b/src/mono/mono/eglib/CMakeLists.txt @@ -43,6 +43,10 @@ set(eglib_common_sources gunicode.c unicode-data.h) +if(HAVE_CLOCK_NANOSLEEP) +list(APPEND eglib_common_sources gclock-nanosleep.c) +endif() + addprefix(eglib_sources ../eglib/ "${eglib_platform_sources};${eglib_common_sources}") add_library(eglib_objects OBJECT "${eglib_sources}") diff --git a/src/mono/mono/eglib/eglib-remap.h b/src/mono/mono/eglib/eglib-remap.h index c3e956842dea85..3af646a8e47b2f 100644 --- a/src/mono/mono/eglib/eglib-remap.h +++ b/src/mono/mono/eglib/eglib-remap.h @@ -318,3 +318,7 @@ #define g_ascii_charcmp monoeg_ascii_charcmp #define g_ascii_charcasecmp monoeg_ascii_charcasecmp #define g_warning_d monoeg_warning_d + +#ifdef HAVE_CLOCK_NANOSLEEP +#define g_clock_nanosleep monoeg_clock_nanosleep +#endif diff --git a/src/mono/mono/eglib/gclock-nanosleep.c b/src/mono/mono/eglib/gclock-nanosleep.c new file mode 100644 index 00000000000000..f2ced8b2c07d1a --- /dev/null +++ b/src/mono/mono/eglib/gclock-nanosleep.c @@ -0,0 +1,31 @@ +/* + * gclock_nanosleep.c: Clock nanosleep on platforms that have clock_nanosleep(). + * + * Copyright 2022 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. +*/ + +#include +#include +#include + +gint +g_clock_nanosleep (clockid_t clockid, gint flags, const struct timespec *request, struct timespec *remain) +{ + gint ret = 0; + +#if defined(HAVE_CLOCK_NANOSLEEP) && !defined(__PASE__) + ret = clock_nanosleep (clockid, flags, request, remain); +#else + g_assert_not_reached (); +#endif + +#ifdef HOST_ANDROID + // Workaround for incorrect implementation of clock_nanosleep return value on old Android (<=5.1) + // See https://github.com/xamarin/xamarin-android/issues/6600 + if (ret == -1) + ret = errno; +#endif + + return ret; +} diff --git a/src/mono/mono/eglib/gdate-unix.c b/src/mono/mono/eglib/gdate-unix.c index 53f4bbb3d5adc2..9a98e663045762 100644 --- a/src/mono/mono/eglib/gdate-unix.c +++ b/src/mono/mono/eglib/gdate-unix.c @@ -64,7 +64,7 @@ g_usleep (gulong microseconds) } do { - ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL); + ret = g_clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL); if (ret != 0 && ret != EINTR) g_error ("%s: clock_nanosleep () returned %d", __func__, ret); } while (ret == EINTR); diff --git a/src/mono/mono/eglib/glib.h b/src/mono/mono/eglib/glib.h index 5a454a037202f5..4c08f44732eee5 100644 --- a/src/mono/mono/eglib/glib.h +++ b/src/mono/mono/eglib/glib.h @@ -27,6 +27,7 @@ #include #include #include +#include // - Pointers should only be converted to or from pointer-sized integers. // - Any size integer can be converted to any other size integer. @@ -1508,4 +1509,13 @@ mono_qsort (void* base, size_t num, size_t size, int (*compare)(const void*, con #define g_try_realloc(obj, size) (g_cast (monoeg_try_realloc ((obj), (size)))) #define g_memdup(mem, size) (g_cast (monoeg_g_memdup ((mem), (size)))) +/* + * Clock Nanosleep + */ + +#ifdef HAVE_CLOCK_NANOSLEEP +gint +g_clock_nanosleep (clockid_t clockid, gint flags, const struct timespec *request, struct timespec *remain); +#endif + #endif // __GLIB_H diff --git a/src/mono/mono/mini/mini-posix.c b/src/mono/mono/mini/mini-posix.c index 346b4bd43f2efd..576623808329fa 100644 --- a/src/mono/mono/mini/mini-posix.c +++ b/src/mono/mono/mini/mini-posix.c @@ -79,6 +79,7 @@ #include #include "mini-runtime.h" #include "jit-icalls.h" +#include #ifdef HOST_DARWIN #include @@ -530,7 +531,7 @@ clock_init_for_profiler (MonoProfilerSampleMode mode) * CLOCK_PROCESS_CPUTIME_ID clock but don't actually support it. For * those systems, we fall back to CLOCK_MONOTONIC if we get EINVAL. */ - if (clock_nanosleep (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME, &ts, NULL) != EINVAL) { + if (g_clock_nanosleep (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME, &ts, NULL) != EINVAL) { sampling_clock = CLOCK_PROCESS_CPUTIME_ID; break; } @@ -555,7 +556,6 @@ clock_sleep_ns_abs (guint64 ns_abs) do { ret = clock_nanosleep (sampling_clock, TIMER_ABSTIME, &then, NULL); - if (ret != 0 && ret != EINTR) g_error ("%s: clock_nanosleep () returned %d", __func__, ret); } while (ret == EINTR && mono_atomic_load_i32 (&sampling_thread_running)); diff --git a/src/mono/mono/utils/mono-threads.c b/src/mono/mono/utils/mono-threads.c index 52890fe288ea33..e26cc53e02ca6e 100644 --- a/src/mono/mono/utils/mono-threads.c +++ b/src/mono/mono/utils/mono-threads.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -1743,7 +1744,7 @@ mono_thread_info_sleep (guint32 ms, gboolean *alerted) } do { - ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL); + ret = g_clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL); } while (ret != 0); #elif HOST_WIN32 Sleep (ms); From cc9c488bb675f195e54e77b7793e76caee636574 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 15 Feb 2022 14:02:25 +0100 Subject: [PATCH 2/2] Fix leftover direct call to clock_nanosleep --- src/mono/mono/mini/mini-posix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-posix.c b/src/mono/mono/mini/mini-posix.c index 576623808329fa..79bf8c84f88885 100644 --- a/src/mono/mono/mini/mini-posix.c +++ b/src/mono/mono/mini/mini-posix.c @@ -555,7 +555,8 @@ clock_sleep_ns_abs (guint64 ns_abs) then.tv_nsec = ns_abs % 1000000000; do { - ret = clock_nanosleep (sampling_clock, TIMER_ABSTIME, &then, NULL); + ret = g_clock_nanosleep (sampling_clock, TIMER_ABSTIME, &then, NULL); + if (ret != 0 && ret != EINTR) g_error ("%s: clock_nanosleep () returned %d", __func__, ret); } while (ret == EINTR && mono_atomic_load_i32 (&sampling_thread_running));