After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 662718 - GDBusInterfaceSkeleton should be able to export on multiple GDBusConnections
GDBusInterfaceSkeleton should be able to export on multiple GDBusConnections
Status: RESOLVED OBSOLETE
Product: glib
Classification: Platform
Component: gdbus
unspecified
Other Linux
: Normal normal
: ---
Assigned To: David Zeuthen (not reading bugmail)
gtkdev
Depends on:
Blocks:
 
 
Reported: 2011-10-25 22:11 UTC by Tristan Van Berkom
Modified: 2018-05-24 13:29 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Patch to allow GDBusInterfaceSkeleton to export itself on multiple GDBusConnections (51.99 KB, patch)
2011-10-25 22:11 UTC, Tristan Van Berkom
none Details | Review
Patch to allow GDBusInterfaceSkeleton to export itself on multiple GDBusConnections [take 2] (36.15 KB, patch)
2011-10-27 02:57 UTC, Tristan Van Berkom
needs-work Details | Review
Patch to allow GDBusInterfaceSkeleton to export itself on multiple GDBusConnections [take 3] (32.84 KB, patch)
2011-10-27 23:23 UTC, Tristan Van Berkom
reviewed Details | Review
Patch to make GDBusObjectManagerServer manage multiple connections (34.98 KB, patch)
2011-10-27 23:28 UTC, Tristan Van Berkom
none Details | Review

Description Tristan Van Berkom 2011-10-25 22:11:01 UTC
Created attachment 199979 [details] [review]
Patch to allow GDBusInterfaceSkeleton to export itself on multiple GDBusConnections

This makes sense particularly when implementing a peer to peer setup
with no object manager and you want to use simple generated code.

Adding a patch that achieves this which comes with a test case.

The test case shows the usage of a GDBusServer directly with
a generated GDBusInterfaceSkeleton (and it shows that it can
handle multiple connections).
Comment 1 David Zeuthen (not reading bugmail) 2011-10-26 16:13:21 UTC
Hey, thanks for the patch, I just read through it and it generally looks good.

However, I don't think we want to deprecate anything - the 99% case is when using a bus connection so supporting the 1% case should not make the 99% case more difficult.

IOW, I think what we want is

 - docs for g_dbus_interface_skeleton_export() should say that
   it can be called multiple times but the object path must be
   the same (return G_IO_ERROR_INVALID_ARGUMENT if it isn't)

 - new method: GList *g_dbus_interface_skeleton_get_connections()

 - docs for g_dbus_interface_skeleton_get_connection() to say
   that the GDBusConnection from the first GDBusConnection
   is returned

 - docs for g_dbus_interface_skeleton_unexport() should say that
   it unexports on all the connections

 - new method: g_dbus_interface_skeleton_unexport_from_connection() 

Also

 - GDBus code is explicit when testing pointers, e.g.
   +  while (interface->priv->connections)
   needs to be
   +  while (interface->priv->connections != NULL)
   (this is in other places too)

 - if we are adding this functionality to GDBusInterfaceSkeleton
   we should also add it to GDBusObjectManagerServer - for this
   I suggest

   - deprecating
     - g_dbus_object_manager_server_get_connection()
     - g_dbus_object_manager_server_set_connection()

   - adding
     - g_dbus_object_manager_server_get_connections()
     - g_dbus_object_manager_server_add_connection()
     - g_dbus_object_manager_server_remove_connection()

 - need a test case for all this - probably in gio/tests/gdbus-peer.c
   - this should use GDBusObjectManagerServer and the existing
     generated types - this will also make the code relatively
     small

 - Not sure we need an example like gdbus-example-codegen-peer.c
   since peer-to-peer connections are relatively rare ... and
   the test case will already serve as a good test case

Finally I'm curious what you want to use this for (if you can disclose it please do - otherwise no problem).
Comment 2 Tristan Van Berkom 2011-10-27 02:57:14 UTC
Created attachment 200075 [details] [review]
Patch to allow GDBusInterfaceSkeleton to export itself on multiple GDBusConnections [take 2]

Ok I started by handling all of the api changes for GDBusInterfaceSkeleton.

Then I spent an embarrassingly long time trying to accomplish the same
with GDBusObjectManagerServer.

What I ended up with is a modified version of the first patch with
you API changes included and an added test to gdbus-peer.c.

The first challenge was that the object manager server does not seem
to emit the InterfacesAdded signal every time a new connection
is set (I had to adjust the code so that was done, this cost me
a few hours...).

And then when I finally put it all together in the test case,
after debugging and figuring why it doesn't work... I found
that GDBusObjectManagerClient is extremely 'bus' centric, it
wont go and query for the objects on the connection until there
is a "name-owner" that appears on it's internal proxy.

not an insurmountable problem, but much code to re-write in
GDBusObjectManagerClient I think to make it happen...

I do have a patch sitting on the side for GDBusObjectManagerServer
but it seems pointless unless you have a good full day or two to
sort out GDBusObjectManagerClient as well.

Personally I'm very satisfied with being able to use these
generated skeletons to handle my incoming connections (and I
unfortunately can't afford to go off on a tangent here anymore
than I already have).
Comment 3 David Zeuthen (not reading bugmail) 2011-10-27 19:50:35 UTC
Review of attachment 200075 [details] [review]:

Generally looks good even though there's a ton of comments from me about stylistic things and random unrelated changes (such as whitespace and formatting). Please don't take the comments the wrong way - I just really like code to follow the existing style and I want the patch itself to be easy to read and minimal.

We can wait with GDBusObjectManagerServer/GDBusObjectManagerClient support for now.

::: gio/gdbus-2.0/codegen/codegen.py
@@ +2245,3 @@
                      '  %sSkeleton *skeleton = %s%s_SKELETON (_skeleton);\n'
                      %(i.name_lower, i.camel_name, i.ns_upper, i.name_upper))
+

Please clean up the patch so it doesn't add extra whitespace.

@@ +2258,3 @@
                      '        {\n'
                      '          GVariant *value;\n'
+                     '          value = _%s_skeleton_handle_get_property (NULL, NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", info->name, NULL, skeleton);\n'

Why pass NULL instead of "the first" GDBusConnection?

@@ +2312,3 @@
+                         '  GSList     *connections, *l;\n'
+                         '  connections = g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON (skeleton));\n'
+                         '  for (l = connections; l; l = l->next)\n'

As I said in comment 1, need explicit "l != NULL" tests

@@ +2318,3 @@
+            self.c.write('      g_dbus_connection_emit_signal (connection,\n'
+                         '        NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", "%s",\n'
+                         '        g_variant_new ("('

As I said on IRC, it's wasteful to construct a new GVariant every time. Instead just do it like this

 value = g_variant_ref_sink (g_variant_new (..));
 for (..)
   connection_emit_signal (.., value, ..);
 g_variant_unref (value);

which works because g_variant_new() always returns a floating variant.

@@ +2321,2 @@
                          %(i.name, s.name))
+

Extra whitespace.

@@ +2396,3 @@
                          '\n'
                          '  g_mutex_lock (&skeleton->priv->lock);\n'
+                         '\n'

Extra whitespace.

@@ +2420,3 @@
+                         '      signal_variant = g_variant_new ("(sa{sv}as)", "%s",\n'
+                         '                                      &builder, &invalidated_builder);\n'
+                         '      g_variant_ref_sink (signal_variant);'

Suggest to combine both lines into one e.g. g_variant_ref_sink (g_variant_new ())

@@ +2435,3 @@
+                         '      g_variant_unref (signal_variant);\n'
+                         '      g_slist_foreach (connections, (GFunc)g_object_unref, NULL);\n'
+                         '          GDBusConnection *connection = list->data;\n'

Ah, like you are already doing here.

@@ +2448,3 @@
             self.c.write('  skeleton->priv->changed_properties_idle_source = NULL;\n')
             self.c.write('  g_mutex_unlock (&skeleton->priv->lock);\n')
+                         

Extra whitespace.

@@ +2481,3 @@
+                         '    {\n'
+                         '      g_value_copy (orig_value, &cp->orig_value);\n'
+                         '    }\n'

Why this?

@@ +2522,3 @@
                          '  if (!_g_value_equal (value, &skeleton->priv->properties->values[prop_id - 1]))\n'
                          '    {\n'
+                         '      if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)))\n'

why remove the '!= NULL'?

::: gio/gdbusinterfaceskeleton.c
@@ +55,3 @@
 };
 
+typedef struct {

curly brace goes on separate line

@@ +100,1 @@
+  /* Do we need to hold the lock here ?? */

We don't need to hold the lock, no, but it doesn't hurt, in fact, it's good to do in case some of the functions called verifies that the lock is held. Suggest to change it to

 /* Take the lock in case code we calls validates that we hold the lock /*

@@ -85,1 @@
-  g_assert (interface->priv->connection == NULL);

Why remove this?

@@ +118,3 @@
   if (interface->priv->object != NULL)
+    g_object_remove_weak_pointer (G_OBJECT (interface->priv->object),
+				  (gpointer *) &interface->priv->object);

This change looks like noise

@@ +267,3 @@
+				 G_TYPE_DBUS_INTERFACE_SKELETON,
+				 GDBusInterfaceSkeletonPrivate);
+

This one too looks like noise

@@ +668,3 @@
+free_connection (ConnectionData *data)
+{
+  data->connection      = g_object_ref (connection);

missing "!= NULL"

@@ +680,3 @@
+		       GError                **error)
+{
+static void

Don't do this, use interface_->priv directly

@@ +684,3 @@
+  guint                          registration_id;
+
+{

use "== NULL", it's not a boolean

@@ +693,3 @@
+	g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
+      priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
+    }

OK, so we now allocate hooked_vtable the first time we use it and then we keep it around until finalized... Suggest to add a comment for this. Also, avoid splitting the first line in two...

@@ +723,3 @@
+  GDBusInterfaceSkeletonPrivate *priv;
+  ConnectionData                *data;
+       * ::g-authorize-method and for dispatching in thread vs

I generally prefer using the single-letter variables for (list) iterators (such as l for lists and n for scalar types).

@@ +728,3 @@
+
+  /* Get the connection in the list and unregister ... */
+       */

s/list/list != NULL/

@@ -627,3 @@
  * not exported anywhere. Do not free, the object belongs to @interface_.
- *
- * Since: 2.30

Why remove this?

@@ +775,3 @@
 {
+  ConnectionData  *data;
+  GDBusConnection *connection;

I prefer using the name 'ret' for the variable that the function returns - please don't change this to connection. Thanks.

@@ +779,2 @@
   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
+

extra whitespace

@@ +782,3 @@
+
+  data = interface_->priv->connections->data;
+  if (data)

missing != NULL

@@ +817,3 @@
+  connections = NULL;
+
+ *

missing != NULL

@@ +821,3 @@
+      data        = list->data;
+      connections = g_slist_prepend (connections,
+ *   A newly allocated #GSList of #GDBusConnections all of wich

No need to state this (it's already stated in the docs for the function)

@@ +847,3 @@
+{
+  GSList *list;
+

initialize to FALSE here instead of in the for() loop

@@ +853,3 @@
+
+  for (ret = FALSE, list = interface_->priv->connections;
+

Please use !ret instead of 'ret == FALSE'

@@ +860,3 @@
+      ret = (data->connection == connection);
+    }
+      connections = g_slist_prepend (connections,

I think it would be nicer like this

 for (l = interface_->priv->connections; l != NULL; l = l->next)
   {
     ConnectionData *data = l->data;
     if (data->connection == connection)
       {
         ret = TRUE;
         goto out;
       }
   }

where out is just before unlocking the mutex.

@@ +869,3 @@
  * @interface_: A #GDBusInterfaceSkeleton.
  *
+ * Gets the object path that @interface_ is configured to export itself on.

why remove ", if any"? I mean, it still could be that interface_ is not yet exported.

@@ +933,2 @@
   g_mutex_unlock (&interface_->priv->lock);
+

extra whitespace

@@ -746,3 @@
 {
   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
-  g_return_if_fail (interface_->priv->registration_id > 0);

Why remove this check? Instead I think we need

 g_return_if_fail (interface_->priv->connections != NULL);

@@ +953,3 @@
   g_mutex_lock (&interface_->priv->lock);
 
+  /* Remove the connection */

Should probably say "Remove all connections"

@@ -750,3 @@
   g_mutex_lock (&interface_->priv->lock);
 
-  g_assert (interface_->priv->connection != NULL);

why remove this assert?

@@ -752,3 @@
-  g_assert (interface_->priv->connection != NULL);
-  g_assert (interface_->priv->object_path != NULL);
-  g_assert (interface_->priv->hooked_vtable != NULL);

Why remove the asserts?

::: gio/gdbusinterfaceskeleton.h
@@ +107,2 @@
 GDBusConnection             *g_dbus_interface_skeleton_get_connection  (GDBusInterfaceSkeleton      *interface_);
+GSList                      *g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton      *interface_);

Use GList, not GSList.

::: gio/tests/gdbus-peer.c
@@ +1707,3 @@
+
+  example_animal_call_poke_sync (animal1, TRUE, FALSE, NULL, &error);
+

Should check here that both animal1 and animal2 are sad now ... but for this you need to be sure that the generated PropertiesChanged signal have been delivered. A nice way to ensure this is simply by pinging the object.. like this

  error = NULL;
  value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal1),
                                  "org.freedesktop.DBus.Peer.Ping",
                                  NULL, G_DBUS_CALL_FLAGS_NONE, -1,
                                  NULL, &error);
  g_assert_no_error (error);
  g_assert (value != NULL);
  g_variant_unref (value);
  g_assert_cmpstr (animal_get_mood (animal1), ==, "Sad");

and ditto for animal2.

@@ +1710,3 @@
+
+  example_animal_call_poke_sync (animal2, FALSE, TRUE, NULL, &error);
+  /* Handle Poke() D-Bus method invocations on the .Animal interface */

and here check that both animals are happy
Comment 4 Tristan Van Berkom 2011-10-27 23:23:07 UTC
Created attachment 200147 [details] [review]
Patch to allow GDBusInterfaceSkeleton to export itself on multiple GDBusConnections [take 3]

Ok I think this new patch covers all of your comments.

I replied to them inline while applying the changes to the patch:

(In reply to comment #3)
> Review of attachment 200075 [details] [review]:
> 
> Generally looks good even though there's a ton of comments from me about
> stylistic things and random unrelated changes (such as whitespace and
> formatting). Please don't take the comments the wrong way - I just really like
> code to follow the existing style and I want the patch itself to be easy to
> read and minimal.
> 
> We can wait with GDBusObjectManagerServer/GDBusObjectManagerClient support for
> now.
> 
> ::: gio/gdbus-2.0/codegen/codegen.py
> @@ +2245,3 @@
>                       '  %sSkeleton *skeleton = %s%s_SKELETON (_skeleton);\n'
>                       %(i.name_lower, i.camel_name, i.ns_upper, i.name_upper))
> +
> 
> Please clean up the patch so it doesn't add extra whitespace.

Got it.

> @@ +2258,3 @@
>                       '        {\n'
>                       '          GVariant *value;\n'
> +                     '          value = _%s_skeleton_handle_get_property
> (NULL, NULL, g_dbus_interface_skeleton_get_object_path
> (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", info->name, NULL, skeleton);\n'
> 
> Why pass NULL instead of "the first" GDBusConnection?

I thought it needless to pass in the first GDBusConnection as it's
unused and probably a bad idea to use, but I'm removing that diff
to keep the patch shorter as it's probably doesnt really change anything...

> 
> @@ +2312,3 @@
> +                         '  GSList     *connections, *l;\n'
> +                         '  connections =
> g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON
> (skeleton));\n'
> +                         '  for (l = connections; l; l = l->next)\n'
> 
> As I said in comment 1, need explicit "l != NULL" tests

Ok I tried to use 'l' instead of 'list' and use '!= NULL' checks for
pointers and '!ret' checks for booleans, if I understand that's what you
want... I hope I have it the way you like this time...

> 
> @@ +2318,3 @@
> +            self.c.write('      g_dbus_connection_emit_signal (connection,\n'
> +                         '        NULL,
> g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON
> (skeleton)), "%s", "%s",\n'
> +                         '        g_variant_new ("('
> 
> As I said on IRC, it's wasteful to construct a new GVariant every time. Instead
> just do it like this
> 
>  value = g_variant_ref_sink (g_variant_new (..));
>  for (..)
>    connection_emit_signal (.., value, ..);
>  g_variant_unref (value);
> 
> which works because g_variant_new() always returns a floating variant.
> 

Got it, I thought I caught it the first time but as you can see
I only did it for one of the two signal emission loops...

> @@ +2481,3 @@
> +                         '    {\n'
> +                         '      g_value_copy (orig_value, &cp->orig_value);\n'
> +                         '    }\n'
> 
> Why this?

Ah, my bad mistake, I had that temporarily and forgot to remove it, gone.

> 
> @@ +2522,3 @@
>                           '  if (!_g_value_equal (value,
> &skeleton->priv->properties->values[prop_id - 1]))\n'
>                           '    {\n'
> +                         '      if (g_dbus_interface_skeleton_get_connection
> (G_DBUS_INTERFACE_SKELETON (skeleton)))\n'
> 
> why remove the '!= NULL'?

Fallout from my last patch when it became a boolean '_exported()' function
and the other one was deprecated, i.e. no good reason, putting it back
the original way.

> ::: gio/gdbusinterfaceskeleton.c
> @@ +55,3 @@
>  };
> 
> +typedef struct {
> 
> curly brace goes on separate line
> 

Done...

> @@ +100,1 @@
> +  /* Do we need to hold the lock here ?? */
> 
> We don't need to hold the lock, no, but it doesn't hurt, in fact, it's good to
> do in case some of the functions called verifies that the lock is held. Suggest
> to change it to
> 
>  /* Take the lock in case code we calls validates that we hold the lock /*
> 

Gotcha...

> @@ -85,1 @@
> -  g_assert (interface->priv->connection == NULL);
> 
> Why remove this?
> 

Because before the code did
  if (priv->connection) set_connection (NULL);
  assert (!connection)

Now it already does:
  while (connections != NULL)
    remove_connection ();

So the assert() becomes pointless after that loop
(in this particular case in finalize at least).

> @@ +118,3 @@
>    if (interface->priv->object != NULL)
> +    g_object_remove_weak_pointer (G_OBJECT (interface->priv->object),
> +                  (gpointer *) &interface->priv->object);
> 
> This change looks like noise
> 
> @@ +267,3 @@
> +                 G_TYPE_DBUS_INTERFACE_SKELETON,
> +                 GDBusInterfaceSkeletonPrivate);
> +
> 
> This one too looks like noise
> 

Removed noise...

> @@ +668,3 @@
> +free_connection (ConnectionData *data)
> +{
> +  data->connection      = g_object_ref (connection);
> 
> missing "!= NULL"
> 

Gotcha...

> @@ +680,3 @@
> +               GError                **error)
> +{
> +static void
> 
> Don't do this, use interface_->priv directly
> 

Ok, changed the source file entirely to that effect...

> @@ +693,3 @@
> +    g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof
> (GDBusInterfaceVTable));
> +      priv->hooked_vtable->method_call =
> skeleton_intercept_handle_method_call;
> +    }
> 
> OK, so we now allocate hooked_vtable the first time we use it and then we keep
> it around until finalized... Suggest to add a comment for this. Also, avoid
> splitting the first line in two...

Alright, added comment saying that we need to wait for subclasses
to initialize in order to fetch a usable vtable (which is why we 
put it off instead of doing it right away in the instance initializer).

> @@ +728,3 @@
> +
> +  /* Get the connection in the list and unregister ... */
> +       */
> 
> s/list/list != NULL/
> 
> @@ -627,3 @@
>   * not exported anywhere. Do not free, the object belongs to @interface_.
> - *
> - * Since: 2.30
> 
> Why remove this?

More fallout, was deprecated in last patch and brought back 
without the since tag, fixed...

> 
> @@ +775,3 @@
>  {
> +  ConnectionData  *data;
> +  GDBusConnection *connection;
> 
> I prefer using the name 'ret' for the variable that the function returns -
> please don't change this to connection. Thanks.
> 

Got it, actually I also caught a possible null pointer dereference
I had in that function... fixed.

> @@ +821,3 @@
> +      data        = list->data;
> +      connections = g_slist_prepend (connections,
> + *   A newly allocated #GSList of #GDBusConnections all of wich
> 
> No need to state this (it's already stated in the docs for the function)
>

Got it... simplified comment...
 
> @@ +847,3 @@
> +{
> +  GSList *list;
> +
> 
> initialize to FALSE here instead of in the for() loop
> 
> @@ +853,3 @@
> +
> +  for (ret = FALSE, list = interface_->priv->connections;
> +
> 
> Please use !ret instead of 'ret == FALSE'
> 
> @@ +860,3 @@
> +      ret = (data->connection == connection);
> +    }
> +      connections = g_slist_prepend (connections,
> 
> I think it would be nicer like this
> 
>  for (l = interface_->priv->connections; l != NULL; l = l->next)
>    {
>      ConnectionData *data = l->data;
>      if (data->connection == connection)
>        {
>          ret = TRUE;
>          goto out;
>        }
>    }
> 
> where out is just before unlocking the mutex.
> 

Done.

> @@ +869,3 @@
>   * @interface_: A #GDBusInterfaceSkeleton.
>   *
> + * Gets the object path that @interface_ is configured to export itself on.
> 
> why remove ", if any"? I mean, it still could be that interface_ is not yet
> exported.

Put it back, again more fallout from my first patch..

> @@ -746,3 @@
>  {
>    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
> -  g_return_if_fail (interface_->priv->registration_id > 0);
> 
> Why remove this check? Instead I think we need
> 
>  g_return_if_fail (interface_->priv->connections != NULL);

Done.

> 
> @@ +953,3 @@
>    g_mutex_lock (&interface_->priv->lock);
> 
> +  /* Remove the connection */
> 
> Should probably say "Remove all connections"

Done..

> 
> @@ -750,3 @@
>    g_mutex_lock (&interface_->priv->lock);
> 
> -  g_assert (interface_->priv->connection != NULL);
> 
> why remove this assert?
> 
> @@ -752,3 @@
> -  g_assert (interface_->priv->connection != NULL);
> -  g_assert (interface_->priv->object_path != NULL);
> -  g_assert (interface_->priv->hooked_vtable != NULL);
> 
> Why remove the asserts?

Well, now I added the:
   g_return_if_fail (interface_->priv->connections != NULL)

as you suggested, so the assert on ->connections is gone,
I put back the other 2 asserts in _unexport() (and replicated
that in _unexport_from_connection).

> 
> ::: gio/gdbusinterfaceskeleton.h
> @@ +107,2 @@
>  GDBusConnection             *g_dbus_interface_skeleton_get_connection 
> (GDBusInterfaceSkeleton      *interface_);
> +GSList                      *g_dbus_interface_skeleton_get_connections
> (GDBusInterfaceSkeleton      *interface_);
> 
> Use GList, not GSList.

Done.

> 
> ::: gio/tests/gdbus-peer.c
> @@ +1707,3 @@
> +
> +  example_animal_call_poke_sync (animal1, TRUE, FALSE, NULL, &error);
> +
> 
> Should check here that both animal1 and animal2 are sad now ... but for this
> you need to be sure that the generated PropertiesChanged signal have been
> delivered. A nice way to ensure this is simply by pinging the object.. like
> this
> 
>   error = NULL;
>   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal1),
>                                   "org.freedesktop.DBus.Peer.Ping",
>                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
>                                   NULL, &error);
>   g_assert_no_error (error);
>   g_assert (value != NULL);
>   g_variant_unref (value);
>   g_assert_cmpstr (animal_get_mood (animal1), ==, "Sad");
> 
> and ditto for animal2.
> 

Gotcha, this was a bit of a challenge to get the test working
but I got it.

The rules of course are
  a.) The skeleton must be created after pushing the default server thread context
  b.) After poking the animal from the proxy, the client thread needs to run a main
      loop to pick up property change notification messages before asserting
  c.) The server needs to also run the main loop to notify changes, so a message
      that causes the server to quit it's mainloop does not result in property
      change notifications on the proxy (even if the skeleton calls animal_set_mood())

I suppose this last part 'c.)' might be considered a bug by some, perhaps
pending signals should be flushed before destroying an interface skeleton
or the like, at any rate its unrelated to this patch...
Comment 5 Tristan Van Berkom 2011-10-27 23:28:50 UTC
Created attachment 200148 [details] [review]
Patch to make GDBusObjectManagerServer manage multiple connections

I'm posting this patch for reference as it did cost me some good effort and
should be useful.

This patch makes GDBusObjectManagerServer export it's objects over multiple
connections.

When applying this patch locally, one problem you will find when
trying to use GDBusObjectManagerClient without the 'name-owner' (i.e. no
bus, just a connection)... is that when creating the derived proxies
(i.e. ExampleAnimalProxy) the constructor method will assign "name" to
the proxy with a passed NULL value.

Going into gdbusproxy.c and fixing set_property() so that NULL is an
exceptable and ignorable value for the "name" property will get you
by this obstacle.

Next the only thing missing is to make the GDBusObjectManagerClient aware
that it can call GetObjects and the like on a GDBusConnection even if there
is no bus... 

Anyway, hope this patch might be helpful...
Comment 6 David Zeuthen (not reading bugmail) 2011-11-14 16:01:40 UTC
Hey, Tristan, sorry for the silence - been busy with other work. Just a headsup that I will be reviewing / merging the patch later this week. Thanks.
Comment 7 Tristan Van Berkom 2011-11-29 12:04:29 UTC
(In reply to comment #1)
[...]
> Finally I'm curious what you want to use this for (if you can disclose it
> please do - otherwise no problem).

Hi, 
   I'm not sure if I may have replied this on irc, anyway when you
asked the question I was not sure if the information was public or
not yet (and I had recently signed an NDA for this).

But I can now tell you that it's for a karaoke player application
which will display the karaoke visual both on the local 'player'
host (which is a TouchTunes Jukebox) and also on some remote displays
(which are driven by some networked devices which are also running
the same client program which can run on the local host).

TouchTunes has already demoed a prototype for this application
at a trade show and announced it's release for early 2012
(so at least this particular information is not a secret).

I've been trying to catch you on IRC but since I moved back to Seoul
Korea last week I think our time zones have went out of sync.

Can we please try to land this soon ? I'll be much more comfortable
if I can tell my boss that we don't depend on a downstream patch
for this player...
Comment 8 David Zeuthen (not reading bugmail) 2011-11-29 19:55:41 UTC
(In reply to comment #7)
> But I can now tell you that it's for a karaoke player application
> which will display the karaoke visual both on the local 'player'
> host (which is a TouchTunes Jukebox) and also on some remote displays
> (which are driven by some networked devices which are also running
> the same client program which can run on the local host).

Interesting.

> Can we please try to land this soon ? I'll be much more comfortable
> if I can tell my boss that we don't depend on a downstream patch
> for this player...

Certainly. Sorry for being slow, I've been very busy with another project. I'll review your patch this week, promise!
Comment 9 David Zeuthen (not reading bugmail) 2011-12-02 16:28:16 UTC
Review of attachment 200147 [details] [review]:

Committed with a bunch of small changes, mostly stylistic (comments, s/tab/space/, trailing whitespace), see

 http://git.gnome.org/browse/glib/commit/?id=a00530ecb0e8576e7a023f37a97528da4d0dfce5

In the future please use 'git format-patch' to generate patches. Thanks.

::: gio/gdbusinterfaceskeleton.c
@@ +722,3 @@
+
+  /* Get the connection in the list and unregister ... */
+       * We need to wait until subclasses have had time to initialize

Not really safe to use l->next since we may be deleting @l below. But note how we can (and should) exit the loop once matched because of the fact that connection will appear at most one time in the list.

@@ +751,3 @@
+    }
+  return FALSE;
+				       NULL, /* user_data_free_func */

No need to return a gboolean since none of the call-sites use it.

::: gio/tests/gdbus-peer.c
@@ +1732,3 @@
+  /* Give the proxies a chance to refresh in the defaul main loop */
+  g_timeout_add (100, codegen_quit_mainloop_timeout, NULL);
+					   test_guid,

Not at all thrilled with this "sleep" ... much better to wait for property changes. I guess we can fix it up later.

@@ +1753,3 @@
+  /* Give the proxies a chance to refresh in the defaul main loop */
+  g_timeout_add (1000, codegen_quit_mainloop_timeout, NULL);
+  service_loop = g_main_loop_new (service_context, FALSE);

Ditto.
Comment 10 Tristan Van Berkom 2011-12-03 06:07:06 UTC
Thank you for taking the time to do this David :)

Shall we keep this one open for the prospect of extending
this to GDBusObjectManagerServer & GDBusObjectManagerClient ?

If you prefer, I could open up a separate bug for that... 
(FWIW I still don't personally need that functionality)
Comment 11 David Zeuthen (not reading bugmail) 2011-12-05 15:46:20 UTC
(In reply to comment #10)
> If you prefer, I could open up a separate bug for that... 
> (FWIW I still don't personally need that functionality)

Let's just keep this bug open. Thanks.
Comment 12 GNOME Infrastructure Team 2018-05-24 13:29:34 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glib/issues/472.