From e3dc6e281aae288e995f9d6a2675662ac3d0749f Mon Sep 17 00:00:00 2001 From: "John (J5) Palmieri" Date: Wed, 12 Jul 2006 15:57:01 +0000 Subject: - Make DBusPendingCall an opaque type even to D-Bus internals --- dbus/dbus-connection-internal.h | 33 +----- dbus/dbus-connection.c | 175 +++++++++++------------------ dbus/dbus-pending-call-internal.h | 64 +++++++++++ dbus/dbus-pending-call.c | 225 +++++++++++++++++++++++++++++++++++++- dbus/dbus-pending-call.h | 1 - 5 files changed, 356 insertions(+), 142 deletions(-) create mode 100644 dbus/dbus-pending-call-internal.h (limited to 'dbus') diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 644793a9..adf17862 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -91,37 +91,8 @@ dbus_bool_t _dbus_connection_send_and_unlock (DBusConnection DBusMessage *message, dbus_uint32_t *client_serial); -/** - * @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 */ - - DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ - - DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ - - 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 */ - +void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, + DBusList *link); DBUS_END_DECLS diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 62a23838..169b474e 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -29,6 +29,7 @@ #include "dbus-transport.h" #include "dbus-watch.h" #include "dbus-connection-internal.h" +#include "dbus-pending-call-internal.h" #include "dbus-list.h" #include "dbus-hash.h" #include "dbus-message-internal.h" @@ -377,11 +378,11 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, reply_serial); if (pending != NULL) { - if (pending->timeout_added) + if (_dbus_pending_call_is_timeout_added (pending)) _dbus_connection_remove_timeout_unlocked (connection, - pending->timeout); + _dbus_pending_call_get_timeout (pending)); - pending->timeout_added = FALSE; + _dbus_pending_call_set_timeout_added (pending, FALSE); } } @@ -404,8 +405,7 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, dbus_message_get_signature (message), dbus_message_get_reply_serial (message), connection, - connection->n_incoming); -} + connection->n_incoming);} /** * Adds a link + message to the incoming message queue. @@ -417,7 +417,7 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, * @todo This needs to wake up the mainloop if it is in * a poll/select and this is a multithreaded app. */ -static void +void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, DBusList *link) { @@ -776,25 +776,31 @@ static dbus_bool_t _dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, DBusPendingCall *pending) { + dbus_uint32_t reply_serial; + DBusTimeout *timeout; + HAVE_LOCK_CHECK (connection); - - _dbus_assert (pending->reply_serial != 0); - if (!_dbus_connection_add_timeout_unlocked (connection, pending->timeout)) + reply_serial = _dbus_pending_call_get_reply_serial (pending); + + _dbus_assert (reply_serial != 0); + + timeout = _dbus_pending_call_get_timeout (pending); + + if (!_dbus_connection_add_timeout_unlocked (connection, timeout)) return FALSE; if (!_dbus_hash_table_insert_int (connection->pending_replies, - pending->reply_serial, + reply_serial, pending)) { - _dbus_connection_remove_timeout_unlocked (connection, pending->timeout); + _dbus_connection_remove_timeout_unlocked (connection, timeout); HAVE_LOCK_CHECK (connection); return FALSE; } - pending->timeout_added = TRUE; - pending->connection = connection; + _dbus_pending_call_set_timeout_added (pending, TRUE); dbus_pending_call_ref (pending); @@ -807,23 +813,26 @@ static void free_pending_call_on_hash_removal (void *data) { DBusPendingCall *pending; - + DBusConnection *connection; + if (data == NULL) return; pending = data; - if (pending->connection) + connection = _dbus_pending_call_get_connection (pending); + + if (connection) { - if (pending->timeout_added) + if (_dbus_pending_call_is_timeout_added (pending)) { - _dbus_connection_remove_timeout_unlocked (pending->connection, - pending->timeout); - pending->timeout_added = FALSE; - } - - pending->connection = NULL; + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout (pending)); + _dbus_pending_call_set_timeout_added (pending, FALSE); + } + + _dbus_pending_call_clear_connection (pending); dbus_pending_call_unref (pending); } } @@ -836,8 +845,7 @@ _dbus_connection_detach_pending_call_unlocked (DBusConnection *connection, dbus_pending_call_ref (pending); _dbus_hash_table_remove_int (connection->pending_replies, - pending->reply_serial); - _dbus_assert (pending->connection == NULL); + _dbus_pending_call_get_reply_serial (pending)); dbus_pending_call_unref (pending); } @@ -851,8 +859,7 @@ _dbus_connection_detach_pending_call_and_unlock (DBusConnection *connection, */ dbus_pending_call_ref (pending); _dbus_hash_table_remove_int (connection->pending_replies, - pending->reply_serial); - _dbus_assert (pending->connection == NULL); + _dbus_pending_call_get_reply_serial (pending)); CONNECTION_UNLOCK (connection); dbus_pending_call_unref (pending); } @@ -873,46 +880,6 @@ _dbus_connection_remove_pending_call (DBusConnection *connection, _dbus_connection_detach_pending_call_and_unlock (connection, pending); } -/** - * 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); - } - else - dbus_message_ref (message); - - _dbus_verbose (" handing message %p (%s) to pending call serial %u\n", - message, - dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? - "method return" : - dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? - "error" : "other type", - pending->reply_serial); - - _dbus_assert (pending->reply == NULL); - _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message)); - pending->reply = message; - - 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 @@ -2342,19 +2309,14 @@ reply_handler_timeout (void *data) DBusDispatchStatus status; DBusPendingCall *pending = data; - connection = pending->connection; + connection = _dbus_pending_call_get_connection (pending); CONNECTION_LOCK (connection); - if (pending->timeout_link) - { - _dbus_connection_queue_synthesized_message_link (connection, - pending->timeout_link); - pending->timeout_link = NULL; - } - + _dbus_pending_call_queue_timeout_error (pending, + connection); _dbus_connection_remove_timeout_unlocked (connection, - pending->timeout); - pending->timeout_added = FALSE; + _dbus_pending_call_get_timeout (pending)); + _dbus_pending_call_set_timeout_added (pending, FALSE); _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); @@ -2409,8 +2371,6 @@ dbus_connection_send_with_reply (DBusConnection *connection, int timeout_milliseconds) { DBusPendingCall *pending; - DBusMessage *reply; - DBusList *reply_link; dbus_int32_t serial = -1; DBusDispatchStatus status; @@ -2431,29 +2391,16 @@ dbus_connection_send_with_reply (DBusConnection *connection, CONNECTION_LOCK (connection); /* Assign a serial to the message */ - if (dbus_message_get_serial (message) == 0) + serial = dbus_message_get_serial (message); + if (serial == 0) { serial = _dbus_connection_get_next_client_serial (connection); _dbus_message_set_serial (message, serial); } - pending->reply_serial = serial; - - reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, - "No reply within specified time"); - if (reply == NULL) + if (!_dbus_pending_call_set_timeout_error (pending, message, serial)) goto error; - - reply_link = _dbus_list_alloc_link (reply); - if (reply_link == NULL) - { - CONNECTION_UNLOCK (connection); - dbus_message_unref (reply); - goto error_unlocked; - } - - pending->timeout_link = reply_link; - + /* Insert the serial in the pending replies hash; * hash takes a refcount on DBusPendingCall. * Also, add the timeout. @@ -2521,6 +2468,19 @@ check_for_reply_unlocked (DBusConnection *connection, return NULL; } +static void +complete_pending_call_and_unlock (DBusPendingCall *pending, + DBusMessage *message) +{ + _dbus_pending_call_set_reply (pending, message); + dbus_pending_call_ref (pending); /* in case there's no app with a ref held */ + _dbus_connection_detach_pending_call_and_unlock (_dbus_pending_call_get_connection (pending), pending); + + /* Must be called unlocked since it invokes app callback */ + _dbus_pending_call_complete (pending); + dbus_pending_call_unref (pending); +} + static dbus_bool_t check_for_reply_and_update_dispatch_unlocked (DBusPendingCall *pending) { @@ -2528,16 +2488,17 @@ check_for_reply_and_update_dispatch_unlocked (DBusPendingCall *pending) DBusDispatchStatus status; DBusConnection *connection; - connection = pending->connection; + connection = _dbus_pending_call_get_connection (pending); - reply = check_for_reply_unlocked (connection, pending->reply_serial); + reply = check_for_reply_unlocked (connection, + _dbus_pending_call_get_reply_serial (pending)); if (reply != NULL) { _dbus_verbose ("%s checked for reply\n", _DBUS_FUNCTION_NAME); _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n"); - _dbus_pending_call_complete_and_unlock (pending, reply); + complete_pending_call_and_unlock (pending, reply); dbus_message_unref (reply); CONNECTION_LOCK (connection); @@ -2603,19 +2564,18 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) if (dbus_pending_call_get_completed (pending)) return; - if (pending->connection == NULL) + connection = _dbus_pending_call_get_connection (pending); + if (connection == NULL) return; /* call already detached */ dbus_pending_call_ref (pending); /* necessary because the call could be canceled */ - - connection = pending->connection; - client_serial = pending->reply_serial; + client_serial = _dbus_pending_call_get_reply_serial (pending); /* note that timeout_milliseconds is limited to a smallish value * in _dbus_pending_call_new() so overflows aren't possible * below */ - timeout_milliseconds = dbus_timeout_get_interval (pending->timeout); + timeout_milliseconds = dbus_timeout_get_interval (_dbus_pending_call_get_timeout (pending)); /* Flush message queue */ dbus_connection_flush (connection); @@ -2680,7 +2640,7 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) * confusing */ - _dbus_pending_call_complete_and_unlock (pending, NULL); + complete_pending_call_and_unlock (pending, NULL); dbus_pending_call_unref (pending); return; } @@ -2724,7 +2684,7 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) _dbus_assert (!dbus_pending_call_get_completed (pending)); /* unlock and call user code */ - _dbus_pending_call_complete_and_unlock (pending, NULL); + complete_pending_call_and_unlock (pending, NULL); /* update user code on dispatch status */ CONNECTION_LOCK (connection); @@ -3585,7 +3545,7 @@ dbus_connection_dispatch (DBusConnection *connection) if (pending) { _dbus_verbose ("Dispatching a pending reply\n"); - _dbus_pending_call_complete_and_unlock (pending, message); + complete_pending_call_and_unlock (pending, message); pending = NULL; /* it's probably unref'd */ CONNECTION_LOCK (connection); @@ -3773,9 +3733,6 @@ dbus_connection_dispatch (DBusConnection *connection) DBUS_INTERFACE_LOCAL, "Disconnected")) { - int i; - - _dbus_bus_check_connection_and_unref (connection); if (connection->exit_on_disconnect) { diff --git a/dbus/dbus-pending-call-internal.h b/dbus/dbus-pending-call-internal.h new file mode 100644 index 00000000..21475e24 --- /dev/null +++ b/dbus/dbus-pending-call-internal.h @@ -0,0 +1,64 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-pending-call-internal.h DBusPendingCall internal interfaces + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_PENDING_CALL_INTERNAL_H +#define DBUS_PENDING_CALL_INTERNAL_H + + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +dbus_bool_t _dbus_pending_call_is_timeout_added (DBusPendingCall *pending); +void _dbus_pending_call_set_timeout_added (DBusPendingCall *pending, + dbus_bool_t is_added); +DBusTimeout *_dbus_pending_call_get_timeout (DBusPendingCall *pending); +dbus_uint32_t _dbus_pending_call_get_reply_serial (DBusPendingCall *pending); +void _dbus_pending_call_set_reply_serial (DBusPendingCall *pending, + dbus_uint32_t serial); +DBusConnection *_dbus_pending_call_get_connection (DBusPendingCall *pending); +void _dbus_pending_call_set_connection (DBusPendingCall *pending, + DBusConnection *connection); + +void _dbus_pending_call_complete (DBusPendingCall *pending); +void _dbus_pending_call_set_reply (DBusPendingCall *pending, + DBusMessage *message); +void _dbus_pending_call_clear_connection (DBusPendingCall *pending); + +void _dbus_pending_call_queue_timeout_error (DBusPendingCall *pending, + DBusConnection *connection); +void _dbus_pending_call_set_reply_serial (DBusPendingCall *pending, + dbus_uint32_t serial); +dbus_bool_t _dbus_pending_call_set_timeout_error (DBusPendingCall *pending, + DBusMessage *message, + dbus_uint32_t serial); +DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, + int timeout_milliseconds, + DBusTimeoutHandler timeout_handler); + + +DBUS_END_DECLS + +#endif /* DBUS_PENDING_CALL_INTERNAL_H */ diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 546f42a6..66573f66 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -23,6 +23,7 @@ #include "dbus-internals.h" #include "dbus-connection-internal.h" +#include "dbus-pending-call-internal.h" #include "dbus-pending-call.h" #include "dbus-list.h" #include "dbus-threads.h" @@ -38,6 +39,31 @@ * @{ */ +/** + * @brief Internals of DBusPendingCall + * + * Opaque object representing a reply message that we're waiting for. + */ +struct DBusPendingCall +{ + DBusAtomic refcount; /**< reference count */ + + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + + DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ + + 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 */ +}; + static dbus_int32_t notify_user_data_slot = -1; /** @@ -100,6 +126,39 @@ _dbus_pending_call_new (DBusConnection *connection, return pending; } +/** + * Sets the reply of 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_set_reply (DBusPendingCall *pending, + DBusMessage *message) +{ + if (message == NULL) + { + message = pending->timeout_link->data; + _dbus_list_clear (&pending->timeout_link); + } + else + dbus_message_ref (message); + + _dbus_verbose (" handing message %p (%s) to pending call serial %u\n", + message, + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? + "method return" : + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? + "error" : "other type", + pending->reply_serial); + + _dbus_assert (pending->reply == NULL); + _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message)); + pending->reply = message; +} + /** * Calls notifier function for the pending call * and sets the call to completed. @@ -108,7 +167,7 @@ _dbus_pending_call_new (DBusConnection *connection, * */ void -_dbus_pending_call_notify (DBusPendingCall *pending) +_dbus_pending_call_complete (DBusPendingCall *pending) { _dbus_assert (!pending->completed); @@ -124,6 +183,170 @@ _dbus_pending_call_notify (DBusPendingCall *pending) } } +void +_dbus_pending_call_queue_timeout_error (DBusPendingCall *pending, + DBusConnection *connection) +{ + if (pending->timeout_link) + { + _dbus_connection_queue_synthesized_message_link (connection, + pending->timeout_link); + pending->timeout_link = NULL; + } +} + +/** + * Checks to see if a timeout has been added + * + * @param pending the pending_call + * @returns #TRUE if there is a timeout or #FALSE if not + */ +dbus_bool_t +_dbus_pending_call_is_timeout_added (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->timeout_added; +} + + +/** + * Sets wether the timeout has been added + * + * @param pending the pending_call + * @param is_added whether or not a timeout is added + */ +void +_dbus_pending_call_set_timeout_added (DBusPendingCall *pending, + dbus_bool_t is_added) +{ + _dbus_assert (pending != NULL); + + pending->timeout_added = is_added; +} + + +/** + * Retrives the timeout + * + * @param pending the pending_call + * @returns a timeout object + */ +DBusTimeout * +_dbus_pending_call_get_timeout (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->timeout; +} + +/** + * Gets the reply's serial number + * + * @param pending the pending_call + * @returns a serial number for the reply or 0 + */ +dbus_uint32_t +_dbus_pending_call_get_reply_serial (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->reply_serial; +} + +/** + * Sets the reply's serial number + * + * @param pending the pending_call + * @param serial the serial number + */ +void +_dbus_pending_call_set_reply_serial (DBusPendingCall *pending, + dbus_uint32_t serial) +{ + _dbus_assert (pending != NULL); + _dbus_assert (pending->reply_serial == 0); + + pending->reply_serial = serial; +} + +/** + * Gets the connection associated with this pending call + * + * @param pending the pending_call + * @returns the connection associated with the pending call + */ +DBusConnection * +_dbus_pending_call_get_connection (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->connection; +} + +/** + * Sets the connection associated with the pending call + * + * @param pending the pending_call + * @param connection the connection which is associated with the pending call + */ +void +_dbus_pending_call_set_connection (DBusPendingCall *pending, + DBusConnection *connection) +{ + _dbus_assert (pending != NULL); + + pending->connection = connection; +} + +/** + * NULLs out the connection + * + * @param pending the pending_call + */ +void +_dbus_pending_call_clear_connection (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + pending->connection = NULL; +} + +/** + * Sets the reply message associated with the pending call to a timeout error + * + * @param pending the pending_call + * @param message the message we are sending the error reply to + * @param serial serial number for the reply + * @return #FALSE on OOM + */ +dbus_bool_t +_dbus_pending_call_set_timeout_error (DBusPendingCall *pending, + DBusMessage *message, + dbus_uint32_t serial) +{ + DBusList *reply_link; + DBusMessage *reply; + + reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, + "No reply within specified time"); + if (reply == NULL) + return FALSE; + + reply_link = _dbus_list_alloc_link (reply); + if (reply_link == NULL) + { + dbus_message_unref (reply); + return FALSE; + } + + pending->timeout_link = reply_link; + + _dbus_pending_call_set_reply_serial (pending, serial); + + return TRUE; +} + /** @} */ /** diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h index f63fa197..ed2de084 100644 --- a/dbus/dbus-pending-call.h +++ b/dbus/dbus-pending-call.h @@ -52,7 +52,6 @@ dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending, DBusFreeFunction free_data_func); void* dbus_pending_call_get_data (DBusPendingCall *pending, dbus_int32_t slot); - DBUS_END_DECLS #endif /* DBUS_PENDING_CALL_H */ -- cgit