mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-12 18:55:12 +01:00
glib: reset errno to 0 when futex() returns EAGAIN
This commit is contained in:
parent
49c2fe77c1
commit
b74ff41bef
@ -54,6 +54,12 @@ struct _GRealThread
|
|||||||
/* Wrapper macro to call `futex_time64` and/or `futex` with simple
|
/* Wrapper macro to call `futex_time64` and/or `futex` with simple
|
||||||
* parameters and without returning the return value.
|
* parameters and without returning the return value.
|
||||||
*
|
*
|
||||||
|
* We expect futex to sometimes return EAGAIN due to the race
|
||||||
|
* between the caller checking the current value and deciding to
|
||||||
|
* do the futex op. To avoid splattering errno on success, we
|
||||||
|
* restore the original errno if EAGAIN is seen. See also:
|
||||||
|
* https://gitlab.gnome.org/GNOME/glib/-/issues/3034
|
||||||
|
*
|
||||||
* If the `futex_time64` syscall does not exist (`ENOSYS`), we retry again
|
* If the `futex_time64` syscall does not exist (`ENOSYS`), we retry again
|
||||||
* with the normal `futex` syscall. This can happen if newer kernel headers
|
* with the normal `futex` syscall. This can happen if newer kernel headers
|
||||||
* are used than the kernel that is actually running.
|
* are used than the kernel that is actually running.
|
||||||
@ -70,23 +76,37 @@ struct _GRealThread
|
|||||||
if (res < 0 && errno == ENOSYS) \
|
if (res < 0 && errno == ENOSYS) \
|
||||||
{ \
|
{ \
|
||||||
errno = saved_errno; \
|
errno = saved_errno; \
|
||||||
syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \
|
res = syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
if (res < 0 && errno == EAGAIN) \
|
||||||
|
{ \
|
||||||
|
errno = saved_errno; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
G_STMT_END
|
G_STMT_END
|
||||||
#elif defined(__NR_futex_time64)
|
#elif defined(__NR_futex_time64)
|
||||||
#define g_futex_simple(uaddr, futex_op, ...) \
|
#define g_futex_simple(uaddr, futex_op, ...) \
|
||||||
G_STMT_START \
|
G_STMT_START \
|
||||||
{ \
|
{ \
|
||||||
syscall (__NR_futex_time64, uaddr, (gsize) futex_op, __VA_ARGS__); \
|
int saved_errno = errno; \
|
||||||
} \
|
int res = syscall (__NR_futex_time64, uaddr, (gsize) futex_op, __VA_ARGS__); \
|
||||||
|
if (res < 0 && errno == EAGAIN) \
|
||||||
|
{ \
|
||||||
|
errno = saved_errno; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
G_STMT_END
|
G_STMT_END
|
||||||
#elif defined(__NR_futex)
|
#elif defined(__NR_futex)
|
||||||
#define g_futex_simple(uaddr, futex_op, ...) \
|
#define g_futex_simple(uaddr, futex_op, ...) \
|
||||||
G_STMT_START \
|
G_STMT_START \
|
||||||
{ \
|
{ \
|
||||||
syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \
|
int saved_errno = errno; \
|
||||||
} \
|
int res = syscall (__NR_futex, uaddr, (gsize) futex_op, __VA_ARGS__); \
|
||||||
|
if (res < 0 && errno == EAGAIN) \
|
||||||
|
{ \
|
||||||
|
errno = saved_errno; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
G_STMT_END
|
G_STMT_END
|
||||||
#else /* !defined(__NR_futex) && !defined(__NR_futex_time64) */
|
#else /* !defined(__NR_futex) && !defined(__NR_futex_time64) */
|
||||||
#error "Neither __NR_futex nor __NR_futex_time64 are defined but were found by meson"
|
#error "Neither __NR_futex nor __NR_futex_time64 are defined but were found by meson"
|
||||||
|
@ -159,6 +159,63 @@ test_mutex5 (void)
|
|||||||
g_assert (owners[i] == NULL);
|
g_assert (owners[i] == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
test_mutex_errno_func (gpointer data)
|
||||||
|
{
|
||||||
|
GMutex *m = data;
|
||||||
|
|
||||||
|
g_test_summary ("Validates that errno is not touched upon return");
|
||||||
|
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3034");
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
g_mutex_lock (m);
|
||||||
|
g_assert_cmpint (errno, ==, 0);
|
||||||
|
|
||||||
|
g_thread_yield ();
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
g_mutex_unlock (m);
|
||||||
|
g_assert_cmpint (errno, ==, 0);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (g_mutex_trylock (m))
|
||||||
|
{
|
||||||
|
g_assert_cmpint (errno, ==, 0);
|
||||||
|
|
||||||
|
g_thread_yield ();
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
g_mutex_unlock (m);
|
||||||
|
g_assert_cmpint (errno, ==, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_mutex_errno (void)
|
||||||
|
{
|
||||||
|
gsize i;
|
||||||
|
GThread *threads[THREADS];
|
||||||
|
GMutex m;
|
||||||
|
|
||||||
|
g_mutex_init (&m);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (threads); i++)
|
||||||
|
{
|
||||||
|
threads[i] = g_thread_new ("test_mutex_errno",
|
||||||
|
test_mutex_errno_func, &m);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (threads); i++)
|
||||||
|
{
|
||||||
|
g_thread_join (threads[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gint count_to = 0;
|
static gint count_to = 0;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -226,6 +283,7 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/thread/mutex3", test_mutex3);
|
g_test_add_func ("/thread/mutex3", test_mutex3);
|
||||||
g_test_add_func ("/thread/mutex4", test_mutex4);
|
g_test_add_func ("/thread/mutex4", test_mutex4);
|
||||||
g_test_add_func ("/thread/mutex5", test_mutex5);
|
g_test_add_func ("/thread/mutex5", test_mutex5);
|
||||||
|
g_test_add_func ("/thread/mutex/errno", test_mutex_errno);
|
||||||
|
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user