[glib] gdbus: Implement g_dbus_connection_get_last_serial()



commit 032e8dabd15133952c7c4f9da05605380b17f79f
Author: Tomas Bzatek <tbzatek redhat com>
Date:   Wed Jun 6 19:44:39 2012 +0200

    gdbus: Implement g_dbus_connection_get_last_serial()
    
    This patch brings an ability to retrieve serial number of the last
    message sent within the current thread.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=676825

 docs/reference/gio/gio-sections.txt |    1 +
 gio/gdbusconnection.c               |   49 +++++++++++++++++++
 gio/gdbusconnection.h               |    4 ++
 gio/gio.symbols                     |    1 +
 gio/tests/gdbus-connection.c        |   90 +++++++++++++++++++++++++++++++++++
 5 files changed, 145 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 5f4a7df..5e25b5d 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -2629,6 +2629,7 @@ g_dbus_connection_get_unique_name
 GDBusCapabilityFlags
 g_dbus_connection_get_capabilities
 g_dbus_connection_get_peer_credentials
+g_dbus_connection_get_last_serial
 GDBusCallFlags
 g_dbus_connection_call
 g_dbus_connection_call_finish
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index d886f8f..7f421c4 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -444,6 +444,9 @@ struct _GDBusConnection
   GHashTable *map_object_path_to_es;  /* gchar* -> ExportedSubtree* */
   GHashTable *map_id_to_es;           /* guint  -> ExportedSubtree* */
 
+  /* Map used for storing last used serials for each thread, protected by @lock */
+  GHashTable *map_thread_to_last_serial;
+
   /* Structure used for message filters, protected by @lock */
   GPtrArray *filters;
 
@@ -672,6 +675,8 @@ g_dbus_connection_finalize (GObject *object)
   g_hash_table_unref (connection->map_id_to_es);
   g_hash_table_unref (connection->map_object_path_to_es);
 
+  g_hash_table_unref (connection->map_thread_to_last_serial);
+
   g_main_context_unref (connection->main_context_at_construction);
 
   g_free (connection->machine_id);
@@ -1090,6 +1095,9 @@ g_dbus_connection_init (GDBusConnection *connection)
   connection->map_id_to_es = g_hash_table_new (g_direct_hash,
                                                g_direct_equal);
 
+  connection->map_thread_to_last_serial = g_hash_table_new (g_direct_hash,
+                                                            g_direct_equal);
+
   connection->main_context_at_construction = g_main_context_ref_thread_default ();
 
   connection->filters = g_ptr_array_new ();
@@ -1571,6 +1579,38 @@ g_dbus_connection_close_sync (GDBusConnection     *connection,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+/**
+ * g_dbus_connection_get_last_serial:
+ * @connection: A #GDBusConnection.
+ *
+ * Retrieves the last serial number assigned to a #GDBusMessage on
+ * the current thread. This includes messages sent via both low-level
+ * API such as g_dbus_connection_send_message() as well as
+ * high-level API such as g_dbus_connection_emit_signal(),
+ * g_dbus_connection_call() or g_dbus_proxy_call().
+ *
+ * Returns: the last used serial or zero when no message has been sent
+ * within the current thread.
+ *
+ * Since: 2.34
+ */
+guint32
+g_dbus_connection_get_last_serial (GDBusConnection *connection)
+{
+  guint32 ret;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+
+  CONNECTION_LOCK (connection);
+  ret = GPOINTER_TO_UINT (g_hash_table_lookup (connection->map_thread_to_last_serial,
+                                               g_thread_self ()));
+  CONNECTION_UNLOCK (connection);
+
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /* Can be called by any thread, with the connection lock held */
 static gboolean
 g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
@@ -1645,6 +1685,15 @@ g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
   if (out_serial != NULL)
     *out_serial = serial_to_use;
 
+  /* store used serial for the current thread */
+  /* TODO: watch the thread disposal and remove associated record
+   *       from hashtable
+   *  - see https://bugzilla.gnome.org/show_bug.cgi?id=676825#c7
+   */
+  g_hash_table_replace (connection->map_thread_to_last_serial,
+                        g_thread_self (),
+                        GUINT_TO_POINTER (serial_to_use));
+
   if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
     g_dbus_message_set_serial (message, serial_to_use);
 
diff --git a/gio/gdbusconnection.h b/gio/gdbusconnection.h
index 9b164d5..6c1ec5c 100644
--- a/gio/gdbusconnection.h
+++ b/gio/gdbusconnection.h
@@ -89,6 +89,10 @@ GIOStream       *g_dbus_connection_get_stream                 (GDBusConnection
 const gchar     *g_dbus_connection_get_guid                   (GDBusConnection    *connection);
 const gchar     *g_dbus_connection_get_unique_name            (GDBusConnection    *connection);
 GCredentials    *g_dbus_connection_get_peer_credentials       (GDBusConnection    *connection);
+
+GLIB_AVAILABLE_IN_2_34
+guint32          g_dbus_connection_get_last_serial            (GDBusConnection    *connection);
+
 gboolean         g_dbus_connection_get_exit_on_close          (GDBusConnection    *connection);
 void             g_dbus_connection_set_exit_on_close          (GDBusConnection    *connection,
                                                                gboolean            exit_on_close);
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 5c8bbd1..c30c8d1 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1233,6 +1233,7 @@ g_dbus_connection_get_capabilities
 g_dbus_connection_get_exit_on_close
 g_dbus_connection_get_guid
 g_dbus_connection_get_peer_credentials
+g_dbus_connection_get_last_serial
 g_dbus_connection_get_stream
 g_dbus_connection_get_unique_name
 g_dbus_connection_is_closed
diff --git a/gio/tests/gdbus-connection.c b/gio/tests/gdbus-connection.c
index 39c915c..353b09e 100644
--- a/gio/tests/gdbus-connection.c
+++ b/gio/tests/gdbus-connection.c
@@ -995,6 +995,95 @@ test_connection_filter (void)
   session_bus_down ();
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+#define NUM_THREADS 50
+
+static void
+send_bogus_message (GDBusConnection *c, guint32 *out_serial)
+{
+  GDBusMessage *m;
+  GError *error;
+
+  m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
+                                      "/org/freedesktop/DBus", /* path */
+                                      "org.freedesktop.DBus", /* interface */
+                                      "GetNameOwner");
+  g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
+  error = NULL;
+  g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, out_serial, &error);
+  g_assert_no_error (error);
+}
+
+static gpointer
+serials_thread_func (GDBusConnection *c)
+{
+  guint32 message_serial;
+
+  /* No calls on this thread yet */
+  g_assert_cmpint (g_dbus_connection_get_last_serial(c), ==, 0);
+
+  /* Send a bogus message and store its serial */
+  message_serial = 0;
+  send_bogus_message (c, &message_serial);
+
+  /* Give it some time to actually send the message out */
+  g_usleep (250000);
+
+  g_assert_cmpint (g_dbus_connection_get_last_serial(c), !=, 0);
+  g_assert_cmpint (g_dbus_connection_get_last_serial(c), ==, message_serial);
+
+  return NULL;
+}
+
+static void
+test_connection_serials (void)
+{
+  GDBusConnection *c;
+  GError *error;
+  GThread *pool[NUM_THREADS];
+  int i;
+
+  session_bus_up ();
+
+  error = NULL;
+  c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (c != NULL);
+
+  /* Status after initialization */
+  g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 1);
+
+  /* Send a bogus message */
+  send_bogus_message (c, NULL);
+  g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 2);
+
+  /* Start the threads */
+  for (i = 0; i < NUM_THREADS; i++)
+    pool[i] = g_thread_new (NULL, (GThreadFunc) serials_thread_func, c);
+
+  /* Wait until threads are finished */
+  for (i = 0; i < NUM_THREADS; i++)
+    {
+      g_thread_join (pool[i]);
+      g_thread_unref (pool[i]);
+    }
+
+  /* No calls in between on this thread, should be the last value */
+  g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 2);
+
+  send_bogus_message (c, NULL);
+
+  /* All above calls + calls in threads */
+  g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 3 + NUM_THREADS);
+
+  g_object_unref (c);
+
+  session_bus_down ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 test_connection_basic (void)
 {
@@ -1066,5 +1155,6 @@ main (int   argc,
   g_test_add_func ("/gdbus/connection/send", test_connection_send);
   g_test_add_func ("/gdbus/connection/signals", test_connection_signals);
   g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
+  g_test_add_func ("/gdbus/connection/serials", test_connection_serials);
   return g_test_run();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]