Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu" -*- */
      2 /* dbus-pending-call.c Object representing a call in progress.
      3  *
      4  * Copyright (C) 2002, 2003 Red Hat Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21  *
     22  */
     23 
     24 #include "dbus-internals.h"
     25 #include "dbus-connection-internal.h"
     26 #include "dbus-pending-call-internal.h"
     27 #include "dbus-pending-call.h"
     28 #include "dbus-list.h"
     29 #include "dbus-threads.h"
     30 #include "dbus-test.h"
     31 
     32 /**
     33  * @defgroup DBusPendingCallInternals DBusPendingCall implementation details
     34  * @ingroup DBusInternals
     35  * @brief DBusPendingCall private implementation details.
     36  *
     37  * The guts of DBusPendingCall and its methods.
     38  *
     39  * @{
     40  */
     41 
     42 /**
     43  * @brief Internals of DBusPendingCall
     44  *
     45  * Opaque object representing a reply message that we're waiting for.
     46  */
     47 
     48 /**
     49  * shorter and more visible way to write _dbus_connection_lock()
     50  */
     51 #define CONNECTION_LOCK(connection)   _dbus_connection_lock(connection)
     52 /**
     53  * shorter and more visible way to write _dbus_connection_unlock()
     54  */
     55 #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection)
     56 
     57 /**
     58  * Implementation details of #DBusPendingCall - all fields are private.
     59  */
     60 struct DBusPendingCall
     61 {
     62   DBusAtomic refcount;                            /**< reference count */
     63 
     64   DBusDataSlotList slot_list;                     /**< Data stored by allocated integer ID */
     65 
     66   DBusPendingCallNotifyFunction function;         /**< Notifier when reply arrives. */
     67 
     68   DBusConnection *connection;                     /**< Connections we're associated with */
     69   DBusMessage *reply;                             /**< Reply (after we've received it) */
     70   DBusTimeout *timeout;                           /**< Timeout */
     71 
     72   DBusList *timeout_link;                         /**< Preallocated timeout response */
     73 
     74   dbus_uint32_t reply_serial;                     /**< Expected serial of reply */
     75 
     76   unsigned int completed : 1;                     /**< TRUE if completed */
     77   unsigned int timeout_added : 1;                 /**< Have added the timeout */
     78 };
     79 
     80 static dbus_int32_t notify_user_data_slot = -1;
     81 
     82 /**
     83  * Creates a new pending reply object.
     84  *
     85  * @param connection connection where reply will arrive
     86  * @param timeout_milliseconds length of timeout, -1 for default
     87  * @param timeout_handler timeout handler, takes pending call as data
     88  * @returns a new #DBusPendingCall or #NULL if no memory.
     89  */
     90 DBusPendingCall*
     91 _dbus_pending_call_new_unlocked (DBusConnection    *connection,
     92                                  int                timeout_milliseconds,
     93                                  DBusTimeoutHandler timeout_handler)
     94 {
     95   DBusPendingCall *pending;
     96   DBusTimeout *timeout;
     97 
     98   _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
     99 
    100   if (timeout_milliseconds == -1)
    101     timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
    102 
    103   /* it would probably seem logical to pass in _DBUS_INT_MAX for
    104    * infinite timeout, but then math in
    105    * _dbus_connection_block_for_reply would get all overflow-prone, so
    106    * smack that down.
    107    */
    108   if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
    109     timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
    110 
    111   if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
    112     return NULL;
    113 
    114   pending = dbus_new0 (DBusPendingCall, 1);
    115 
    116   if (pending == NULL)
    117     {
    118       dbus_pending_call_free_data_slot (&notify_user_data_slot);
    119       return NULL;
    120     }
    121 
    122   timeout = _dbus_timeout_new (timeout_milliseconds,
    123                                timeout_handler,
    124 			       pending, NULL);
    125 
    126   if (timeout == NULL)
    127     {
    128       dbus_pending_call_free_data_slot (&notify_user_data_slot);
    129       dbus_free (pending);
    130       return NULL;
    131     }
    132 
    133   pending->refcount.value = 1;
    134   pending->connection = connection;
    135   _dbus_connection_ref_unlocked (pending->connection);
    136 
    137   pending->timeout = timeout;
    138 
    139 
    140   _dbus_data_slot_list_init (&pending->slot_list);
    141 
    142   return pending;
    143 }
    144 
    145 /**
    146  * Sets the reply of a pending call with the given message,
    147  * or if the message is #NULL, by timing out the pending call.
    148  *
    149  * @param pending the pending call
    150  * @param message the message to complete the call with, or #NULL
    151  *  to time out the call
    152  */
    153 void
    154 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
    155                                        DBusMessage     *message)
    156 {
    157   if (message == NULL)
    158     {
    159       message = pending->timeout_link->data;
    160       _dbus_list_clear (&pending->timeout_link);
    161     }
    162   else
    163     dbus_message_ref (message);
    164 
    165   _dbus_verbose ("  handing message %p (%s) to pending call serial %u\n",
    166                  message,
    167                  dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
    168                  "method return" :
    169                  dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
    170                  "error" : "other type",
    171                  pending->reply_serial);
    172 
    173   _dbus_assert (pending->reply == NULL);
    174   _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
    175   pending->reply = message;
    176 }
    177 
    178 /**
    179  * Calls notifier function for the pending call
    180  * and sets the call to completed.
    181  *
    182  * @param pending the pending call
    183  *
    184  */
    185 void
    186 _dbus_pending_call_complete (DBusPendingCall *pending)
    187 {
    188   _dbus_assert (!pending->completed);
    189 
    190   pending->completed = TRUE;
    191 
    192   if (pending->function)
    193     {
    194       void *user_data;
    195       user_data = dbus_pending_call_get_data (pending,
    196                                               notify_user_data_slot);
    197 
    198       (* pending->function) (pending, user_data);
    199     }
    200 }
    201 
    202 /**
    203  * If the pending call hasn't been timed out, add its timeout
    204  * error reply to the connection's incoming message queue.
    205  *
    206  * @param pending the pending call
    207  * @param connection the connection the call was sent to
    208  */
    209 void
    210 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
    211                                                  DBusConnection  *connection)
    212 {
    213   _dbus_assert (connection == pending->connection);
    214 
    215   if (pending->timeout_link)
    216     {
    217       _dbus_connection_queue_synthesized_message_link (connection,
    218 						       pending->timeout_link);
    219       pending->timeout_link = NULL;
    220     }
    221 }
    222 
    223 /**
    224  * Checks to see if a timeout has been added
    225  *
    226  * @param pending the pending_call
    227  * @returns #TRUE if there is a timeout or #FALSE if not
    228  */
    229 dbus_bool_t
    230 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall  *pending)
    231 {
    232   _dbus_assert (pending != NULL);
    233 
    234   return pending->timeout_added;
    235 }
    236 
    237 
    238 /**
    239  * Sets wether the timeout has been added
    240  *
    241  * @param pending the pending_call
    242  * @param is_added whether or not a timeout is added
    243  */
    244 void
    245 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall  *pending,
    246                                                dbus_bool_t       is_added)
    247 {
    248   _dbus_assert (pending != NULL);
    249 
    250   pending->timeout_added = is_added;
    251 }
    252 
    253 
    254 /**
    255  * Retrives the timeout
    256  *
    257  * @param pending the pending_call
    258  * @returns a timeout object
    259  */
    260 DBusTimeout *
    261 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall  *pending)
    262 {
    263   _dbus_assert (pending != NULL);
    264 
    265   return pending->timeout;
    266 }
    267 
    268 /**
    269  * Gets the reply's serial number
    270  *
    271  * @param pending the pending_call
    272  * @returns a serial number for the reply or 0
    273  */
    274 dbus_uint32_t
    275 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall  *pending)
    276 {
    277   _dbus_assert (pending != NULL);
    278 
    279   return pending->reply_serial;
    280 }
    281 
    282 /**
    283  * Sets the reply's serial number
    284  *
    285  * @param pending the pending_call
    286  * @param serial the serial number
    287  */
    288 void
    289 _dbus_pending_call_set_reply_serial_unlocked  (DBusPendingCall *pending,
    290                                                dbus_uint32_t serial)
    291 {
    292   _dbus_assert (pending != NULL);
    293   _dbus_assert (pending->reply_serial == 0);
    294 
    295   pending->reply_serial = serial;
    296 }
    297 
    298 /**
    299  * Gets the connection associated with this pending call.
    300  *
    301  * @param pending the pending_call
    302  * @returns the connection associated with the pending call
    303  */
    304 DBusConnection *
    305 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
    306 {
    307   _dbus_assert (pending != NULL);
    308 
    309   CONNECTION_LOCK (pending->connection);
    310   return pending->connection;
    311 }
    312 
    313 /**
    314  * Gets the connection associated with this pending call.
    315  *
    316  * @param pending the pending_call
    317  * @returns the connection associated with the pending call
    318  */
    319 DBusConnection *
    320 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
    321 {
    322   _dbus_assert (pending != NULL);
    323 
    324   return pending->connection;
    325 }
    326 
    327 /**
    328  * Sets the reply message associated with the pending call to a timeout error
    329  *
    330  * @param pending the pending_call
    331  * @param message the message we are sending the error reply to
    332  * @param serial serial number for the reply
    333  * @return #FALSE on OOM
    334  */
    335 dbus_bool_t
    336 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
    337                                                DBusMessage     *message,
    338                                                dbus_uint32_t    serial)
    339 {
    340   DBusList *reply_link;
    341   DBusMessage *reply;
    342 
    343   reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
    344                                   "Did not receive a reply. Possible causes include: "
    345                                   "the remote application did not send a reply, "
    346                                   "the message bus security policy blocked the reply, "
    347                                   "the reply timeout expired, or "
    348                                   "the network connection was broken.");
    349   if (reply == NULL)
    350     return FALSE;
    351 
    352   reply_link = _dbus_list_alloc_link (reply);
    353   if (reply_link == NULL)
    354     {
    355       dbus_message_unref (reply);
    356       return FALSE;
    357     }
    358 
    359   pending->timeout_link = reply_link;
    360 
    361   _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
    362 
    363   return TRUE;
    364 }
    365 
    366 /**
    367  * Increments the reference count on a pending call,
    368  * while the lock on its connection is already held.
    369  *
    370  * @param pending the pending call object
    371  * @returns the pending call object
    372  */
    373 DBusPendingCall *
    374 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
    375 {
    376   pending->refcount.value += 1;
    377 
    378   return pending;
    379 }
    380 
    381 
    382 static void
    383 _dbus_pending_call_last_unref (DBusPendingCall *pending)
    384 {
    385   DBusConnection *connection;
    386 
    387   /* If we get here, we should be already detached
    388    * from the connection, or never attached.
    389    */
    390   _dbus_assert (!pending->timeout_added);
    391 
    392   connection = pending->connection;
    393 
    394   /* this assumes we aren't holding connection lock... */
    395   _dbus_data_slot_list_free (&pending->slot_list);
    396 
    397   if (pending->timeout != NULL)
    398     _dbus_timeout_unref (pending->timeout);
    399 
    400   if (pending->timeout_link)
    401     {
    402       dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
    403       _dbus_list_free_link (pending->timeout_link);
    404       pending->timeout_link = NULL;
    405     }
    406 
    407   if (pending->reply)
    408     {
    409       dbus_message_unref (pending->reply);
    410       pending->reply = NULL;
    411     }
    412 
    413   dbus_free (pending);
    414 
    415   dbus_pending_call_free_data_slot (&notify_user_data_slot);
    416 
    417   /* connection lock should not be held. */
    418   /* Free the connection last to avoid a weird state while
    419    * calling out to application code where the pending exists
    420    * but not the connection.
    421    */
    422   dbus_connection_unref (connection);
    423 }
    424 
    425 /**
    426  * Decrements the reference count on a pending call,
    427  * freeing it if the count reaches 0. Assumes
    428  * connection lock is already held.
    429  *
    430  * @param pending the pending call object
    431  */
    432 void
    433 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
    434 {
    435   dbus_bool_t last_unref;
    436 
    437   _dbus_assert (pending->refcount.value > 0);
    438 
    439   pending->refcount.value -= 1;
    440   last_unref = pending->refcount.value == 0;
    441 
    442   CONNECTION_UNLOCK (pending->connection);
    443   if (last_unref)
    444     _dbus_pending_call_last_unref (pending);
    445 }
    446 
    447 /**
    448  * Checks whether the pending call has received a reply
    449  * yet, or not. Assumes connection lock is held.
    450  *
    451  * @param pending the pending call
    452  * @returns #TRUE if a reply has been received
    453  */
    454 dbus_bool_t
    455 _dbus_pending_call_get_completed_unlocked (DBusPendingCall    *pending)
    456 {
    457   return pending->completed;
    458 }
    459 
    460 static DBusDataSlotAllocator slot_allocator;
    461 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
    462 
    463 /**
    464  * Stores a pointer on a #DBusPendingCall, along
    465  * with an optional function to be used for freeing
    466  * the data when the data is set again, or when
    467  * the pending call is finalized. The slot number
    468  * must have been allocated with dbus_pending_call_allocate_data_slot().
    469  *
    470  * @param pending the pending_call
    471  * @param slot the slot number
    472  * @param data the data to store
    473  * @param free_data_func finalizer function for the data
    474  * @returns #TRUE if there was enough memory to store the data
    475  */
    476 dbus_bool_t
    477 _dbus_pending_call_set_data_unlocked (DBusPendingCall  *pending,
    478                                      dbus_int32_t      slot,
    479                                      void             *data,
    480                                      DBusFreeFunction  free_data_func)
    481 {
    482   DBusFreeFunction old_free_func;
    483   void *old_data;
    484   dbus_bool_t retval;
    485 
    486   retval = _dbus_data_slot_list_set (&slot_allocator,
    487                                      &pending->slot_list,
    488                                      slot, data, free_data_func,
    489                                      &old_free_func, &old_data);
    490 
    491   /* Drop locks to call out to app code */
    492   CONNECTION_UNLOCK (pending->connection);
    493 
    494   if (retval)
    495     {
    496       if (old_free_func)
    497         (* old_free_func) (old_data);
    498     }
    499 
    500   CONNECTION_LOCK (pending->connection);
    501 
    502   return retval;
    503 }
    504 
    505 /** @} */
    506 
    507 /**
    508  * @defgroup DBusPendingCall DBusPendingCall
    509  * @ingroup  DBus
    510  * @brief Pending reply to a method call message
    511  *
    512  * A DBusPendingCall is an object representing an
    513  * expected reply. A #DBusPendingCall can be created
    514  * when you send a message that should have a reply.
    515  *
    516  * @{
    517  */
    518 
    519 /**
    520  * @typedef DBusPendingCall
    521  *
    522  * Opaque data type representing a message pending.
    523  */
    524 
    525 /**
    526  * Increments the reference count on a pending call.
    527  *
    528  * @param pending the pending call object
    529  * @returns the pending call object
    530  */
    531 DBusPendingCall *
    532 dbus_pending_call_ref (DBusPendingCall *pending)
    533 {
    534   _dbus_return_val_if_fail (pending != NULL, NULL);
    535 
    536   /* The connection lock is better than the global
    537    * lock in the atomic increment fallback
    538    */
    539 #ifdef DBUS_HAVE_ATOMIC_INT
    540   _dbus_atomic_inc (&pending->refcount);
    541 #else
    542   CONNECTION_LOCK (pending->connection);
    543   _dbus_assert (pending->refcount.value > 0);
    544 
    545   pending->refcount.value += 1;
    546   CONNECTION_UNLOCK (pending->connection);
    547 #endif
    548 
    549   return pending;
    550 }
    551 
    552 /**
    553  * Decrements the reference count on a pending call,
    554  * freeing it if the count reaches 0.
    555  *
    556  * @param pending the pending call object
    557  */
    558 void
    559 dbus_pending_call_unref (DBusPendingCall *pending)
    560 {
    561   dbus_bool_t last_unref;
    562 
    563   _dbus_return_if_fail (pending != NULL);
    564 
    565   /* More efficient to use the connection lock instead of atomic
    566    * int fallback if we lack atomic int decrement
    567    */
    568 #ifdef DBUS_HAVE_ATOMIC_INT
    569   last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
    570 #else
    571   CONNECTION_LOCK (pending->connection);
    572   _dbus_assert (pending->refcount.value > 0);
    573   pending->refcount.value -= 1;
    574   last_unref = pending->refcount.value == 0;
    575   CONNECTION_UNLOCK (pending->connection);
    576 #endif
    577 
    578   if (last_unref)
    579     _dbus_pending_call_last_unref(pending);
    580 }
    581 
    582 /**
    583  * Sets a notification function to be called when the reply is
    584  * received or the pending call times out.
    585  *
    586  * @param pending the pending call
    587  * @param function notifier function
    588  * @param user_data data to pass to notifier function
    589  * @param free_user_data function to free the user data
    590  * @returns #FALSE if not enough memory
    591  */
    592 dbus_bool_t
    593 dbus_pending_call_set_notify (DBusPendingCall              *pending,
    594                               DBusPendingCallNotifyFunction function,
    595                               void                         *user_data,
    596                               DBusFreeFunction              free_user_data)
    597 {
    598   _dbus_return_val_if_fail (pending != NULL, FALSE);
    599 
    600   CONNECTION_LOCK (pending->connection);
    601 
    602   /* could invoke application code! */
    603   if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
    604                                              user_data, free_user_data))
    605     return FALSE;
    606 
    607   pending->function = function;
    608 
    609   CONNECTION_UNLOCK (pending->connection);
    610 
    611   return TRUE;
    612 }
    613 
    614 /**
    615  * Cancels the pending call, such that any reply or error received
    616  * will just be ignored.  Drops the dbus library's internal reference
    617  * to the #DBusPendingCall so will free the call if nobody else is
    618  * holding a reference. However you usually get a reference from
    619  * dbus_connection_send_with_reply() so probably your app owns a ref
    620  * also.
    621  *
    622  * Note that canceling a pending call will <em>not</em> simulate a
    623  * timed-out call; if a call times out, then a timeout error reply is
    624  * received. If you cancel the call, no reply is received unless the
    625  * the reply was already received before you canceled.
    626  *
    627  * @param pending the pending call
    628  */
    629 void
    630 dbus_pending_call_cancel (DBusPendingCall *pending)
    631 {
    632   _dbus_return_if_fail (pending != NULL);
    633 
    634   _dbus_connection_remove_pending_call (pending->connection,
    635                                         pending);
    636 }
    637 
    638 /**
    639  * Checks whether the pending call has received a reply
    640  * yet, or not.
    641  *
    642  * @param pending the pending call
    643  * @returns #TRUE if a reply has been received
    644  */
    645 dbus_bool_t
    646 dbus_pending_call_get_completed (DBusPendingCall *pending)
    647 {
    648   dbus_bool_t completed;
    649 
    650   _dbus_return_val_if_fail (pending != NULL, FALSE);
    651 
    652   CONNECTION_LOCK (pending->connection);
    653   completed = pending->completed;
    654   CONNECTION_UNLOCK (pending->connection);
    655 
    656   return completed;
    657 }
    658 
    659 /**
    660  * Gets the reply, or returns #NULL if none has been received
    661  * yet. Ownership of the reply message passes to the caller. This
    662  * function can only be called once per pending call, since the reply
    663  * message is tranferred to the caller.
    664  *
    665  * @param pending the pending call
    666  * @returns the reply message or #NULL.
    667  */
    668 DBusMessage*
    669 dbus_pending_call_steal_reply (DBusPendingCall *pending)
    670 {
    671   DBusMessage *message;
    672 
    673   _dbus_return_val_if_fail (pending != NULL, NULL);
    674   _dbus_return_val_if_fail (pending->completed, NULL);
    675   _dbus_return_val_if_fail (pending->reply != NULL, NULL);
    676 
    677   CONNECTION_LOCK (pending->connection);
    678 
    679   message = pending->reply;
    680   pending->reply = NULL;
    681 
    682   CONNECTION_UNLOCK (pending->connection);
    683 
    684   return message;
    685 }
    686 
    687 /**
    688  * Block until the pending call is completed.  The blocking is as with
    689  * dbus_connection_send_with_reply_and_block(); it does not enter the
    690  * main loop or process other messages, it simply waits for the reply
    691  * in question.
    692  *
    693  * If the pending call is already completed, this function returns
    694  * immediately.
    695  *
    696  * @todo when you start blocking, the timeout is reset, but it should
    697  * really only use time remaining since the pending call was created.
    698  * This requires storing timestamps instead of intervals in the timeout
    699  *
    700  * @param pending the pending call
    701  */
    702 void
    703 dbus_pending_call_block (DBusPendingCall *pending)
    704 {
    705   _dbus_return_if_fail (pending != NULL);
    706 
    707   _dbus_connection_block_pending_call (pending);
    708 }
    709 
    710 /**
    711  * Allocates an integer ID to be used for storing application-specific
    712  * data on any DBusPendingCall. The allocated ID may then be used
    713  * with dbus_pending_call_set_data() and dbus_pending_call_get_data().
    714  * The passed-in slot must be initialized to -1, and is filled in
    715  * with the slot ID. If the passed-in slot is not -1, it's assumed
    716  * to be already allocated, and its refcount is incremented.
    717  *
    718  * The allocated slot is global, i.e. all DBusPendingCall objects will
    719  * have a slot with the given integer ID reserved.
    720  *
    721  * @param slot_p address of a global variable storing the slot
    722  * @returns #FALSE on failure (no memory)
    723  */
    724 dbus_bool_t
    725 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
    726 {
    727   _dbus_return_val_if_fail (slot_p != NULL, FALSE);
    728 
    729   return _dbus_data_slot_allocator_alloc (&slot_allocator,
    730                                           &_DBUS_LOCK_NAME (pending_call_slots),
    731                                           slot_p);
    732 }
    733 
    734 /**
    735  * Deallocates a global ID for #DBusPendingCall data slots.
    736  * dbus_pending_call_get_data() and dbus_pending_call_set_data() may
    737  * no longer be used with this slot.  Existing data stored on existing
    738  * DBusPendingCall objects will be freed when the #DBusPendingCall is
    739  * finalized, but may not be retrieved (and may only be replaced if
    740  * someone else reallocates the slot).  When the refcount on the
    741  * passed-in slot reaches 0, it is set to -1.
    742  *
    743  * @param slot_p address storing the slot to deallocate
    744  */
    745 void
    746 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
    747 {
    748   _dbus_return_if_fail (slot_p != NULL);
    749   _dbus_return_if_fail (*slot_p >= 0);
    750 
    751   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
    752 }
    753 
    754 /**
    755  * Stores a pointer on a #DBusPendingCall, along
    756  * with an optional function to be used for freeing
    757  * the data when the data is set again, or when
    758  * the pending call is finalized. The slot number
    759  * must have been allocated with dbus_pending_call_allocate_data_slot().
    760  *
    761  * @param pending the pending_call
    762  * @param slot the slot number
    763  * @param data the data to store
    764  * @param free_data_func finalizer function for the data
    765  * @returns #TRUE if there was enough memory to store the data
    766  */
    767 dbus_bool_t
    768 dbus_pending_call_set_data (DBusPendingCall  *pending,
    769                             dbus_int32_t      slot,
    770                             void             *data,
    771                             DBusFreeFunction  free_data_func)
    772 {
    773   dbus_bool_t retval;
    774 
    775   _dbus_return_val_if_fail (pending != NULL, FALSE);
    776   _dbus_return_val_if_fail (slot >= 0, FALSE);
    777 
    778 
    779   CONNECTION_LOCK (pending->connection);
    780   retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
    781   CONNECTION_UNLOCK (pending->connection);
    782   return retval;
    783 }
    784 
    785 /**
    786  * Retrieves data previously set with dbus_pending_call_set_data().
    787  * The slot must still be allocated (must not have been freed).
    788  *
    789  * @param pending the pending_call
    790  * @param slot the slot to get data from
    791  * @returns the data, or #NULL if not found
    792  */
    793 void*
    794 dbus_pending_call_get_data (DBusPendingCall   *pending,
    795                             dbus_int32_t       slot)
    796 {
    797   void *res;
    798 
    799   _dbus_return_val_if_fail (pending != NULL, NULL);
    800 
    801   CONNECTION_LOCK (pending->connection);
    802   res = _dbus_data_slot_list_get (&slot_allocator,
    803                                   &pending->slot_list,
    804                                   slot);
    805   CONNECTION_UNLOCK (pending->connection);
    806 
    807   return res;
    808 }
    809 
    810 /** @} */
    811 
    812 #ifdef DBUS_BUILD_TESTS
    813 
    814 /**
    815  * @ingroup DBusPendingCallInternals
    816  * Unit test for DBusPendingCall.
    817  *
    818  * @returns #TRUE on success.
    819  */
    820 dbus_bool_t
    821 _dbus_pending_call_test (const char *test_data_dir)
    822 {
    823 
    824   return TRUE;
    825 }
    826 #endif /* DBUS_BUILD_TESTS */
    827