| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ |
| /* dbus-pending-call.c Object representing a call in progress. |
| * |
| * Copyright (C) 2002, 2003 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #include <config.h> |
| #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" |
| #include "dbus-test.h" |
| |
| /** |
| * @defgroup DBusPendingCallInternals DBusPendingCall implementation details |
| * @ingroup DBusInternals |
| * @brief DBusPendingCall private implementation details. |
| * |
| * The guts of DBusPendingCall and its methods. |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief Internals of DBusPendingCall |
| * |
| * Opaque object representing a reply message that we're waiting for. |
| */ |
| |
| /** |
| * shorter and more visible way to write _dbus_connection_lock() |
| */ |
| #define CONNECTION_LOCK(connection) _dbus_connection_lock(connection) |
| /** |
| * shorter and more visible way to write _dbus_connection_unlock() |
| */ |
| #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection) |
| |
| /** |
| * Implementation details of #DBusPendingCall - all fields are private. |
| */ |
| 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; |
| |
| /** |
| * Creates a new pending reply object. |
| * |
| * @param connection connection where reply will arrive |
| * @param timeout_milliseconds length of timeout, -1 for default, INT_MAX for no timeout |
| * @param timeout_handler timeout handler, takes pending call as data |
| * @returns a new #DBusPendingCall or #NULL if no memory. |
| */ |
| DBusPendingCall* |
| _dbus_pending_call_new_unlocked (DBusConnection *connection, |
| int timeout_milliseconds, |
| DBusTimeoutHandler timeout_handler) |
| { |
| DBusPendingCall *pending; |
| DBusTimeout *timeout; |
| |
| _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1); |
| |
| if (timeout_milliseconds == -1) |
| timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; |
| |
| if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) |
| return NULL; |
| |
| pending = dbus_new0 (DBusPendingCall, 1); |
| |
| if (pending == NULL) |
| { |
| dbus_pending_call_free_data_slot (¬ify_user_data_slot); |
| return NULL; |
| } |
| |
| if (timeout_milliseconds != _DBUS_INT_MAX) |
| { |
| timeout = _dbus_timeout_new (timeout_milliseconds, |
| timeout_handler, |
| pending, NULL); |
| |
| if (timeout == NULL) |
| { |
| dbus_pending_call_free_data_slot (¬ify_user_data_slot); |
| dbus_free (pending); |
| return NULL; |
| } |
| |
| pending->timeout = timeout; |
| } |
| else |
| { |
| pending->timeout = NULL; |
| } |
| |
| pending->refcount.value = 1; |
| pending->connection = connection; |
| _dbus_connection_ref_unlocked (pending->connection); |
| |
| _dbus_data_slot_list_init (&pending->slot_list); |
| |
| 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_unlocked (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. |
| * |
| * @param pending the pending call |
| * |
| */ |
| void |
| _dbus_pending_call_complete (DBusPendingCall *pending) |
| { |
| _dbus_assert (!pending->completed); |
| |
| pending->completed = TRUE; |
| |
| if (pending->function) |
| { |
| void *user_data; |
| user_data = dbus_pending_call_get_data (pending, |
| notify_user_data_slot); |
| |
| (* pending->function) (pending, user_data); |
| } |
| } |
| |
| /** |
| * If the pending call hasn't been timed out, add its timeout |
| * error reply to the connection's incoming message queue. |
| * |
| * @param pending the pending call |
| * @param connection the connection the call was sent to |
| */ |
| void |
| _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, |
| DBusConnection *connection) |
| { |
| _dbus_assert (connection == pending->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_unlocked (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_unlocked (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 or NULL if call has no timeout |
| */ |
| DBusTimeout * |
| _dbus_pending_call_get_timeout_unlocked (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_unlocked (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_unlocked (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_and_lock (DBusPendingCall *pending) |
| { |
| _dbus_assert (pending != NULL); |
| |
| CONNECTION_LOCK (pending->connection); |
| return pending->connection; |
| } |
| |
| /** |
| * 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_unlocked (DBusPendingCall *pending) |
| { |
| _dbus_assert (pending != NULL); |
| |
| return pending->connection; |
| } |
| |
| /** |
| * 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_unlocked (DBusPendingCall *pending, |
| DBusMessage *message, |
| dbus_uint32_t serial) |
| { |
| DBusList *reply_link; |
| DBusMessage *reply; |
| |
| reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, |
| "Did not receive a reply. Possible causes include: " |
| "the remote application did not send a reply, " |
| "the message bus security policy blocked the reply, " |
| "the reply timeout expired, or " |
| "the network connection was broken."); |
| 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_unlocked (pending, serial); |
| |
| return TRUE; |
| } |
| |
| /** |
| * Increments the reference count on a pending call, |
| * while the lock on its connection is already held. |
| * |
| * @param pending the pending call object |
| * @returns the pending call object |
| */ |
| DBusPendingCall * |
| _dbus_pending_call_ref_unlocked (DBusPendingCall *pending) |
| { |
| pending->refcount.value += 1; |
| |
| return pending; |
| } |
| |
| |
| static void |
| _dbus_pending_call_last_unref (DBusPendingCall *pending) |
| { |
| DBusConnection *connection; |
| |
| /* If we get here, we should be already detached |
| * from the connection, or never attached. |
| */ |
| _dbus_assert (!pending->timeout_added); |
| |
| connection = pending->connection; |
| |
| /* this assumes we aren't holding connection lock... */ |
| _dbus_data_slot_list_free (&pending->slot_list); |
| |
| if (pending->timeout != NULL) |
| _dbus_timeout_unref (pending->timeout); |
| |
| if (pending->timeout_link) |
| { |
| dbus_message_unref ((DBusMessage *)pending->timeout_link->data); |
| _dbus_list_free_link (pending->timeout_link); |
| pending->timeout_link = NULL; |
| } |
| |
| if (pending->reply) |
| { |
| dbus_message_unref (pending->reply); |
| pending->reply = NULL; |
| } |
| |
| dbus_free (pending); |
| |
| dbus_pending_call_free_data_slot (¬ify_user_data_slot); |
| |
| /* connection lock should not be held. */ |
| /* Free the connection last to avoid a weird state while |
| * calling out to application code where the pending exists |
| * but not the connection. |
| */ |
| dbus_connection_unref (connection); |
| } |
| |
| /** |
| * Decrements the reference count on a pending call, |
| * freeing it if the count reaches 0. Assumes |
| * connection lock is already held. |
| * |
| * @param pending the pending call object |
| */ |
| void |
| _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) |
| { |
| dbus_bool_t last_unref; |
| |
| _dbus_assert (pending->refcount.value > 0); |
| |
| pending->refcount.value -= 1; |
| last_unref = pending->refcount.value == 0; |
| |
| CONNECTION_UNLOCK (pending->connection); |
| if (last_unref) |
| _dbus_pending_call_last_unref (pending); |
| } |
| |
| /** |
| * Checks whether the pending call has received a reply |
| * yet, or not. Assumes connection lock is held. |
| * |
| * @param pending the pending call |
| * @returns #TRUE if a reply has been received |
| */ |
| dbus_bool_t |
| _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending) |
| { |
| return pending->completed; |
| } |
| |
| static DBusDataSlotAllocator slot_allocator; |
| _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots); |
| |
| /** |
| * Stores a pointer on a #DBusPendingCall, along |
| * with an optional function to be used for freeing |
| * the data when the data is set again, or when |
| * the pending call is finalized. The slot number |
| * must have been allocated with dbus_pending_call_allocate_data_slot(). |
| * |
| * @param pending the pending_call |
| * @param slot the slot number |
| * @param data the data to store |
| * @param free_data_func finalizer function for the data |
| * @returns #TRUE if there was enough memory to store the data |
| */ |
| dbus_bool_t |
| _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, |
| dbus_int32_t slot, |
| void *data, |
| DBusFreeFunction free_data_func) |
| { |
| DBusFreeFunction old_free_func; |
| void *old_data; |
| dbus_bool_t retval; |
| |
| retval = _dbus_data_slot_list_set (&slot_allocator, |
| &pending->slot_list, |
| slot, data, free_data_func, |
| &old_free_func, &old_data); |
| |
| /* Drop locks to call out to app code */ |
| CONNECTION_UNLOCK (pending->connection); |
| |
| if (retval) |
| { |
| if (old_free_func) |
| (* old_free_func) (old_data); |
| } |
| |
| CONNECTION_LOCK (pending->connection); |
| |
| return retval; |
| } |
| |
| /** @} */ |
| |
| /** |
| * @defgroup DBusPendingCall DBusPendingCall |
| * @ingroup DBus |
| * @brief Pending reply to a method call message |
| * |
| * A DBusPendingCall is an object representing an |
| * expected reply. A #DBusPendingCall can be created |
| * when you send a message that should have a reply. |
| * |
| * @{ |
| */ |
| |
| /** |
| * @typedef DBusPendingCall |
| * |
| * Opaque data type representing a message pending. |
| */ |
| |
| /** |
| * Increments the reference count on a pending call. |
| * |
| * @param pending the pending call object |
| * @returns the pending call object |
| */ |
| DBusPendingCall * |
| dbus_pending_call_ref (DBusPendingCall *pending) |
| { |
| _dbus_return_val_if_fail (pending != NULL, NULL); |
| |
| /* The connection lock is better than the global |
| * lock in the atomic increment fallback |
| */ |
| #ifdef DBUS_HAVE_ATOMIC_INT |
| _dbus_atomic_inc (&pending->refcount); |
| #else |
| CONNECTION_LOCK (pending->connection); |
| _dbus_assert (pending->refcount.value > 0); |
| |
| pending->refcount.value += 1; |
| CONNECTION_UNLOCK (pending->connection); |
| #endif |
| |
| return pending; |
| } |
| |
| /** |
| * Decrements the reference count on a pending call, |
| * freeing it if the count reaches 0. |
| * |
| * @param pending the pending call object |
| */ |
| void |
| dbus_pending_call_unref (DBusPendingCall *pending) |
| { |
| dbus_bool_t last_unref; |
| |
| _dbus_return_if_fail (pending != NULL); |
| |
| /* More efficient to use the connection lock instead of atomic |
| * int fallback if we lack atomic int decrement |
| */ |
| #ifdef DBUS_HAVE_ATOMIC_INT |
| last_unref = (_dbus_atomic_dec (&pending->refcount) == 1); |
| #else |
| CONNECTION_LOCK (pending->connection); |
| _dbus_assert (pending->refcount.value > 0); |
| pending->refcount.value -= 1; |
| last_unref = pending->refcount.value == 0; |
| CONNECTION_UNLOCK (pending->connection); |
| #endif |
| |
| if (last_unref) |
| _dbus_pending_call_last_unref(pending); |
| } |
| |
| /** |
| * Sets a notification function to be called when the reply is |
| * received or the pending call times out. |
| * |
| * @param pending the pending call |
| * @param function notifier function |
| * @param user_data data to pass to notifier function |
| * @param free_user_data function to free the user data |
| * @returns #FALSE if not enough memory |
| */ |
| dbus_bool_t |
| dbus_pending_call_set_notify (DBusPendingCall *pending, |
| DBusPendingCallNotifyFunction function, |
| void *user_data, |
| DBusFreeFunction free_user_data) |
| { |
| _dbus_return_val_if_fail (pending != NULL, FALSE); |
| |
| CONNECTION_LOCK (pending->connection); |
| |
| /* could invoke application code! */ |
| if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot, |
| user_data, free_user_data)) |
| return FALSE; |
| |
| pending->function = function; |
| |
| CONNECTION_UNLOCK (pending->connection); |
| |
| return TRUE; |
| } |
| |
| /** |
| * Cancels the pending call, such that any reply or error received |
| * will just be ignored. Drops the dbus library's internal reference |
| * to the #DBusPendingCall so will free the call if nobody else is |
| * holding a reference. However you usually get a reference from |
| * dbus_connection_send_with_reply() so probably your app owns a ref |
| * also. |
| * |
| * Note that canceling a pending call will <em>not</em> simulate a |
| * timed-out call; if a call times out, then a timeout error reply is |
| * received. If you cancel the call, no reply is received unless the |
| * the reply was already received before you canceled. |
| * |
| * @param pending the pending call |
| */ |
| void |
| dbus_pending_call_cancel (DBusPendingCall *pending) |
| { |
| _dbus_return_if_fail (pending != NULL); |
| |
| _dbus_connection_remove_pending_call (pending->connection, |
| pending); |
| } |
| |
| /** |
| * 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) |
| { |
| dbus_bool_t completed; |
| |
| _dbus_return_val_if_fail (pending != NULL, FALSE); |
| |
| CONNECTION_LOCK (pending->connection); |
| completed = pending->completed; |
| CONNECTION_UNLOCK (pending->connection); |
| |
| return completed; |
| } |
| |
| /** |
| * Gets the reply, or returns #NULL if none has been received |
| * yet. Ownership of the reply message passes to the caller. This |
| * function can only be called once per pending call, since the reply |
| * message is tranferred to the caller. |
| * |
| * @param pending the pending call |
| * @returns the reply message or #NULL. |
| */ |
| DBusMessage* |
| dbus_pending_call_steal_reply (DBusPendingCall *pending) |
| { |
| DBusMessage *message; |
| |
| _dbus_return_val_if_fail (pending != NULL, NULL); |
| _dbus_return_val_if_fail (pending->completed, NULL); |
| _dbus_return_val_if_fail (pending->reply != NULL, NULL); |
| |
| CONNECTION_LOCK (pending->connection); |
| |
| message = pending->reply; |
| pending->reply = NULL; |
| |
| CONNECTION_UNLOCK (pending->connection); |
| |
| return message; |
| } |
| |
| /** |
| * 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. |
| * |
| * If the pending call is already completed, this function returns |
| * immediately. |
| * |
| * @todo when you start blocking, the timeout is reset, but it should |
| * really only use time remaining since the pending call was created. |
| * This requires storing timestamps instead of intervals in the timeout |
| * |
| * @param pending the pending call |
| */ |
| void |
| dbus_pending_call_block (DBusPendingCall *pending) |
| { |
| _dbus_return_if_fail (pending != NULL); |
| |
| _dbus_connection_block_pending_call (pending); |
| } |
| |
| /** |
| * Allocates an integer ID to be used for storing application-specific |
| * data on any DBusPendingCall. The allocated ID may then be used |
| * with dbus_pending_call_set_data() and dbus_pending_call_get_data(). |
| * The passed-in slot must be initialized to -1, and is filled in |
| * with the slot ID. If the passed-in slot is not -1, it's assumed |
| * to be already allocated, and its refcount is incremented. |
| * |
| * The allocated slot is global, i.e. all DBusPendingCall objects will |
| * have a slot with the given integer ID reserved. |
| * |
| * @param slot_p address of a global variable storing the slot |
| * @returns #FALSE on failure (no memory) |
| */ |
| dbus_bool_t |
| dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) |
| { |
| _dbus_return_val_if_fail (slot_p != NULL, FALSE); |
| |
| return _dbus_data_slot_allocator_alloc (&slot_allocator, |
| &_DBUS_LOCK_NAME (pending_call_slots), |
| slot_p); |
| } |
| |
| /** |
| * Deallocates a global ID for #DBusPendingCall data slots. |
| * dbus_pending_call_get_data() and dbus_pending_call_set_data() may |
| * no longer be used with this slot. Existing data stored on existing |
| * DBusPendingCall objects will be freed when the #DBusPendingCall is |
| * finalized, but may not be retrieved (and may only be replaced if |
| * someone else reallocates the slot). When the refcount on the |
| * passed-in slot reaches 0, it is set to -1. |
| * |
| * @param slot_p address storing the slot to deallocate |
| */ |
| void |
| dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) |
| { |
| _dbus_return_if_fail (slot_p != NULL); |
| _dbus_return_if_fail (*slot_p >= 0); |
| |
| _dbus_data_slot_allocator_free (&slot_allocator, slot_p); |
| } |
| |
| /** |
| * Stores a pointer on a #DBusPendingCall, along |
| * with an optional function to be used for freeing |
| * the data when the data is set again, or when |
| * the pending call is finalized. The slot number |
| * must have been allocated with dbus_pending_call_allocate_data_slot(). |
| * |
| * @param pending the pending_call |
| * @param slot the slot number |
| * @param data the data to store |
| * @param free_data_func finalizer function for the data |
| * @returns #TRUE if there was enough memory to store the data |
| */ |
| dbus_bool_t |
| dbus_pending_call_set_data (DBusPendingCall *pending, |
| dbus_int32_t slot, |
| void *data, |
| DBusFreeFunction free_data_func) |
| { |
| dbus_bool_t retval; |
| |
| _dbus_return_val_if_fail (pending != NULL, FALSE); |
| _dbus_return_val_if_fail (slot >= 0, FALSE); |
| |
| |
| CONNECTION_LOCK (pending->connection); |
| retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func); |
| CONNECTION_UNLOCK (pending->connection); |
| return retval; |
| } |
| |
| /** |
| * Retrieves data previously set with dbus_pending_call_set_data(). |
| * The slot must still be allocated (must not have been freed). |
| * |
| * @param pending the pending_call |
| * @param slot the slot to get data from |
| * @returns the data, or #NULL if not found |
| */ |
| void* |
| dbus_pending_call_get_data (DBusPendingCall *pending, |
| dbus_int32_t slot) |
| { |
| void *res; |
| |
| _dbus_return_val_if_fail (pending != NULL, NULL); |
| |
| CONNECTION_LOCK (pending->connection); |
| res = _dbus_data_slot_list_get (&slot_allocator, |
| &pending->slot_list, |
| slot); |
| CONNECTION_UNLOCK (pending->connection); |
| |
| return res; |
| } |
| |
| /** @} */ |
| |
| #ifdef DBUS_BUILD_TESTS |
| |
| /** |
| * @ingroup DBusPendingCallInternals |
| * Unit test for DBusPendingCall. |
| * |
| * @returns #TRUE on success. |
| */ |
| dbus_bool_t |
| _dbus_pending_call_test (const char *test_data_dir) |
| { |
| |
| return TRUE; |
| } |
| #endif /* DBUS_BUILD_TESTS */ |