Skip to content

Commit

Permalink
[Android] Workaround for invalid return value from clock_nanosleep (#…
Browse files Browse the repository at this point in the history
…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](dotnet/android#6600 (comment)).

Fixes dotnet/android#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
  • Loading branch information
simonrozsival authored Feb 9, 2022
1 parent aaaa2a7 commit ac82c68
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/mono/mono/eglib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
4 changes: 4 additions & 0 deletions src/mono/mono/eglib/eglib-remap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
31 changes: 31 additions & 0 deletions src/mono/mono/eglib/gclock-nanosleep.c
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion src/mono/mono/eglib/gdate-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions src/mono/mono/eglib/glib.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <inttypes.h>
#include <eglib-config.h>
#include <minipal/utils.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.
Expand Down Expand Up @@ -1506,4 +1507,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
4 changes: 2 additions & 2 deletions src/mono/mono/mini/mini-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,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>
Expand Down Expand Up @@ -484,7 +485,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;
}
Expand All @@ -509,7 +510,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));
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/utils/mono-threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -1748,7 +1749,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);
Expand Down

0 comments on commit ac82c68

Please sign in to comment.