Merge branch 'g_main_context_check_skipping_pollrec_updates' into 'master'

gmain: g_main_context_check() can skip updating polled FD sources

Closes #1592

See merge request GNOME/glib!1713
This commit is contained in:
Philip Withnall 2020-10-26 14:12:04 +00:00
commit ec222422c0
2 changed files with 87 additions and 2 deletions

View File

@ -3733,7 +3733,10 @@ g_main_context_prepare (GMainContext *context,
* store #GPollFD records that need to be polled.
* @n_fds: (in): length of @fds.
*
* Determines information necessary to poll this main loop.
* Determines information necessary to poll this main loop. You should
* be careful to pass the resulting @fds array and its length @n_fds
* as is when calling g_main_context_check(), as this function relies
* on assumptions made when the array is filled.
*
* You must have successfully acquired the context with
* g_main_context_acquire() before you may call this function.
@ -3757,6 +3760,10 @@ g_main_context_query (GMainContext *context,
TRACE (GLIB_MAIN_CONTEXT_BEFORE_QUERY (context, max_priority));
/* fds is filled sequentially from poll_records. Since poll_records
* are incrementally sorted by file descriptor identifier, fds will
* also be incrementally sorted.
*/
n_poll = 0;
lastpollrec = NULL;
for (pollrec = context->poll_records; pollrec; pollrec = pollrec->next)
@ -3771,6 +3778,10 @@ g_main_context_query (GMainContext *context,
*/
events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL);
/* This optimization --using the same GPollFD to poll for more
* than one poll record-- relies on the poll records being
* incrementally sorted.
*/
if (lastpollrec && pollrec->fd->fd == lastpollrec->fd->fd)
{
if (n_poll - 1 < n_fds)
@ -3816,7 +3827,10 @@ g_main_context_query (GMainContext *context,
* the last call to g_main_context_query()
* @n_fds: return value of g_main_context_query()
*
* Passes the results of polling back to the main loop.
* Passes the results of polling back to the main loop. You should be
* careful to pass @fds and its length @n_fds as received from
* g_main_context_query(), as this functions relies on assumptions
* on how @fds is filled.
*
* You must have successfully acquired the context with
* g_main_context_acquire() before you may call this function.
@ -3871,10 +3885,22 @@ g_main_context_check (GMainContext *context,
return FALSE;
}
/* The linear iteration below relies on the assumption that both
* poll records and the fds array are incrementally sorted by file
* descriptor identifier.
*/
pollrec = context->poll_records;
i = 0;
while (pollrec && i < n_fds)
{
/* Make sure that fds is sorted by file descriptor identifier. */
g_assert (i <= 0 || fds[i - 1].fd < fds[i].fd);
/* Skip until finding 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 +3911,7 @@ g_main_context_check (GMainContext *context,
pollrec = pollrec->next;
}
/* Iterate to next GPollFD. */
i++;
}
@ -4495,6 +4522,7 @@ g_main_context_add_poll_unlocked (GMainContext *context,
newrec->fd = fd;
newrec->priority = priority;
/* Poll records are incrementally sorted by file descriptor identifier. */
prevrec = NULL;
nextrec = context->poll_records;
while (nextrec)

View File

@ -1542,6 +1542,62 @@ 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;
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1592");
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 should have been dispatched. */
g_assert_true (s3);
g_main_loop_unref (loop);
close (fd1);
close (fd2);
}
#endif
#ifdef G_OS_UNIX
@ -2035,6 +2091,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);