[daemon-fix] fixed querying about name information
[platform/upstream/dbus.git] / dbus / dbus-pending-call.c
index 6076d72..be53410 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- 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.
  *
  * 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
+ * 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-message-internal.h"
 #include "dbus-pending-call-internal.h"
 #include "dbus-pending-call.h"
 #include "dbus-list.h"
  *
  * 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 */
@@ -67,13 +79,29 @@ struct DBusPendingCall
   unsigned int timeout_added : 1;                 /**< Have added the timeout */
 };
 
+static void
+_dbus_pending_call_trace_ref (DBusPendingCall *pending_call,
+    int old_refcount,
+    int new_refcount,
+    const char *why)
+{
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+  static int enabled = -1;
+
+  _dbus_trace_ref ("DBusPendingCall", pending_call, old_refcount,
+      new_refcount, why, "DBUS_PENDING_CALL_TRACE", &enabled);
+#endif
+}
+
 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
+ * @param timeout_milliseconds length of timeout, -1 (or
+ *  #DBUS_TIMEOUT_USE_DEFAULT) for default,
+ *  #DBUS_TIMEOUT_INFINITE for no timeout
  * @param timeout_handler timeout handler, takes pending call as data
  * @returns a new #DBusPendingCall or #NULL if no memory.
  */
@@ -90,14 +118,6 @@ _dbus_pending_call_new_unlocked (DBusConnection    *connection,
   if (timeout_milliseconds == -1)
     timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
 
-  /* it would probably seem logical to pass in _DBUS_INT_MAX for
-   * infinite timeout, but then math in
-   * _dbus_connection_block_for_reply would get all overflow-prone, so
-   * smack that down.
-   */
-  if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
-    timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
-  
   if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
     return NULL;
   
@@ -109,26 +129,34 @@ _dbus_pending_call_new_unlocked (DBusConnection    *connection,
       return NULL;
     }
 
-  timeout = _dbus_timeout_new (timeout_milliseconds,
-                               timeout_handler,
-                              pending, NULL);  
-
-  if (timeout == NULL)
+  if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
     {
-      dbus_pending_call_free_data_slot (&notify_user_data_slot);
-      dbus_free (pending);
-      return NULL;
+      timeout = _dbus_timeout_new (timeout_milliseconds,
+                                   timeout_handler,
+                                   pending, NULL);  
+
+      if (timeout == NULL)
+        {
+          dbus_pending_call_free_data_slot (&notify_user_data_slot);
+          dbus_free (pending);
+          return NULL;
+        }
+
+      pending->timeout = timeout;
     }
-  
-  pending->refcount.value = 1;
+  else
+    {
+      pending->timeout = NULL;
+    }
+
+  _dbus_atomic_inc (&pending->refcount);
   pending->connection = connection;
   _dbus_connection_ref_unlocked (pending->connection);
 
-  pending->timeout = timeout;
+  _dbus_data_slot_list_init (&pending->slot_list);
 
+  _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked");
 
-  _dbus_data_slot_list_init (&pending->slot_list);
-  
   return pending;
 }
 
@@ -189,6 +217,13 @@ _dbus_pending_call_complete (DBusPendingCall *pending)
     }
 }
 
+/**
+ * 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)
@@ -238,7 +273,7 @@ _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall  *pending,
  * Retrives the timeout
  *
  * @param pending the pending_call
- * @returns a timeout object 
+ * @returns a timeout object or NULL if call has no timeout
  */
 DBusTimeout *
 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall  *pending)
@@ -335,6 +370,8 @@ _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
   reply_link = _dbus_list_alloc_link (reply);
   if (reply_link == NULL)
     {
+      /* it's OK to unref this, nothing that could have attached a callback
+       * has ever seen it */
       dbus_message_unref (reply);
       return FALSE;
     }
@@ -346,26 +383,6 @@ _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
   return TRUE;
 }
 
-/** @} */
-
-/**
- * @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,
  * while the lock on its connection is already held.
@@ -376,38 +393,16 @@ _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
 DBusPendingCall *
 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
 {
-  pending->refcount.value += 1;
-  
-  return 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);
+  dbus_int32_t old_refcount;
 
-  /* 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);
+  old_refcount = _dbus_atomic_inc (&pending->refcount);
+  _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
+      "ref_unlocked");
 
-  pending->refcount.value += 1;
-  CONNECTION_UNLOCK (pending->connection);
-#endif
-  
   return pending;
 }
 
+
 static void
 _dbus_pending_call_last_unref (DBusPendingCall *pending)
 {
@@ -461,19 +456,138 @@ _dbus_pending_call_last_unref (DBusPendingCall *pending)
 void
 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
 {
-  dbus_bool_t last_unref;
-  
-  _dbus_assert (pending->refcount.value > 0);
+  dbus_int32_t old_refcount;
 
-  pending->refcount.value -= 1;
-  last_unref = pending->refcount.value == 0;
+  old_refcount = _dbus_atomic_dec (&pending->refcount);
+  _dbus_assert (old_refcount > 0);
+  _dbus_pending_call_trace_ref (pending, old_refcount,
+      old_refcount - 1, "unref_and_unlock");
 
   CONNECTION_UNLOCK (pending->connection);
-  if (last_unref)
+
+  if (old_refcount == 1)
     _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_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (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.
+ *
+ * @{
+ */
+
+/**
+ * @def DBUS_TIMEOUT_INFINITE
+ *
+ * An integer constant representing an infinite timeout. This has the
+ * numeric value 0x7fffffff (the largest 32-bit signed integer).
+ *
+ * For source compatibility with D-Bus versions earlier than 1.4.12, use
+ * 0x7fffffff, or INT32_MAX (assuming your platform has it).
+ */
+
+/**
+ * @def DBUS_TIMEOUT_USE_DEFAULT
+ *
+ * An integer constant representing a request to use the default timeout.
+ * This has numeric value -1.
+ *
+ * For source compatibility with D-Bus versions earlier than 1.4.12, use a
+ * literal -1.
+ */
+
+/**
+ * @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_int32_t old_refcount;
+
+  _dbus_return_val_if_fail (pending != NULL, NULL);
+
+  old_refcount = _dbus_atomic_inc (&pending->refcount);
+  _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
+      "ref");
+
+  return pending;
+}
+
+/**
  * Decrements the reference count on a pending call,
  * freeing it if the count reaches 0.
  *
@@ -482,24 +596,15 @@ _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
 void
 dbus_pending_call_unref (DBusPendingCall *pending)
 {
-  dbus_bool_t last_unref;
+  dbus_int32_t old_refcount;
 
   _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)
+  old_refcount = _dbus_atomic_dec (&pending->refcount);
+  _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1,
+      "unref");
+
+  if (old_refcount == 1)
     _dbus_pending_call_last_unref(pending);
 }
 
@@ -519,6 +624,8 @@ dbus_pending_call_set_notify (DBusPendingCall              *pending,
                               void                         *user_data,
                               DBusFreeFunction              free_user_data)
 {
+  dbus_bool_t ret = FALSE;
+
   _dbus_return_val_if_fail (pending != NULL, FALSE);
 
   CONNECTION_LOCK (pending->connection);
@@ -526,46 +633,43 @@ dbus_pending_call_set_notify (DBusPendingCall              *pending,
   /* could invoke application code! */
   if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
                                              user_data, free_user_data))
-    return FALSE;
+    goto out;
   
   pending->function = function;
+  ret = TRUE;
 
+out:
   CONNECTION_UNLOCK (pending->connection);
   
-  return TRUE;
+  return ret;
 }
 
 /**
  * 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() so probably your app owns a ref also.
+ * 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. 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;
-}
-
-/**
- * Checks whether the pending call has received a reply
  * yet, or not.
  *
  * @param pending the pending call
@@ -576,6 +680,8 @@ 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);
@@ -597,6 +703,7 @@ 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);
 
@@ -606,7 +713,8 @@ dbus_pending_call_steal_reply (DBusPendingCall *pending)
   pending->reply = NULL;
 
   CONNECTION_UNLOCK (pending->connection);
-  
+
+  _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply");
   return message;
 }
 
@@ -621,18 +729,18 @@ dbus_pending_call_steal_reply (DBusPendingCall *pending)
  *
  * @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);
 }
 
-static DBusDataSlotAllocator slot_allocator;
-_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
-
 /**
  * Allocates an integer ID to be used for storing application-specific
  * data on any DBusPendingCall. The allocated ID may then be used
@@ -650,8 +758,9 @@ _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
 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);
 }
 
@@ -669,6 +778,7 @@ dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
 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);
@@ -688,48 +798,6 @@ dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
  * @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;
-}
-
-/**
- * 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,
@@ -773,19 +841,3 @@ dbus_pending_call_get_data (DBusPendingCall   *pending,
 }
 
 /** @} */
-
-#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 */