[release/6.0] [Android] Workaround for invalid return value from clock_nanosleep...
authorSimon Rozsival <simon@rozsival.com>
Thu, 10 Mar 2022 20:31:16 +0000 (21:31 +0100)
committerGitHub <noreply@github.com>
Thu, 10 Mar 2022 20:31:16 +0000 (14:31 -0600)
* [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

* Fix leftover direct call to clock_nanosleep

src/mono/mono/eglib/CMakeLists.txt
src/mono/mono/eglib/eglib-remap.h
src/mono/mono/eglib/gclock-nanosleep.c [new file with mode: 0644]
src/mono/mono/eglib/gdate-unix.c
src/mono/mono/eglib/glib.h
src/mono/mono/mini/mini-posix.c
src/mono/mono/utils/mono-threads.c

index 1325ee6..69bf7e1 100644 (file)
@@ -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}")
index c3e9568..3af646a 100644 (file)
 #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 (file)
index 0000000..f2ced8b
--- /dev/null
@@ -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 <config.h>
+#include <glib.h>
+#include <errno.h>
+
+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;
+}
index 53f4bbb..9a98e66 100644 (file)
@@ -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);
index 5a454a0..4c08f44 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdint.h>
 #include <inttypes.h>
 #include <eglib-config.h>
+#include <time.h>
 
 // - 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
index 346b4bd..79bf8c8 100644 (file)
@@ -79,6 +79,7 @@
 #include <mono/component/debugger-agent.h>
 #include "mini-runtime.h"
 #include "jit-icalls.h"
+#include <glib.h>
 
 #ifdef HOST_DARWIN
 #include <mach/mach.h>
@@ -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;
                }
@@ -554,7 +555,7 @@ 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);
index 52890fe..e26cc53 100644 (file)
@@ -33,6 +33,7 @@
 #include <mono/utils/mono-threads-debug.h>
 #include <mono/utils/os-event.h>
 #include <mono/utils/w32api.h>
+#include <glib.h>
 
 #include <errno.h>
 #include <mono/utils/mono-errno.h>
@@ -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);