Skip to content
Commits on Source (13)
  • Philip Withnall's avatar
    gtrace: Add G_GNUC_PRINTF annotation · 848a5343
    Philip Withnall authored
    
    
    This allows compilers to check the format placeholders properly. It
    fixes compilation on clang, which gives a warning about untrusted
    strings being passed on to subsequent functions which require format
    placeholders.
    
    Signed-off-by: default avatarPhilip Withnall <pwithnall@endlessos.org>
    848a5343
  • Emmanuele Bassi's avatar
    Merge branch 'backport-1718-clang-fix-glib-2-66' into 'glib-2-66' · cea485ac
    Emmanuele Bassi authored
    Backport !1718 “gtrace: Add G_GNUC_PRINTF annotation” to glib-2-66
    
    See merge request GNOME/glib!1720
    cea485ac
  • Claudio Saavedra's avatar
    gmain: g_main_context_check() can skip updating polled FD sources · fa45688f
    Claudio Saavedra authored and Philip Withnall's avatar Philip Withnall committed
    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. At
    the same time, document the assumptions about the ordering of the
    file descriptor records and array and make explicit in the documentation
    that the array needs to be passed to g_main_context_check() as it was
    received from g_main_context_query().
    
    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.
    
    While this patch was written independently, a similar fix for this
    bug was first submitted by Eugene M in GNOME/glib!562. Having a
    second fix that basically does the same is a reassurance that we
    are in the right here.
    
    Fixes #1592
    fa45688f
  • Philip Withnall's avatar
    Merge branch 'backport-1713-main-context-check-glib-2-66' into 'glib-2-66' · 614d4094
    Philip Withnall authored
    Backport !1713 “gmain: g_main_context_check() can skip updating polled FD sources” to glib-2-66
    
    See merge request GNOME/glib!1721
    614d4094
  • Michael Catanzaro's avatar
    Fix race in socketclient-slow test · 832d09ad
    Michael Catanzaro authored and Philip Withnall's avatar Philip Withnall committed
    This test ensures that g_socket_client_connect_to_host_async() fails if
    it is cancelled, but it's not cancelled until after 1 millisecond. Our
    CI testers are hitting that race window, and Milan is able to reproduce
    the crash locally as well. Switching it from 1ms to 0ms is enough for
    Milan to avoid the crash, but not enough for our CI, so let's move the
    cancellation to a GSocketClientEvent callback where the timing is
    completely deterministic.
    
    Hopefully fixes #2221
    832d09ad
  • Emmanuele Bassi's avatar
    Merge branch 'backport-1711-socket-fix-glib-2-66' into 'glib-2-66' · cfbab734
    Emmanuele Bassi authored
    Backport !1711 “Fix race in socketclient-slow test” to glib-2-66
    
    See merge request GNOME/glib!1723
    cfbab734
  • Simon McVittie (Collabora)'s avatar
    gdbus: Cope with sending fds in a message that takes multiple writes · 40cd84d9
    Simon McVittie (Collabora) authored and Philip Withnall's avatar Philip Withnall committed
    Suppose we are sending a 5K message with fds (so data->blob points
    to 5K of data, data->blob_size is 5K, and fd_list is non-null), but
    the kernel is only accepting up to 4K with each sendmsg().
    
    The first time we get into write_message_continue_writing(),
    data->total_written will be 0. We will try to write the entire message,
    plus the attached file descriptors; or if the stream doesn't support
    fd-passing (not a socket), we need to fail with
    "Tried sending a file descriptor on unsupported stream".
    
    Because the kernel didn't accept the entire message, we come back in.
    This time, we won't enter the Unix-specific block that involves sending
    fds, because now data->total_written is 4K, and it would be wrong to try
    to attach the same fds again. However, we also need to avoid failing
    with "Tried sending a file descriptor on unsupported stream" in this
    case. We just want to write out the data of the rest of the message,
    starting from (blob + total_written) (in this exaple, the last 1K).
    
    Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2074
    
    
    Signed-off-by: Simon McVittie (Collabora)'s avatarSimon McVittie <smcv@collabora.com>
    40cd84d9
  • Simon McVittie (Collabora)'s avatar
    gio/tests/gdbus-peer: Exercise fds attached to a large message · 60c3c948
    Simon McVittie (Collabora) authored and Philip Withnall's avatar Philip Withnall committed
    This incidentally also exercises the intended pattern for sending fds in
    a D-Bus message: the fd list is meant to contain exactly those fds that
    are referenced by a handle (type 'h') in the body of the message, with
    numeric handle value n corresponding to g_unix_fd_list_peek_fds(...)[n].
    
    Being able to send and receive file descriptors that are not referenced by
    a handle (as in OpenFile here) is a quirk of the GDBus API, and while it's
    entirely possible in the wire protocol, other D-Bus implementations like
    libdbus and sd-bus typically don't provide APIs that make this possible.
    
    Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/2074
    
    
    Signed-off-by: Simon McVittie (Collabora)'s avatarSimon McVittie <smcv@collabora.com>
    60c3c948
  • Simon McVittie's avatar
    Merge branch 'backport-1725-gdbus-fds-glib-2-66' into 'glib-2-66' · 4daaf303
    Simon McVittie authored
    Backport !1725 “gdbus: Cope with sending fds in a message that takes multiple writes” to glib-2-66
    
    See merge request GNOME/glib!1727
    4daaf303
  • Carlos Garnacho's avatar
    glocalfileinfo: Use a single timeout source at a time for hidden file cache · 92c19ebd
    Carlos Garnacho authored and Philip Withnall's avatar Philip Withnall committed
    As hidden file caches currently work, every look up on a directory caches
    its .hidden file contents, and sets a 5s timeout to prune the directory
    from the cache.
    
    This creates a problem for usecases like Tracker Miners, which is in the
    business of inspecting as many files as possible from as many directories
    as possible in the shortest time possible. One timeout is created for each
    directory, which possibly means gobbling thousands of entries in the hidden
    file cache. This adds as many GSources to the glib worker thread, with the
    involved CPU overhead in iterating those in its main context.
    
    To fix this, use a unique timeout that will keep running until the cache
    is empty. This will keep the overhead constant with many files/folders
    being queried.
    92c19ebd
  • Emmanuele Bassi's avatar
    Merge branch 'backport-1734-hidden-cache-glib-2-66' into 'glib-2-66' · e18a6a85
    Emmanuele Bassi authored
    Backport !1734 “glocalfileinfo: Use a single timeout source at a time for hidden file cache” to glib-2-66
    
    See merge request GNOME/glib!1736
    e18a6a85
  • Philip Withnall's avatar
    2.66.3 · 30c06eb5
    Philip Withnall authored
    
    
    Signed-off-by: default avatarPhilip Withnall <pwithnall@endlessos.org>
    30c06eb5
  • Simon McVittie's avatar
    New upstream version 2.66.3 · 32c9765e
    Simon McVittie authored
    32c9765e
Overview of changes in GLib 2.66.3
==================================
* Fix awkward bug with `GPollFD` handling in some situations (work by Claudio
Saavedra and Eugene M) (#1592)
* Fix sending FDs attached to very large D-Bus messages (work by Simon McVittie
and Giovanni Campagna) (#2074)
* Bugs fixed:
- #1592 Main loop ignores GPollFD sources when there is at least one source ready with priority higher than default one
- !1720 Backport !1718 “gtrace: Add G_GNUC_PRINTF annotation” to glib-2-66
- !1721 Backport !1713 “gmain: g_main_context_check() can skip updating polled FD sources” to glib-2-66
- !1723 Backport !1711 “Fix race in socketclient-slow test” to glib-2-66
- !1727 Backport !1725 “gdbus: Cope with sending fds in a message that takes multiple writes” to glib-2-66
- !1736 Backport !1734 “glocalfileinfo: Use a single timeout source at a time for hidden file cache” to glib-2-66
Overview of changes in GLib 2.66.2
==================================
......
......@@ -1085,8 +1085,11 @@ write_message_continue_writing (MessageToWriteData *data)
else
{
#ifdef G_OS_UNIX
if (fd_list != NULL)
if (data->total_written == 0 && fd_list != NULL)
{
/* We were trying to write byte 0 of the message, which needs
* the fd list to be attached to it, but this connection doesn't
* support doing that. */
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_FAILED,
......
......@@ -1547,15 +1547,45 @@ win32_get_file_user_info (const gchar *filename,
/* support for '.hidden' files */
G_LOCK_DEFINE_STATIC (hidden_cache);
static GHashTable *hidden_cache;
static GSource *hidden_cache_source = NULL; /* Under the hidden_cache lock */
static guint hidden_cache_ttl_secs = 5;
static guint hidden_cache_ttl_jitter_secs = 2;
typedef struct
{
GHashTable *hidden_files;
gint64 timestamp_secs;
} HiddenCacheData;
static gboolean
remove_from_hidden_cache (gpointer user_data)
{
HiddenCacheData *data;
GHashTableIter iter;
gboolean retval;
gint64 timestamp_secs;
G_LOCK (hidden_cache);
g_hash_table_remove (hidden_cache, user_data);
timestamp_secs = g_source_get_time (hidden_cache_source) / G_USEC_PER_SEC;
g_hash_table_iter_init (&iter, hidden_cache);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
{
if (timestamp_secs > data->timestamp_secs + hidden_cache_ttl_secs)
g_hash_table_iter_remove (&iter);
}
if (g_hash_table_size (hidden_cache) == 0)
{
g_clear_pointer (&hidden_cache_source, g_source_unref);
retval = G_SOURCE_REMOVE;
}
else
retval = G_SOURCE_CONTINUE;
G_UNLOCK (hidden_cache);
return FALSE;
return retval;
}
static GHashTable *
......@@ -1593,16 +1623,19 @@ read_hidden_file (const gchar *dirname)
}
static void
maybe_unref_hash_table (gpointer data)
free_hidden_file_data (gpointer user_data)
{
if (data != NULL)
g_hash_table_unref (data);
HiddenCacheData *data = user_data;
g_clear_pointer (&data->hidden_files, g_hash_table_unref);
g_free (data);
}
static gboolean
file_is_hidden (const gchar *path,
const gchar *basename)
{
HiddenCacheData *data;
gboolean result;
gchar *dirname;
gpointer table;
......@@ -1613,28 +1646,38 @@ file_is_hidden (const gchar *path,
if G_UNLIKELY (hidden_cache == NULL)
hidden_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, maybe_unref_hash_table);
g_free, free_hidden_file_data);
if (!g_hash_table_lookup_extended (hidden_cache, dirname,
NULL, &table))
NULL, (gpointer *) &data))
{
gchar *mydirname;
GSource *remove_from_cache_source;
data = g_new0 (HiddenCacheData, 1);
data->hidden_files = table = read_hidden_file (dirname);
data->timestamp_secs = g_get_monotonic_time () / G_USEC_PER_SEC;
g_hash_table_insert (hidden_cache,
mydirname = g_strdup (dirname),
table = read_hidden_file (dirname));
data);
remove_from_cache_source = g_timeout_source_new_seconds (5);
g_source_set_priority (remove_from_cache_source, G_PRIORITY_DEFAULT);
g_source_set_callback (remove_from_cache_source,
remove_from_hidden_cache,
mydirname,
NULL);
g_source_attach (remove_from_cache_source,
GLIB_PRIVATE_CALL (g_get_worker_context) ());
g_source_unref (remove_from_cache_source);
if (!hidden_cache_source)
{
hidden_cache_source =
g_timeout_source_new_seconds (hidden_cache_ttl_secs +
hidden_cache_ttl_jitter_secs);
g_source_set_priority (hidden_cache_source, G_PRIORITY_DEFAULT);
g_source_set_name (hidden_cache_source,
"[gio] remove_from_hidden_cache");
g_source_set_callback (hidden_cache_source,
remove_from_hidden_cache,
NULL, NULL);
g_source_attach (hidden_cache_source,
GLIB_PRIVATE_CALL (g_get_worker_context) ());
}
}
else
table = data->hidden_files;
result = table != NULL && g_hash_table_contains (table, basename);
......
......@@ -76,6 +76,12 @@ typedef struct
gboolean signal_received;
} PeerData;
/* This needs to be enough to usually take more than one write(),
* to reproduce
* <https://gitlab.gnome.org/GNOME/glib/-/issues/2074>.
* 1 MiB ought to be enough. */
#define BIG_MESSAGE_ARRAY_SIZE (1024 * 1024)
static const gchar *test_interface_introspection_xml =
"<node>"
" <interface name='org.gtk.GDBus.PeerTestInterface'>"
......@@ -88,6 +94,11 @@ static const gchar *test_interface_introspection_xml =
" <method name='OpenFile'>"
" <arg type='s' name='path' direction='in'/>"
" </method>"
" <method name='OpenFileWithBigMessage'>"
" <arg type='s' name='path' direction='in'/>"
" <arg type='h' name='handle' direction='out'/>"
" <arg type='ay' name='junk' direction='out'/>"
" </method>"
" <signal name='PeerSignal'>"
" <arg type='s' name='a_string'/>"
" </signal>"
......@@ -164,7 +175,8 @@ test_interface_method_call (GDBusConnection *connection,
g_dbus_method_invocation_return_value (invocation, NULL);
}
else if (g_strcmp0 (method_name, "OpenFile") == 0)
else if (g_strcmp0 (method_name, "OpenFile") == 0 ||
g_strcmp0 (method_name, "OpenFileWithBigMessage") == 0)
{
#ifdef G_OS_UNIX
const gchar *path;
......@@ -190,6 +202,21 @@ test_interface_method_call (GDBusConnection *connection,
g_object_unref (fd_list);
g_object_unref (invocation);
if (g_strcmp0 (method_name, "OpenFileWithBigMessage") == 0)
{
char *junk;
junk = g_new0 (char, BIG_MESSAGE_ARRAY_SIZE);
g_dbus_message_set_body (reply,
g_variant_new ("(h@ay)",
0,
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
junk,
BIG_MESSAGE_ARRAY_SIZE,
1)));
g_free (junk);
}
error = NULL;
g_dbus_connection_send_message (connection,
reply,
......@@ -723,6 +750,7 @@ do_test_peer (void)
const gchar *s;
GThread *service_thread;
gulong signal_handler_id;
gsize i;
memset (&data, '\0', sizeof (PeerData));
data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
......@@ -843,73 +871,116 @@ do_test_peer (void)
g_assert_cmpint (data.num_method_calls, ==, 3);
g_signal_handler_disconnect (proxy, signal_handler_id);
/* check for UNIX fd passing */
/*
* Check for UNIX fd passing.
*
* The first time through, we use a very simple method call. Note that
* because this does not have a G_VARIANT_TYPE_HANDLE in the message body
* to refer to the fd, it is a GDBus-specific idiom that would not
* interoperate with libdbus or sd-bus
* (see <https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1726>).
*
* The second time, we call a method that returns a fd attached to a
* large message, to reproduce
* <https://gitlab.gnome.org/GNOME/glib/-/issues/2074>. It also happens
* to follow the more usual pattern for D-Bus messages containing a
* G_VARIANT_TYPE_HANDLE to refer to attached fds.
*/
for (i = 0; i < 2; i++)
{
#ifdef G_OS_UNIX
{
GDBusMessage *method_call_message;
GDBusMessage *method_reply_message;
GUnixFDList *fd_list;
gint fd;
gchar *buf;
gsize len;
gchar *buf2;
gsize len2;
const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL);
method_call_message = g_dbus_message_new_method_call (NULL, /* name */
"/org/gtk/GDBus/PeerTestObject",
"org.gtk.GDBus.PeerTestInterface",
"OpenFile");
g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile));
error = NULL;
method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
method_call_message,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-1,
NULL, /* out_serial */
NULL, /* cancellable */
&error);
g_assert_no_error (error);
g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
g_assert (fd_list != NULL);
g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
error = NULL;
fd = g_unix_fd_list_get (fd_list, 0, &error);
g_assert_no_error (error);
g_object_unref (method_call_message);
g_object_unref (method_reply_message);
GDBusMessage *method_call_message;
GDBusMessage *method_reply_message;
GUnixFDList *fd_list;
gint fd;
gchar *buf;
gsize len;
gchar *buf2;
gsize len2;
const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL);
const char *method = "OpenFile";
GVariant *body;
if (i == 1)
method = "OpenFileWithBigMessage";
method_call_message = g_dbus_message_new_method_call (NULL, /* name */
"/org/gtk/GDBus/PeerTestObject",
"org.gtk.GDBus.PeerTestInterface",
method);
g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile));
error = NULL;
method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
method_call_message,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-1,
NULL, /* out_serial */
NULL, /* cancellable */
&error);
g_assert_no_error (error);
g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
error = NULL;
len = 0;
buf = read_all_from_fd (fd, &len, &error);
g_assert_no_error (error);
g_assert (buf != NULL);
close (fd);
body = g_dbus_message_get_body (method_reply_message);
error = NULL;
g_file_get_contents (testfile,
&buf2,
&len2,
&error);
g_assert_no_error (error);
g_assert_cmpmem (buf, len, buf2, len2);
g_free (buf2);
g_free (buf);
}
if (i == 1)
{
gint32 handle = -1;
GVariant *junk = NULL;
g_assert_cmpstr (g_variant_get_type_string (body), ==, "(hay)");
g_variant_get (body, "(h@ay)", &handle, &junk);
g_assert_cmpint (handle, ==, 0);
g_assert_cmpuint (g_variant_n_children (junk), ==, BIG_MESSAGE_ARRAY_SIZE);
g_variant_unref (junk);
}
else
{
g_assert_null (body);
}
fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
g_assert (fd_list != NULL);
g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
error = NULL;
fd = g_unix_fd_list_get (fd_list, 0, &error);
g_assert_no_error (error);
g_object_unref (method_call_message);
g_object_unref (method_reply_message);
error = NULL;
len = 0;
buf = read_all_from_fd (fd, &len, &error);
g_assert_no_error (error);
g_assert (buf != NULL);
close (fd);
error = NULL;
g_file_get_contents (testfile,
&buf2,
&len2,
&error);
g_assert_no_error (error);
g_assert_cmpmem (buf, len, buf2, len2);
g_free (buf2);
g_free (buf);
#else
error = NULL;
result = g_dbus_proxy_call_sync (proxy,
"OpenFile",
g_variant_new ("(s)", "boo"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, /* GCancellable */
&error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
g_assert (result == NULL);
g_error_free (error);
/* We do the same number of iterations on non-Unix, so that
* the method call count will match. In this case we use
* OpenFile both times, because the difference between this
* and OpenFileWithBigMessage is only relevant on Unix. */
error = NULL;
result = g_dbus_proxy_call_sync (proxy,
"OpenFile",
g_variant_new ("(s)", "boo"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, /* GCancellable */
&error);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
g_assert (result == NULL);
g_error_free (error);
#endif /* G_OS_UNIX */
}
/* Check that g_socket_get_credentials() work - (though this really
* should be in socket.c)
......@@ -1017,7 +1088,7 @@ do_test_peer (void)
g_variant_get (result, "(&s)", &s);
g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
g_variant_unref (result);
g_assert_cmpint (data.num_method_calls, ==, 5);
g_assert_cmpint (data.num_method_calls, ==, 6);
#if 0
/* TODO: THIS TEST DOESN'T WORK YET */
......
......@@ -79,23 +79,26 @@ on_connected_cancelled (GObject *source_object,
g_main_loop_quit (user_data);
}
static int
on_timer (GCancellable *cancel)
typedef struct
{
g_cancellable_cancel (cancel);
return G_SOURCE_REMOVE;
}
GCancellable *cancellable;
gboolean completed;
} EventCallbackData;
static void
on_event (GSocketClient *client,
GSocketClientEvent event,
GSocketConnectable *connectable,
GIOStream *connection,
gboolean *got_completed_event)
EventCallbackData *data)
{
if (event == G_SOCKET_CLIENT_COMPLETE)
if (data->cancellable && event == G_SOCKET_CLIENT_CONNECTED)
{
g_cancellable_cancel (data->cancellable);
}
else if (event == G_SOCKET_CLIENT_COMPLETE)
{
*got_completed_event = TRUE;
data->completed = TRUE;
g_assert_null (connection);
}
}
......@@ -108,8 +111,7 @@ test_happy_eyeballs_cancel_delayed (void)
GError *error = NULL;
guint16 port;
GMainLoop *loop;
GCancellable *cancel;
gboolean got_completed_event = FALSE;
EventCallbackData data = { NULL, FALSE };
/* This just tests that cancellation works as expected, still emits the completed signal,
* and never returns a connection */
......@@ -122,17 +124,16 @@ test_happy_eyeballs_cancel_delayed (void)
g_socket_service_start (service);
client = g_socket_client_new ();
cancel = g_cancellable_new ();
g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop);
g_timeout_add (1, (GSourceFunc) on_timer, cancel);
g_signal_connect (client, "event", G_CALLBACK (on_event), &got_completed_event);
data.cancellable = g_cancellable_new ();
g_socket_client_connect_to_host_async (client, "localhost", port, data.cancellable, on_connected_cancelled, loop);
g_signal_connect (client, "event", G_CALLBACK (on_event), &data);
g_main_loop_run (loop);
g_assert_true (got_completed_event);
g_assert_true (data.completed);
g_main_loop_unref (loop);
g_object_unref (service);
g_object_unref (client);
g_object_unref (cancel);
g_object_unref (data.cancellable);
}
static void
......@@ -144,7 +145,7 @@ test_happy_eyeballs_cancel_instant (void)
guint16 port;
GMainLoop *loop;
GCancellable *cancel;
gboolean got_completed_event = FALSE;
EventCallbackData data = { NULL, FALSE };
/* This tests the same things as above, test_happy_eyeballs_cancel_delayed(), but
* with different timing since it sends an already cancelled cancellable */
......@@ -160,10 +161,10 @@ test_happy_eyeballs_cancel_instant (void)
cancel = g_cancellable_new ();
g_cancellable_cancel (cancel);
g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop);
g_signal_connect (client, "event", G_CALLBACK (on_event), &got_completed_event);
g_signal_connect (client, "event", G_CALLBACK (on_event), &data);
g_main_loop_run (loop);
g_assert_true (got_completed_event);
g_assert_true (data.completed);
g_main_loop_unref (loop);
g_object_unref (service);
g_object_unref (client);
......
......@@ -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)
......
......@@ -54,7 +54,7 @@ void (g_trace_mark) (gint64 begin_time_nsec,
const gchar *group,
const gchar *name,
const gchar *message_format,
...);
...) G_GNUC_PRINTF (5, 6);
#ifndef HAVE_SYSPROF
/* Optimise the whole call out */
......
......@@ -1541,6 +1541,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
......@@ -2034,6 +2090,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);
......
project('glib', 'c', 'cpp',
version : '2.66.2',
version : '2.66.3',
# NOTE: We keep this pinned at 0.49 because that's what Debian 10 ships
meson_version : '>= 0.49.2',
default_options : [
......