Skip to content

Commit ac82c68

Browse files
[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](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
1 parent aaaa2a7 commit ac82c68

File tree

7 files changed

+54
-4
lines changed

7 files changed

+54
-4
lines changed

src/mono/mono/eglib/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ set(eglib_common_sources
4343
gunicode.c
4444
unicode-data.h)
4545

46+
if(HAVE_CLOCK_NANOSLEEP)
47+
list(APPEND eglib_common_sources gclock-nanosleep.c)
48+
endif()
49+
4650
addprefix(eglib_sources ../eglib/ "${eglib_platform_sources};${eglib_common_sources}")
4751

4852
add_library(eglib_objects OBJECT "${eglib_sources}")

src/mono/mono/eglib/eglib-remap.h

+4
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,7 @@
318318
#define g_ascii_charcmp monoeg_ascii_charcmp
319319
#define g_ascii_charcasecmp monoeg_ascii_charcasecmp
320320
#define g_warning_d monoeg_warning_d
321+
322+
#ifdef HAVE_CLOCK_NANOSLEEP
323+
#define g_clock_nanosleep monoeg_clock_nanosleep
324+
#endif
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* gclock_nanosleep.c: Clock nanosleep on platforms that have clock_nanosleep().
3+
*
4+
* Copyright 2022 Microsoft
5+
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
6+
*/
7+
8+
#include <config.h>
9+
#include <glib.h>
10+
#include <errno.h>
11+
12+
gint
13+
g_clock_nanosleep (clockid_t clockid, gint flags, const struct timespec *request, struct timespec *remain)
14+
{
15+
gint ret = 0;
16+
17+
#if defined(HAVE_CLOCK_NANOSLEEP) && !defined(__PASE__)
18+
ret = clock_nanosleep (clockid, flags, request, remain);
19+
#else
20+
g_assert_not_reached ();
21+
#endif
22+
23+
#ifdef HOST_ANDROID
24+
// Workaround for incorrect implementation of clock_nanosleep return value on old Android (<=5.1)
25+
// See https://github.com/xamarin/xamarin-android/issues/6600
26+
if (ret == -1)
27+
ret = errno;
28+
#endif
29+
30+
return ret;
31+
}

src/mono/mono/eglib/gdate-unix.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ g_usleep (gulong microseconds)
6464
}
6565

6666
do {
67-
ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
67+
ret = g_clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
6868
if (ret != 0 && ret != EINTR)
6969
g_error ("%s: clock_nanosleep () returned %d", __func__, ret);
7070
} while (ret == EINTR);

src/mono/mono/eglib/glib.h

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <inttypes.h>
2929
#include <eglib-config.h>
3030
#include <minipal/utils.h>
31+
#include <time.h>
3132

3233
// - Pointers should only be converted to or from pointer-sized integers.
3334
// - Any size integer can be converted to any other size integer.
@@ -1506,4 +1507,13 @@ mono_qsort (void* base, size_t num, size_t size, int (*compare)(const void*, con
15061507
#define g_try_realloc(obj, size) (g_cast (monoeg_try_realloc ((obj), (size))))
15071508
#define g_memdup(mem, size) (g_cast (monoeg_g_memdup ((mem), (size))))
15081509

1510+
/*
1511+
* Clock Nanosleep
1512+
*/
1513+
1514+
#ifdef HAVE_CLOCK_NANOSLEEP
1515+
gint
1516+
g_clock_nanosleep (clockid_t clockid, gint flags, const struct timespec *request, struct timespec *remain);
1517+
#endif
1518+
15091519
#endif // __GLIB_H

src/mono/mono/mini/mini-posix.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#include <mono/component/debugger-agent.h>
7979
#include "mini-runtime.h"
8080
#include "jit-icalls.h"
81+
#include <glib.h>
8182

8283
#ifdef HOST_DARWIN
8384
#include <mach/mach.h>
@@ -484,7 +485,7 @@ clock_init_for_profiler (MonoProfilerSampleMode mode)
484485
* CLOCK_PROCESS_CPUTIME_ID clock but don't actually support it. For
485486
* those systems, we fall back to CLOCK_MONOTONIC if we get EINVAL.
486487
*/
487-
if (clock_nanosleep (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME, &ts, NULL) != EINVAL) {
488+
if (g_clock_nanosleep (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME, &ts, NULL) != EINVAL) {
488489
sampling_clock = CLOCK_PROCESS_CPUTIME_ID;
489490
break;
490491
}
@@ -509,7 +510,6 @@ clock_sleep_ns_abs (guint64 ns_abs)
509510

510511
do {
511512
ret = clock_nanosleep (sampling_clock, TIMER_ABSTIME, &then, NULL);
512-
513513
if (ret != 0 && ret != EINTR)
514514
g_error ("%s: clock_nanosleep () returned %d", __func__, ret);
515515
} while (ret == EINTR && mono_atomic_load_i32 (&sampling_thread_running));

src/mono/mono/utils/mono-threads.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <mono/utils/mono-threads-debug.h>
3434
#include <mono/utils/os-event.h>
3535
#include <mono/utils/w32api.h>
36+
#include <glib.h>
3637

3738
#include <errno.h>
3839
#include <mono/utils/mono-errno.h>
@@ -1748,7 +1749,7 @@ mono_thread_info_sleep (guint32 ms, gboolean *alerted)
17481749
}
17491750

17501751
do {
1751-
ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
1752+
ret = g_clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
17521753
} while (ret != 0);
17531754
#elif HOST_WIN32
17541755
Sleep (ms);

0 commit comments

Comments
 (0)