diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-08-15 04:17:58 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-08-15 04:17:58 +0000 | 
| commit | ef614207fc4f03e5cc02faeb109f739eb1ccdf31 (patch) | |
| tree | 8e32a70a0094c6605c29f2f2ed99075b6fc0d483 | |
| parent | a6c8a71b1bcba04b63812a61f668e87af0922e5e (diff) | |
2003-08-15  Havoc Pennington  <hp@pobox.com>
	* dbus/dbus-connection.c,
	dbus/dbus-pending-call.c: Finish the pending call stuff
| -rw-r--r-- | ChangeLog | 5 | ||||
| -rw-r--r-- | dbus/Makefile.am | 2 | ||||
| -rw-r--r-- | dbus/dbus-connection-internal.h | 45 | ||||
| -rw-r--r-- | dbus/dbus-connection.c | 364 | ||||
| -rw-r--r-- | dbus/dbus-connection.h | 6 | ||||
| -rw-r--r-- | dbus/dbus-pending-call.c | 146 | ||||
| -rw-r--r-- | dbus/dbus-pending-call.h | 9 | ||||
| -rw-r--r-- | dbus/dbus-test.c | 6 | ||||
| -rw-r--r-- | dbus/dbus-test.h | 2 | ||||
| -rw-r--r-- | dbus/dbus.h | 1 | 
10 files changed, 363 insertions, 223 deletions
@@ -1,3 +1,8 @@ +2003-08-15  Havoc Pennington  <hp@pobox.com> + +	* dbus/dbus-connection.c,  +	dbus/dbus-pending-call.c: Finish the pending call stuff +  2003-08-14  Havoc Pennington  <hp@redhat.com>  	* dbus/dbus-pending-call.c: start on new object that will replace diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 8c919f31..3537b935 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -19,6 +19,7 @@ dbusinclude_HEADERS=				\  	dbus-message-handler.h			\  	dbus-object.h				\  	dbus-objectid.h				\ +	dbus-pending-call.h			\  	dbus-protocol.h				\  	dbus-server.h				\  	dbus-threads.h				\ @@ -48,6 +49,7 @@ DBUS_LIB_SOURCES=				\  	dbus-objectid.c				\  	dbus-object-registry.c			\  	dbus-object-registry.h			\ +	dbus-pending-call.c			\  	dbus-resources.c			\  	dbus-resources.h			\  	dbus-server.c				\ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 423df5f8..d9d5c5b4 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -29,6 +29,7 @@  #include <dbus/dbus-transport.h>  #include <dbus/dbus-resources.h>  #include <dbus/dbus-list.h> +#include <dbus/dbus-timeout.h>  DBUS_BEGIN_DECLS; @@ -39,6 +40,9 @@ typedef enum    DBUS_ITERATION_BLOCK      = 1 << 2  /**< Block if nothing to do. */  } DBusIterationFlags; +/** default timeout value when waiting for a message reply */ +#define _DBUS_DEFAULT_TIMEOUT_VALUE (15 * 1000) +  void              _dbus_connection_lock                        (DBusConnection     *connection);  void              _dbus_connection_unlock                      (DBusConnection     *connection);  void              _dbus_connection_ref_unlocked                (DBusConnection     *connection); @@ -85,6 +89,47 @@ DBusHandlerResult _dbus_message_handler_handle_message         (DBusMessageHandl  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); + +/** + * @addtogroup DBusPendingCallInternals DBusPendingCall implementation details + * @{ + */ +/** + * @brief Internals of DBusPendingCall + * + * Object representing a reply message that we're waiting for. + */ +struct DBusPendingCall +{ +  DBusAtomic refcount;                            /**< reference count */ + +  DBusPendingCallNotifyFunction function;         /**< Notifier when reply arrives. */ +  void                     *user_data;            /**< user data for function */ +  DBusFreeFunction          free_user_data;       /**< free the user data */ + +  DBusConnection *connection;                     /**< Connections we're associated with */ +  DBusMessage *reply;                             /**< Reply (after we've received it) */ +  DBusTimeout *timeout;                           /**< Timeout */ + +  DBusList *timeout_link;                         /**< Preallocated timeout response */ +   +  dbus_uint32_t reply_serial;                     /**< Expected serial of reply */ + +  unsigned int completed : 1;                     /**< TRUE if completed */ +  unsigned int timeout_added : 1;                 /**< Have added the timeout */ +}; + +/** @} End of DBusPendingCallInternals */ + +  DBUS_END_DECLS;  #endif /* DBUS_CONNECTION_INTERNAL_H */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ba5601e3..3af00ed0 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -37,6 +37,7 @@  #include "dbus-dataslot.h"  #include "dbus-object-registry.h"  #include "dbus-string.h" +#include "dbus-pending-call.h"  #if 0  #define CONNECTION_LOCK(connection)   do {                      \ @@ -124,9 +125,6 @@   * @{   */ -/** default timeout value when waiting for a message reply */ -#define DEFAULT_TIMEOUT_VALUE (15 * 1000) -  static dbus_bool_t _dbus_modify_sigpipe = TRUE;  /** @@ -163,7 +161,7 @@ struct DBusConnection    DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */ -  DBusHashTable *pending_replies;  /**< Hash of message serials and their message handlers. */   +  DBusHashTable *pending_replies;  /**< Hash of message serials to #DBusPendingCall. */      dbus_uint32_t client_serial;       /**< Client serial. Increments each time a message is sent  */    DBusList *disconnect_message_link; /**< Preallocated list node for queueing the disconnection message */ @@ -184,21 +182,6 @@ struct DBusConnection    DBusObjectRegistry *objects; /**< Objects registered with this connection */  }; -typedef struct -{ -  DBusConnection *connection; -  DBusMessageHandler *handler; -  DBusTimeout *timeout; -  int serial; - -  DBusList *timeout_link; /* Preallocated timeout response */ -   -  dbus_bool_t timeout_added; -  dbus_bool_t connection_added; -} ReplyHandlerData; - -static void reply_handler_data_free (ReplyHandlerData *data); -  static void               _dbus_connection_remove_timeout_locked             (DBusConnection     *connection,                                                                                DBusTimeout        *timeout);  static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked      (DBusConnection     *connection); @@ -283,7 +266,7 @@ void  _dbus_connection_queue_received_message_link (DBusConnection  *connection,                                                DBusList        *link)  { -  ReplyHandlerData *reply_handler_data; +  DBusPendingCall *pending;    dbus_int32_t reply_serial;    DBusMessage *message; @@ -297,14 +280,15 @@ _dbus_connection_queue_received_message_link (DBusConnection  *connection,    reply_serial = dbus_message_get_reply_serial (message);    if (reply_serial != -1)      { -      reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, -							reply_serial); -      if (reply_handler_data != NULL) +      pending = _dbus_hash_table_lookup_int (connection->pending_replies, +                                             reply_serial); +      if (pending != NULL)  	{ -	  if (reply_handler_data->timeout_added) +	  if (pending->timeout_added)  	    _dbus_connection_remove_timeout_locked (connection, -						    reply_handler_data->timeout); -	  reply_handler_data->timeout_added = FALSE; +                                                    pending->timeout); + +	  pending->timeout_added = FALSE;  	}      } @@ -555,6 +539,86 @@ _dbus_connection_notify_disconnected (DBusConnection *connection)      }  } +static dbus_bool_t +_dbus_connection_attach_pending_call_unlocked (DBusConnection  *connection, +                                               DBusPendingCall *pending) +{ +  _dbus_assert (pending->reply_serial != 0); + +  if (!_dbus_connection_add_timeout (connection, pending->timeout)) +    return FALSE; +   +  if (!_dbus_hash_table_insert_int (connection->pending_replies, +                                    pending->reply_serial, +                                    pending)) +    { +      _dbus_connection_remove_timeout (connection, pending->timeout); +      return FALSE; +    } +   +  pending->timeout_added = TRUE; +  pending->connection = connection; + +  dbus_pending_call_ref (pending); +   +  return TRUE; +} + +static void +free_pending_call_on_hash_removal (void *data) +{ +  DBusPendingCall *pending; +   +  if (data == NULL) +    return; + +  pending = data; + +  if (pending->connection) +    { +      if (pending->timeout_added) +        { +          _dbus_connection_remove_timeout (pending->connection, +                                           pending->timeout); +          pending->timeout_added = FALSE; +        } + +      pending->connection = NULL; +       +      dbus_pending_call_unref (pending); +    } +} + +static void +_dbus_connection_detach_pending_call_and_unlock (DBusConnection  *connection, +                                                 DBusPendingCall *pending) +{ +  /* The idea here is to avoid finalizing the pending call +   * with the lock held, since there's a destroy notifier +   * in pending call that goes out to application code. +   */ +  dbus_pending_call_ref (pending); +  _dbus_hash_table_remove_int (connection->pending_replies, +                               pending->reply_serial); +  CONNECTION_UNLOCK (connection); +  dbus_pending_call_unref (pending); +} + +/** + * Removes a pending call from the connection, such that + * the pending reply will be ignored. May drop the last + * reference to the pending call. + * + * @param connection the connection + * @param pending the pending call + */ +void +_dbus_connection_remove_pending_call (DBusConnection  *connection, +                                      DBusPendingCall *pending) +{ +  CONNECTION_LOCK (connection); +  _dbus_connection_detach_pending_call_and_unlock (connection, pending); +}  /**   * Acquire the transporter I/O path. This must be done before @@ -699,7 +763,8 @@ _dbus_connection_new_for_transport (DBusTransport *transport)    pending_replies =      _dbus_hash_table_new (DBUS_HASH_INT, -			  NULL, (DBusFreeFunction)reply_handler_data_free); +			  NULL, +                          (DBusFreeFunction)free_pending_call_on_hash_removal);    if (pending_replies == NULL)      goto error; @@ -1442,6 +1507,28 @@ dbus_connection_send_preallocated (DBusConnection       *connection,    CONNECTION_UNLOCK (connection);    } +static dbus_bool_t +_dbus_connection_send_unlocked (DBusConnection *connection, +                                DBusMessage    *message, +                                dbus_uint32_t  *client_serial) +{ +  DBusPreallocatedSend *preallocated; + +  _dbus_assert (connection != NULL); +  _dbus_assert (message != NULL); +   +  preallocated = _dbus_connection_preallocate_send_unlocked (connection); +  if (preallocated == NULL) +    return FALSE; + + +  _dbus_connection_send_preallocated_unlocked (connection, +                                               preallocated, +                                               message, +                                               client_serial); +  return TRUE; +} +  /**   * Adds a message to the outgoing message queue. Does not block to   * write the message to the network; that happens asynchronously. To @@ -1465,50 +1552,41 @@ dbus_connection_send (DBusConnection *connection,                        DBusMessage    *message,                        dbus_uint32_t  *client_serial)  { -  DBusPreallocatedSend *preallocated; -    _dbus_return_val_if_fail (connection != NULL, FALSE);    _dbus_return_val_if_fail (message != NULL, FALSE);    CONNECTION_LOCK (connection); -   -  preallocated = _dbus_connection_preallocate_send_unlocked (connection); -  if (preallocated == NULL) + +  if (!_dbus_connection_send_unlocked (connection, message, client_serial))      {        CONNECTION_UNLOCK (connection);        return FALSE;      } -  else -    { -      _dbus_connection_send_preallocated_unlocked (connection, -                                                   preallocated, -                                                   message, -                                                   client_serial); -      CONNECTION_UNLOCK (connection); -      return TRUE; -    } + +  CONNECTION_UNLOCK (connection); +  return TRUE;  }  static dbus_bool_t  reply_handler_timeout (void *data)  {    DBusConnection *connection; -  ReplyHandlerData *reply_handler_data = data;    DBusDispatchStatus status; +  DBusPendingCall *pending = data; -  connection = reply_handler_data->connection; +  connection = pending->connection;    CONNECTION_LOCK (connection); -  if (reply_handler_data->timeout_link) +  if (pending->timeout_link)      {        _dbus_connection_queue_synthesized_message_link (connection, -						       reply_handler_data->timeout_link); -      reply_handler_data->timeout_link = NULL; +						       pending->timeout_link); +      pending->timeout_link = NULL;      }    _dbus_connection_remove_timeout (connection, -				   reply_handler_data->timeout); -  reply_handler_data->timeout_added = FALSE; +				   pending->timeout); +  pending->timeout_added = FALSE;    status = _dbus_connection_get_dispatch_status_unlocked (connection); @@ -1518,52 +1596,29 @@ reply_handler_timeout (void *data)    return TRUE;  } -static void -reply_handler_data_free (ReplyHandlerData *data) -{ -  if (!data) -    return; - -  if (data->timeout_added) -    _dbus_connection_remove_timeout_locked (data->connection, -					    data->timeout); - -  if (data->connection_added) -    _dbus_message_handler_remove_connection (data->handler, -					     data->connection); - -  if (data->timeout_link) -    { -      dbus_message_unref ((DBusMessage *)data->timeout_link->data); -      _dbus_list_free_link (data->timeout_link); -    } -   -  dbus_message_handler_unref (data->handler); -   -  dbus_free (data); -} -  /**   * Queues a message to send, as with dbus_connection_send_message(), - * but also sets up a DBusMessageHandler to receive a reply to the + * but also returns a #DBusPendingCall used to receive a reply to the   * message. If no reply is received in the given timeout_milliseconds, - * expires the pending reply and sends the DBusMessageHandler a - * synthetic error reply (generated in-process, not by the remote - * application) indicating that a timeout occurred. - * - * Reply handlers see their replies after message filters see them, - * but before message handlers added with - * dbus_connection_register_handler() see them, regardless of the - * reply message's name. Reply handlers are only handed a single - * message as a reply, after one reply has been seen the handler is - * removed. If a filter filters out the reply before the handler sees - * it, the reply is immediately timed out and a timeout error reply is + * this function expires the pending reply and generates a synthetic + * error reply (generated in-process, not by the remote application) + * indicating that a timeout occurred. + * + * A #DBusPendingCall will see a reply message after any filters, but + * before any object instances or other handlers. A #DBusPendingCall + * will always see exactly one reply message, unless it's cancelled + * with dbus_pending_call_cancel(). + *  + * If a filter filters out the reply before the handler sees it, the + * reply is immediately timed out and a timeout error reply is   * generated. If a filter removes the timeout error reply then the - * reply handler will never be called. Filters should not do this. + * #DBusPendingCall will get confused. Filtering the timeout error + * is thus considered a bug and will print a warning.   *  - * If #NULL is passed for the reply_handler, the timeout reply will - * still be generated and placed into the message queue, but no - * specific message handler will receive the reply. + * If #NULL is passed for the pending_return, the #DBusPendingCall + * will still be generated internally, and used to track + * the message reply timeout. This means a timeout error will + * occur if no reply arrives, unlike with dbus_connection_send().   *   * If -1 is passed for the timeout, a sane default timeout is used. -1   * is typically the best value for the timeout for this reason, unless @@ -1573,7 +1628,7 @@ reply_handler_data_free (ReplyHandlerData *data)   *    * @param connection the connection   * @param message the message to send - * @param reply_handler message handler expecting the reply, or #NULL + * @param pending_return return location for a #DBusPendingCall object, or #NULL   * @param timeout_milliseconds timeout in milliseconds or -1 for default   * @returns #TRUE if the message is successfully queued, #FALSE if no memory.   * @@ -1581,63 +1636,30 @@ reply_handler_data_free (ReplyHandlerData *data)  dbus_bool_t  dbus_connection_send_with_reply (DBusConnection     *connection,                                   DBusMessage        *message, -                                 DBusMessageHandler *reply_handler, +                                 DBusPendingCall   **pending_return,                                   int                 timeout_milliseconds)  { -  DBusTimeout *timeout; -  ReplyHandlerData *data; +  DBusPendingCall *pending;    DBusMessage *reply;    DBusList *reply_link;    dbus_int32_t serial = -1;    _dbus_return_val_if_fail (connection != NULL, FALSE);    _dbus_return_val_if_fail (message != NULL, FALSE); -  _dbus_return_val_if_fail (reply_handler != NULL, FALSE);    _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); -   -  if (timeout_milliseconds == -1) -    timeout_milliseconds = DEFAULT_TIMEOUT_VALUE; -  data = dbus_new0 (ReplyHandlerData, 1); - -  if (!data) -    return FALSE; +  if (pending_return) +    *pending_return = NULL; -  timeout = _dbus_timeout_new (timeout_milliseconds, reply_handler_timeout, -			       data, NULL); +  pending = _dbus_pending_call_new (connection, +                                    timeout_milliseconds, +                                    reply_handler_timeout); -  if (!timeout) -    { -      reply_handler_data_free (data); -      return FALSE; -    } +  if (pending == NULL) +    return FALSE;    CONNECTION_LOCK (connection); -  /* Add timeout */ -  if (!_dbus_connection_add_timeout (connection, timeout)) -    { -      reply_handler_data_free (data); -      _dbus_timeout_unref (timeout); -      CONNECTION_UNLOCK (connection); -      return FALSE; -    } - -  /* The connection now owns the reference to the timeout. */ -  _dbus_timeout_unref (timeout); -   -  data->timeout_added = TRUE; -  data->timeout = timeout; -  data->connection = connection; -   -  if (!_dbus_message_handler_add_connection (reply_handler, connection)) -    { -      CONNECTION_UNLOCK (connection); -      reply_handler_data_free (data); -      return FALSE; -    } -  data->connection_added = TRUE; -      /* Assign a serial to the message */    if (dbus_message_get_serial (message) == 0)      { @@ -1645,17 +1667,14 @@ dbus_connection_send_with_reply (DBusConnection     *connection,        _dbus_message_set_serial (message, serial);      } -  data->handler = reply_handler; -  data->serial = serial; - -  dbus_message_handler_ref (reply_handler); +  pending->reply_serial = serial;    reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,                                    "No reply within specified time");    if (!reply)      {        CONNECTION_UNLOCK (connection); -      reply_handler_data_free (data); +      dbus_pending_call_unref (pending);        return FALSE;      } @@ -1664,33 +1683,42 @@ dbus_connection_send_with_reply (DBusConnection     *connection,      {        CONNECTION_UNLOCK (connection);        dbus_message_unref (reply); -      reply_handler_data_free (data); +      dbus_pending_call_unref (pending);        return FALSE;      } -  data->timeout_link = reply_link; -   -  /* Insert the serial in the pending replies hash. */ -  if (!_dbus_hash_table_insert_int (connection->pending_replies, serial, data)) +  pending->timeout_link = reply_link; + +  /* Insert the serial in the pending replies hash; +   * hash takes a refcount on DBusPendingCall. +   * Also, add the timeout. +   */ +  if (!_dbus_connection_attach_pending_call_unlocked (connection, +                                                      pending))      {        CONNECTION_UNLOCK (connection); -      reply_handler_data_free (data);       +      dbus_pending_call_unref (pending);        return FALSE;      } - -  CONNECTION_UNLOCK (connection); -  if (!dbus_connection_send (connection, message, NULL)) +  if (!_dbus_connection_send_unlocked (connection, message, NULL))      { -      /* This will free the handler data too */ -      _dbus_hash_table_remove_int (connection->pending_replies, serial); +      _dbus_connection_detach_pending_call_and_unlock (connection, +                                                       pending);        return FALSE;      } +  if (pending_return) +    { +      dbus_pending_call_ref (pending); +      *pending_return = pending; +    } + +  CONNECTION_UNLOCK (connection); +      return TRUE;  } -  static DBusMessage*  check_for_reply_unlocked (DBusConnection *connection,                            dbus_uint32_t   client_serial) @@ -1755,7 +1783,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,    _dbus_return_val_if_error_is_set (error, NULL);    if (timeout_milliseconds == -1) -    timeout_milliseconds = DEFAULT_TIMEOUT_VALUE; +    timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;    /* it would probably seem logical to pass in _DBUS_INT_MAX     * for infinite timeout, but then math below would get @@ -2283,7 +2311,7 @@ dbus_connection_dispatch (DBusConnection *connection)    DBusMessage *message;    DBusList *link, *filter_list_copy, *message_link;    DBusHandlerResult result; -  ReplyHandlerData *reply_handler_data; +  DBusPendingCall *pending;    dbus_int32_t reply_serial;    DBusDispatchStatus status; @@ -2332,8 +2360,8 @@ dbus_connection_dispatch (DBusConnection *connection)    result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;    reply_serial = dbus_message_get_reply_serial (message); -  reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, -						    reply_serial); +  pending = _dbus_hash_table_lookup_int (connection->pending_replies, +                                         reply_serial);    if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy))      { @@ -2386,34 +2414,42 @@ dbus_connection_dispatch (DBusConnection *connection)      goto out;    /* Did a reply we were waiting on get filtered? */ -  if (reply_handler_data && result == DBUS_HANDLER_RESULT_HANDLED) +  if (pending && result == DBUS_HANDLER_RESULT_HANDLED)      {        /* Queue the timeout immediately! */ -      if (reply_handler_data->timeout_link) +      if (pending->timeout_link)  	{  	  _dbus_connection_queue_synthesized_message_link (connection, -							   reply_handler_data->timeout_link); -	  reply_handler_data->timeout_link = NULL; +							   pending->timeout_link); +	  pending->timeout_link = NULL;  	}        else  	{  	  /* We already queued the timeout? Then it was filtered! */ -	  _dbus_warn ("The timeout error with reply serial %d was filtered, so the reply handler will never be called.\n", reply_serial); +	  _dbus_warn ("The timeout error with reply serial %d was filtered, so the DBusPendingCall will never stop pending.\n", reply_serial);  	}      }    if (result == DBUS_HANDLER_RESULT_HANDLED)      goto out; -  if (reply_handler_data) +  if (pending)      { -      CONNECTION_UNLOCK (connection); +      _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_verbose ("  running reply handler on message %p\n", message); +      pending = NULL; -      result = _dbus_message_handler_handle_message (reply_handler_data->handler, -						     connection, message); -      reply_handler_data_free (reply_handler_data);        CONNECTION_LOCK (connection);        goto out;      } diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 7bf1221a..ef106524 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -37,6 +37,7 @@ typedef struct DBusWatch DBusWatch;  typedef struct DBusTimeout DBusTimeout;  typedef struct DBusMessageHandler DBusMessageHandler;  typedef struct DBusPreallocatedSend DBusPreallocatedSend; +typedef struct DBusPendingCall DBusPendingCall;  typedef enum  { @@ -76,6 +77,9 @@ typedef dbus_bool_t (* DBusAllowUnixUserFunction)  (DBusConnection *connection,                                                      unsigned long   uid,                                                      void           *data); +typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, +                                                void            *user_data); +  DBusConnection*    dbus_connection_open                         (const char                 *address,                                                                   DBusError                  *error);  void               dbus_connection_ref                          (DBusConnection             *connection); @@ -97,7 +101,7 @@ dbus_bool_t        dbus_connection_send                         (DBusConnection                                                                   dbus_uint32_t              *client_serial);  dbus_bool_t        dbus_connection_send_with_reply              (DBusConnection             *connection,                                                                   DBusMessage                *message, -                                                                 DBusMessageHandler         *reply_handler, +                                                                 DBusPendingCall           **pending_return,                                                                   int                         timeout_milliseconds);  DBusMessage *      dbus_connection_send_with_reply_and_block    (DBusConnection             *connection,                                                                   DBusMessage                *message, diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 7a65ad62..84ca7ae0 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -22,11 +22,11 @@   */  #include "dbus-internals.h" -#include "dbus-message-pending.h" +#include "dbus-connection-internal.h" +#include "dbus-pending-call.h"  #include "dbus-list.h"  #include "dbus-threads.h"  #include "dbus-test.h" -#include "dbus-connection-internal.h"  /**   * @defgroup DBusPendingCallInternals DBusPendingCall implementation details @@ -39,55 +39,64 @@   */  /** - * @brief Internals of DBusPendingCall - * - * Object representing a reply message that we're waiting for. - */ -struct DBusPendingCall -{ -  DBusAtomic refcount;                            /**< reference count */ - -  DBusPendingCallNotifyFunction function;         /**< Notifier when reply arrives. */ -  void                     *user_data;            /**< user data for function */ -  DBusFreeFunction          free_user_data;       /**< free the user data */ - -  DBusConnection *connection;                     /**< Connections we're associated with */ -  DBusMessage *reply;                             /**< Reply (after we've received it) */ -  DBusTimeout *timeout;                           /**< Timeout */ - -  DBusList *timeout_link;                         /**< Preallocated timeout response */ -   -  dbus_uint32_t reply_serial;                     /**< Expected serial of reply */ - -  unsigned int completed : 1;                     /**< TRUE if completed */ -  unsigned int timeout_added : 1;                 /**< Have added the timeout */ -}; - -/**   * Creates a new pending reply object.   *   * @param connection connection where reply will arrive - * @param reply_serial reply serial of the expected reply + * @param timeout_milliseconds length of timeout, -1 for default + * @param timeout_handler timeout handler, takes pending call as data   * @returns a new #DBusPendingCall or #NULL if no memory.   */  DBusPendingCall* -_dbus_pending_call_new (DBusConnection *connection, -                       dbus_uint32_t    reply_serial) +_dbus_pending_call_new (DBusConnection    *connection, +                        int                timeout_milliseconds, +                        DBusTimeoutHandler timeout_handler)  {    DBusPendingCall *pending; +  DBusTimeout *timeout; +  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); +   +  if (timeout_milliseconds == -1) +    timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; +      pending = dbus_new (DBusPendingCall, 1);    if (pending == NULL)      return NULL; +  timeout = _dbus_timeout_new (timeout_milliseconds, +                               timeout_handler, +			       pending, NULL);   + +  if (timeout == NULL) +    { +      dbus_free (pending); +      return NULL; +    } +      pending->refcount.value = 1;    pending->connection = connection; -  pending->reply_serial = reply_serial; - +  pending->timeout = timeout; +      return pending;  } +/** + * Calls notifier function for the pending call + * and sets the call to completed. + * + * @param pending the pending call + *  + */ +void +_dbus_pending_call_notify (DBusPendingCall *pending) +{ +  pending->completed = TRUE; + +  if (pending->function) +    (* pending->function) (pending, pending->user_data); +} +  /** @} */  /** @@ -138,14 +147,24 @@ dbus_pending_call_unref (DBusPendingCall *pending)    if (last_unref)      { +      /* If we get here, we should be already detached +       * from the connection, or never attached. +       */ +      _dbus_assert (pending->connection == NULL); +      _dbus_assert (!pending->timeout_added);   + +      /* this assumes we aren't holding connection lock... */        if (pending->free_user_data)          (* pending->free_user_data) (pending->user_data); - -      if (pending->connection != NULL) +      if (pending->timeout != NULL) +        _dbus_timeout_unref (pending->timeout); +       +      if (pending->timeout_link)          { -          _dbus_connection_pending_destroyed_locked (connection, pending); -          pending->connection = NULL; +          dbus_message_unref ((DBusMessage *)pending->timeout_link->data); +          _dbus_list_free_link (pending->timeout_link); +          pending->timeout_link = NULL;          }        if (pending->reply) @@ -179,37 +198,66 @@ dbus_pending_call_set_notify (DBusPendingCall              *pending,    _dbus_return_if_fail (pending != NULL); -  _DBUS_LOCK (pending_call);    old_free_func = pending->free_user_data;    old_user_data = pending->user_data;    pending->user_data = user_data;    pending->free_user_data = free_user_data;    pending->function = function; -  _DBUS_UNLOCK (pending_call);    if (old_free_func)      (* old_free_func) (old_user_data);  } -/** @} */ +/** + * Cancels the pending call, such that any reply + * or error received will just be ignored. + * Drops at least one reference to the #DBusPendingCall + * so will free the call if nobody else is holding + * a reference. + *  + * @param pending the pending call + */ +void +dbus_pending_call_cancel (DBusPendingCall *pending) +{ +  if (pending->connection) +    _dbus_connection_remove_pending_call (pending->connection, +                                          pending); +} -#ifdef DBUS_BUILD_TESTS -static DBusPendingResult -test_pending (DBusPendingCall *pending, -              DBusConnection     *connection, -              DBusMessage        *message, -              void               *user_data) +/** + * Checks whether the pending call has received a reply + * yet, or not. + * + * @param pending the pending call + * @returns #TRUE if a reply has been received + */ +dbus_bool_t +dbus_pending_call_get_completed (DBusPendingCall *pending)  { -  return DBUS_PENDING_RESULT_NOT_YET_HANDLED; +  return pending->completed;  } -static void -free_test_data (void *data) +/** + * Gets the reply, or returns #NULL if none has been received yet. The + * reference count is not incremented on the returned message, so you + * have to keep a reference count on the pending call (or add one + * to the message). + * + * @param pending the pending call + * @returns the reply message or #NULL. + */ +DBusMessage* +dbus_pending_call_get_reply (DBusPendingCall *pending)  { -  /* does nothing */ +  return pending->reply;  } +/** @} */ + +#ifdef DBUS_BUILD_TESTS +  /**   * @ingroup DBusPendingCallInternals   * Unit test for DBusPendingCall. diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h index ff2c176a..66f1bac5 100644 --- a/dbus/dbus-pending-call.h +++ b/dbus/dbus-pending-call.h @@ -33,23 +33,16 @@  DBUS_BEGIN_DECLS; -typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, -                                                void            *user_data); - -DBusPendingCall* _dbus_pending_call_new          (DBusConnection   *connection, -                                                  dbus_uint32_t     reply_serial); -  void         dbus_pending_call_ref           (DBusPendingCall               *pending);  void         dbus_pending_call_unref         (DBusPendingCall               *pending);  void         dbus_pending_call_set_notify    (DBusPendingCall               *pending,                                                DBusPendingCallNotifyFunction  function,                                                void                          *user_data,                                                DBusFreeFunction               free_user_data); +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); - -  DBUS_END_DECLS;  #endif /* DBUS_PENDING_CALL_H */ diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index c3b31107..8a99d179 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -197,6 +197,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)      die ("auth");    check_memleaks (); + +  printf ("%s: running pending call tests\n", "dbus-test"); +  if (!_dbus_pending_call_test (test_data_dir)) +    die ("auth"); + +  check_memleaks ();    printf ("%s: completed successfully\n", "dbus-test");  #else diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index 8537be40..276e8f9e 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -56,7 +56,7 @@ dbus_bool_t _dbus_memory_test	       (void);  dbus_bool_t _dbus_object_test          (void);  dbus_bool_t _dbus_object_id_test       (void);  dbus_bool_t _dbus_object_registry_test (void); - +dbus_bool_t _dbus_pending_call_test    (const char *test_data_dir);  void        dbus_internal_do_not_use_run_tests         (const char          *test_data_dir);  dbus_bool_t dbus_internal_do_not_use_try_message_file  (const DBusString    *filename, diff --git a/dbus/dbus.h b/dbus/dbus.h index d83a4a50..12a087f5 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -40,6 +40,7 @@  #include <dbus/dbus-message-handler.h>  #include <dbus/dbus-object.h>  #include <dbus/dbus-objectid.h> +#include <dbus/dbus-pending-call.h>  #include <dbus/dbus-protocol.h>  #include <dbus/dbus-server.h>  #include <dbus/dbus-threads.h>  | 
