[glib/g_main_context_check_skipping_pollrec_updates] gmain: g_main_context_check() can skip updating polled FD sources
- From: Claudio Saavedra <csaavedra src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/g_main_context_check_skipping_pollrec_updates] gmain: g_main_context_check() can skip updating polled FD sources
- Date: Wed, 21 Oct 2020 10:30:21 +0000 (UTC)
commit f9575121f897d5068d2cf3bdb3b9131353207cd8
Author: Claudio Saavedra <csaavedra igalia com>
Date: Wed Oct 21 13:19:42 2020 +0300
gmain: g_main_context_check() can skip updating polled FD sources
If there is a file descriptor source that has a lower priority
than the one for sources that are going to be dispatched,
all subsequent file descriptor sources (internally sorted by
file descriptor identifier) do not get an update in their GPollRec
and later on wrong sources can be dispatched.
Fix this by first finding the first GPollRec that matches the current
GPollFD, instead of relying on it to be the current one. Additionally
add a few comments to explain how the iteration works.
Added a new test that reproduces the bug by creating two file
descriptor sources and an idle one. Since the first
file descriptor created has a lower identifier and a low priority,
the second one is not dispatched even when it has the same, higher,
priority as the idle source. After fixing this bug, both
higher priority sources are dispatched as expected.
glib/gmain.c | 6 ++++++
glib/tests/mainloop.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index 4d057badf..511a7421e 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -3875,6 +3875,11 @@ g_main_context_check (GMainContext *context,
i = 0;
while (pollrec && i < n_fds)
{
+ /* First find the first GPollRec matching the current GPollFD. */
+ while (pollrec && pollrec->fd->fd != fds[i].fd)
+ pollrec = pollrec->next;
+
+ /* Update all consecutive GPollRecs that match. */
while (pollrec && pollrec->fd->fd == fds[i].fd)
{
if (pollrec->priority <= max_priority)
@@ -3885,6 +3890,7 @@ g_main_context_check (GMainContext *context,
pollrec = pollrec->next;
}
+ /* Iterate to next GPollFD. */
i++;
}
diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c
index ec96bfa8a..37a171d36 100644
--- a/glib/tests/mainloop.c
+++ b/glib/tests/mainloop.c
@@ -1542,6 +1542,60 @@ test_unix_file_poll (void)
close (fd);
}
+static void
+test_unix_fd_priority (void)
+{
+ gint fd1, fd2;
+ GMainLoop *loop;
+ GSource *source;
+
+ gint s1 = 0;
+ gboolean s2 = FALSE, s3 = FALSE;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, count_calls, &s1, NULL);
+ g_source_set_priority (source, 0);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ fd1 = open ("/dev/random", O_RDONLY);
+ g_assert_cmpint (fd1, >=, 0);
+ source = g_unix_fd_source_new (fd1, G_IO_IN);
+ g_source_set_callback (source, G_SOURCE_FUNC (flag_bool), &s2, NULL);
+ g_source_set_priority (source, 10);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ fd2 = open ("/dev/random", O_RDONLY);
+ g_assert_cmpint (fd2, >=, 0);
+ source = g_unix_fd_source_new (fd2, G_IO_IN);
+ g_source_set_callback (source, G_SOURCE_FUNC (flag_bool), &s3, NULL);
+ g_source_set_priority (source, 0);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ /* This tests a bug that depends on the source with the lowest FD
+ identifier to have the lowest priority. Make sure that this is
+ the case. */
+ g_assert_cmpint (fd1, <, fd2);
+
+ g_assert_true (g_main_context_iteration (NULL, FALSE));
+
+ /* Idle source should have been dispatched. */
+ g_assert_cmpint (s1, ==, 1);
+ /* Low priority FD source shouldn't have been dispatched. */
+ g_assert_false (s2);
+ /* Default priority FD source have been dispatched. */
+ g_assert_true (s3);
+
+ g_main_loop_unref (loop);
+
+ close (fd1);
+ close (fd2);
+}
+
#endif
#ifdef G_OS_UNIX
@@ -2035,6 +2089,7 @@ main (int argc, char *argv[])
g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
g_test_add_func ("/mainloop/wait", test_mainloop_wait);
g_test_add_func ("/mainloop/unix-file-poll", test_unix_file_poll);
+ g_test_add_func ("/mainloop/unix-fd-priority", test_unix_fd_priority);
#endif
g_test_add_func ("/mainloop/nfds", test_nfds);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]