2003-08-15 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Fri, 15 Aug 2003 23:10:12 +0000 (23:10 +0000)
committerHavoc Pennington <hp@redhat.com>
Fri, 15 Aug 2003 23:10:12 +0000 (23:10 +0000)
* dbus/dbus-pending-call.c (dbus_pending_call_block): implement

* dbus/dbus-connection.c
(dbus_connection_send_with_reply_and_block): factor out internals;
change to convert any error replies to DBusError instead of
returning them as a message

ChangeLog
dbus/dbus-connection-internal.h
dbus/dbus-connection.c
dbus/dbus-pending-call.c
dbus/dbus-pending-call.h
glib/dbus-gproxy.h

index f1024db..4a8f4ac 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2003-08-15  Havoc Pennington  <hp@redhat.com>
+
+       * dbus/dbus-pending-call.c (dbus_pending_call_block): implement
+
+       * dbus/dbus-connection.c
+       (dbus_connection_send_with_reply_and_block): factor out internals;
+       change to convert any error replies to DBusError instead of 
+       returning them as a message
+
 2003-08-15  Havoc Pennington  <hp@pobox.com>
 
        * dbus/dbus-connection.c, 
index d9d5c5b..f26c92e 100644 (file)
@@ -88,15 +88,18 @@ DBusHandlerResult _dbus_message_handler_handle_message         (DBusMessageHandl
                                                                 DBusMessage        *message);
 void              _dbus_connection_init_id                     (DBusConnection     *connection,
                                                                 DBusObjectID       *id);
-
 DBusPendingCall*  _dbus_pending_call_new                       (DBusConnection     *connection,
                                                                 int                 timeout_milliseconds,
                                                                 DBusTimeoutHandler  timeout_handler);
-
 void              _dbus_pending_call_notify                    (DBusPendingCall    *pending);
-
 void              _dbus_connection_remove_pending_call         (DBusConnection     *connection,
                                                                 DBusPendingCall    *pending);
+DBusMessage*      _dbus_connection_block_for_reply             (DBusConnection     *connection,
+                                                                dbus_uint32_t       client_serial,
+                                                                int                 timeout_milliseconds);
+void              _dbus_pending_call_complete_and_unlock       (DBusPendingCall    *pending,
+                                                                DBusMessage        *message);
+
 
 /**
  * @addtogroup DBusPendingCallInternals DBusPendingCall implementation details
index 3af00ed..bc26a3e 100644 (file)
@@ -621,6 +621,38 @@ _dbus_connection_remove_pending_call (DBusConnection  *connection,
 }
 
 /**
+ * Completes a pending call with the given message,
+ * or if the message is #NULL, by timing out the pending call.
+ * 
+ * @param pending the pending call
+ * @param message the message to complete the call with, or #NULL
+ *  to time out the call
+ */
+void
+_dbus_pending_call_complete_and_unlock (DBusPendingCall *pending,
+                                        DBusMessage     *message)
+{
+  if (message == NULL)
+    {
+      message = pending->timeout_link->data;
+      _dbus_list_clear (&pending->timeout_link);
+    }
+
+  _dbus_verbose ("  handing message %p to pending call\n", message);
+  
+  _dbus_assert (pending->reply == NULL);
+  pending->reply = message;
+  dbus_message_ref (pending->reply);
+  
+  dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
+  _dbus_connection_detach_pending_call_and_unlock (pending->connection, pending);
+  
+  /* Must be called unlocked since it invokes app callback */
+  _dbus_pending_call_notify (pending);
+  dbus_pending_call_unref (pending);
+}
+
+/**
  * Acquire the transporter I/O path. This must be done before
  * doing any I/O in the transporter. May sleep and drop the
  * connection mutex while waiting for the I/O path.
@@ -1745,42 +1777,31 @@ check_for_reply_unlocked (DBusConnection *connection,
 }
 
 /**
- * Sends a message and blocks a certain time period while waiting for a reply.
- * This function does not dispatch any message handlers until the main loop
- * has been reached. This function is used to do non-reentrant "method calls."
- * If a reply is received, it is returned, and removed from the incoming
- * message queue. If it is not received, #NULL is returned and the
- * error is set to #DBUS_ERROR_NO_REPLY. If something else goes
- * wrong, result is set to whatever is appropriate, such as
- * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
+ * Blocks a certain time period while waiting for a reply.
+ * If no reply arrives, returns #NULL.
  *
  * @todo could use performance improvements (it keeps scanning
  * the whole message queue for example) and has thread issues,
  * see comments in source
  *
  * @param connection the connection
- * @param message the message to send
+ * @param client_serial the reply serial to wait for
  * @param timeout_milliseconds timeout in milliseconds or -1 for default
- * @param error return location for error message
- * @returns the message that is the reply or #NULL with an error code if the
- * function fails.
+ * @returns the message that is the reply or #NULL if no reply
  */
-DBusMessage *
-dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
-                                           DBusMessage        *message,
-                                           int                 timeout_milliseconds,
-                                           DBusError          *error)
+DBusMessage*
+_dbus_connection_block_for_reply (DBusConnection     *connection,
+                                  dbus_uint32_t       client_serial,
+                                  int                 timeout_milliseconds)
 {
-  dbus_uint32_t client_serial;
   long start_tv_sec, start_tv_usec;
   long end_tv_sec, end_tv_usec;
   long tv_sec, tv_usec;
   DBusDispatchStatus status;
 
   _dbus_return_val_if_fail (connection != NULL, NULL);
-  _dbus_return_val_if_fail (message != NULL, NULL);
-  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);  
-  _dbus_return_val_if_error_is_set (error, NULL);
+  _dbus_return_val_if_fail (client_serial != 0, NULL);
+  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
   
   if (timeout_milliseconds == -1)
     timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
@@ -1792,14 +1813,6 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
   if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
     timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
   
-  if (!dbus_connection_send (connection, message, &client_serial))
-    {
-      _DBUS_SET_OOM (error);
-      return NULL;
-    }
-
-  message = NULL;
-  
   /* Flush message queue */
   dbus_connection_flush (connection);
 
@@ -1894,11 +1907,6 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
 
   _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %ld milliseconds and got no reply\n",
                  (tv_sec - start_tv_sec) * 1000 + (tv_usec - start_tv_usec) / 1000);
-  
-  if (dbus_connection_get_is_connected (connection))
-    dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
-  else
-    dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
 
   /* unlocks and calls out to user code */
   _dbus_connection_update_dispatch_status_and_unlock (connection, status);
@@ -1907,6 +1915,70 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
 }
 
 /**
+ * Sends a message and blocks a certain time period while waiting for
+ * a reply.  This function does not reenter the main loop,
+ * i.e. messages other than the reply are queued up but not
+ * processed. This function is used to do non-reentrant "method
+ * calls."
+ * 
+ * If a normal reply is received, it is returned, and removed from the
+ * incoming message queue. If it is not received, #NULL is returned
+ * and the error is set to #DBUS_ERROR_NO_REPLY.  If an error reply is
+ * received, it is converted to a #DBusError and returned as an error,
+ * then the reply message is deleted. If something else goes wrong,
+ * result is set to whatever is appropriate, such as
+ * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
+ *
+ * @param connection the connection
+ * @param message the message to send
+ * @param timeout_milliseconds timeout in milliseconds or -1 for default
+ * @param error return location for error message
+ * @returns the message that is the reply or #NULL with an error code if the
+ * function fails.
+ */
+DBusMessage *
+dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
+                                           DBusMessage        *message,
+                                           int                 timeout_milliseconds,
+                                           DBusError          *error)
+{
+  dbus_uint32_t client_serial;
+  DBusMessage *reply;
+  
+  _dbus_return_val_if_fail (connection != NULL, NULL);
+  _dbus_return_val_if_fail (message != NULL, NULL);
+  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);  
+  _dbus_return_val_if_error_is_set (error, NULL);
+  
+  if (!dbus_connection_send (connection, message, &client_serial))
+    {
+      _DBUS_SET_OOM (error);
+      return NULL;
+    }
+
+  reply = _dbus_connection_block_for_reply (connection,
+                                            client_serial,
+                                            timeout_milliseconds);
+  
+  if (reply == NULL)
+    {
+      if (dbus_connection_get_is_connected (connection))
+        dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
+      else
+        dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
+
+      return NULL;
+    }
+  else if (dbus_set_error_from_message (error, reply))
+    {
+      dbus_message_unref (reply);
+      return NULL;
+    }
+  else
+    return reply;
+}
+
+/**
  * Blocks until the outgoing message queue is empty.
  *
  * @param connection the connection.
@@ -2301,6 +2373,10 @@ dbus_connection_get_dispatch_status (DBusConnection *connection)
  * be part of authentication or the like.
  *
  * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY
+ *
+ * @todo right now a message filter gets run on replies to a pending
+ * call in here, but not in the case where we block without
+ * entering the main loop.
  * 
  * @param connection the connection
  * @returns dispatch status
@@ -2435,18 +2511,7 @@ dbus_connection_dispatch (DBusConnection *connection)
   
   if (pending)
     {
-      _dbus_verbose ("  handing message %p to pending call\n", message);
-
-      _dbus_assert (pending->reply == NULL);
-      pending->reply = message;
-      dbus_message_ref (pending->reply);
-
-      dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
-      _dbus_connection_detach_pending_call_and_unlock (connection, pending);
-
-      /* Must be called unlocked since it invokes app callback */
-      _dbus_pending_call_notify (pending);
-      dbus_pending_call_unref (pending);
+      _dbus_pending_call_complete_and_unlock (pending, message);
 
       pending = NULL;
       
@@ -2869,6 +2934,10 @@ dbus_connection_set_unix_user_function (DBusConnection             *connection,
  * forgets about it. Thus the caller of this function must keep a
  * reference to the message handler.
  *
+ * @todo we don't run filters on messages while blocking without
+ * entering the main loop, since filters are run as part of
+ * dbus_connection_dispatch().
+ *
  * @param connection the connection
  * @param handler the handler
  * @returns #TRUE on success, #FALSE if not enough memory.
index 84ca7ae..2b6021e 100644 (file)
@@ -254,6 +254,31 @@ dbus_pending_call_get_reply (DBusPendingCall *pending)
   return pending->reply;
 }
 
+/**
+ * Block until the pending call is completed.  The blocking is as with
+ * dbus_connection_send_with_reply_and_block(); it does not enter the
+ * main loop or process other messages, it simply waits for the reply
+ * in question.
+ *
+ * @todo when you start blocking, the timeout is reset, but it should
+ * really only use time remaining since the pending call was created.
+ *
+ * @param pending the pending call
+ */
+void
+dbus_pending_call_block (DBusPendingCall *pending)
+{
+  DBusMessage *message;
+  
+  message = _dbus_connection_block_for_reply (pending->connection,
+                                              pending->reply_serial,
+                                              dbus_timeout_get_interval (pending->timeout));
+
+  _dbus_connection_lock (pending->connection);
+  _dbus_pending_call_complete_and_unlock (pending, message);
+  dbus_message_unref (message);
+}
+
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS
index 66f1bac..81af872 100644 (file)
@@ -42,6 +42,7 @@ void         dbus_pending_call_set_notify    (DBusPendingCall               *pen
 void         dbus_pending_call_cancel        (DBusPendingCall               *pending);
 dbus_bool_t  dbus_pending_call_get_completed (DBusPendingCall               *pending);
 DBusMessage* dbus_pending_call_get_reply     (DBusPendingCall               *pending);
+void         dbus_pending_call_block         (DBusPendingCall               *pending);
 
 DBUS_END_DECLS;
 
index bebcd1c..47b70f3 100644 (file)
 G_BEGIN_DECLS
 
 typedef struct DBusGProxy       DBusGProxy;
-typedef struct DBusGPendingCall DBusGPendingCall;
+typedef struct DBusPendingCall DBusPendingCall;
 
-DBusGProxy*       dbus_gproxy_new_for_service        (DBusConnection          *connection,
-                                                      const char              *service_name,
-                                                      const char              *interface_name);
-DBusGProxy*       dbus_gproxy_new_for_service_owner  (DBusConnection          *connection,
-                                                      const char              *service_name,
-                                                      const char              *interface_name,
-                                                      GError                 **error);
-DBusGProxy*       dbus_gproxy_new_for_object_id      (DBusConnection          *connection,
-                                                      const DBusObjectID      *object_id,
-                                                      const char              *interface_name);
-DBusGProxy*       dbus_gproxy_new_for_interface      (DBusConnection          *connection,
-                                                      const char              *interface_name);
-void              dbus_gproxy_ref                    (DBusGProxy              *proxy);
-void              dbus_gproxy_unref                  (DBusGProxy              *proxy);
-gboolean          dbus_gproxy_connect_signal         (DBusGProxy              *proxy,
-                                                      const char              *signal_name,
-                                                      GCallback                callback,
-                                                      void                    *data,
-                                                      GFreeFunc                free_data_func,
-                                                      GError                 **error);
-DBusGPendingCall* dbus_gproxy_begin_call             (DBusGProxy              *proxy,
-                                                      const char              *method,
-                                                      int                      first_arg_type,
-                                                      ...);
-void              dbus_gproxy_oneway_call            (DBusGProxy              *proxy,
-                                                      const char              *method,
-                                                      int                      first_arg_type,
-                                                      ...);
+DBusGProxy*      dbus_gproxy_new_for_service       (DBusConnection      *connection,
+                                                    const char          *service_name,
+                                                    const char          *interface_name);
+DBusGProxy*      dbus_gproxy_new_for_service_owner (DBusConnection      *connection,
+                                                    const char          *service_name,
+                                                    const char          *interface_name,
+                                                    GError             **error);
+DBusGProxy*      dbus_gproxy_new_for_object_id     (DBusConnection      *connection,
+                                                    const DBusObjectID  *object_id,
+                                                    const char          *interface_name);
+DBusGProxy*      dbus_gproxy_new_for_interface     (DBusConnection      *connection,
+                                                    const char          *interface_name);
+void             dbus_gproxy_ref                   (DBusGProxy          *proxy);
+void             dbus_gproxy_unref                 (DBusGProxy          *proxy);
+gboolean         dbus_gproxy_connect_signal        (DBusGProxy          *proxy,
+                                                    const char          *signal_name,
+                                                    GCallback            callback,
+                                                    void                *data,
+                                                    GFreeFunc            free_data_func,
+                                                    GError             **error);
+DBusPendingCall* dbus_gproxy_begin_call            (DBusGProxy          *proxy,
+                                                    const char          *method,
+                                                    int                  first_arg_type,
+                                                    ...);
+void             dbus_gproxy_oneway_call           (DBusGProxy          *proxy,
+                                                    const char          *method,
+                                                    int                  first_arg_type,
+                                                    ...);
+gboolean         dbus_pending_call_is_complete     (DBusPendingCall     *call);
+void             dbus_pending_call_cancel_and_free (DBusPendingCall     *call);
+gboolean         dbus_pending_call_block_and_free  (DBusPendingCall     *call,
+                                                    GError             **error,
+                                                    int                  first_arg_type,
+                                                    ...);
 
-gboolean          dbus_gpending_call_is_complete     (DBusGPendingCall        *call);
-void              dbus_gpending_call_cancel_and_free (DBusGPendingCall        *call);
-gboolean          dbus_gpending_call_block_and_free  (DBusGPendingCall        *call,
-                                                      GError                 **error,
-                                                      int                      first_arg_type,
-                                                      ...);