Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

dbus-pending-call.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-pending-call.c Object representing a call in progress.
00003  *
00004  * Copyright (C) 2002, 2003 Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include "dbus-internals.h"
00025 #include "dbus-connection-internal.h"
00026 #include "dbus-pending-call.h"
00027 #include "dbus-list.h"
00028 #include "dbus-threads.h"
00029 #include "dbus-test.h"
00030 
00041 static dbus_int32_t notify_user_data_slot = -1;
00042 
00051 DBusPendingCall*
00052 _dbus_pending_call_new (DBusConnection    *connection,
00053                         int                timeout_milliseconds,
00054                         DBusTimeoutHandler timeout_handler)
00055 {
00056   DBusPendingCall *pending;
00057   DBusTimeout *timeout;
00058 
00059   _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
00060   
00061   if (timeout_milliseconds == -1)
00062     timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
00063 
00064   /* it would probably seem logical to pass in _DBUS_INT_MAX for
00065    * infinite timeout, but then math in
00066    * _dbus_connection_block_for_reply would get all overflow-prone, so
00067    * smack that down.
00068    */
00069   if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
00070     timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
00071   
00072   if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
00073     return NULL;
00074   
00075   pending = dbus_new0 (DBusPendingCall, 1);
00076   
00077   if (pending == NULL)
00078     {
00079       dbus_pending_call_free_data_slot (&notify_user_data_slot);
00080       return NULL;
00081     }
00082 
00083   timeout = _dbus_timeout_new (timeout_milliseconds,
00084                                timeout_handler,
00085                                pending, NULL);  
00086 
00087   if (timeout == NULL)
00088     {
00089       dbus_pending_call_free_data_slot (&notify_user_data_slot);
00090       dbus_free (pending);
00091       return NULL;
00092     }
00093   
00094   pending->refcount.value = 1;
00095   pending->connection = connection;
00096   pending->timeout = timeout;
00097 
00098   _dbus_data_slot_list_init (&pending->slot_list);
00099   
00100   return pending;
00101 }
00102 
00110 void
00111 _dbus_pending_call_notify (DBusPendingCall *pending)
00112 {
00113   _dbus_assert (!pending->completed);
00114   
00115   pending->completed = TRUE;
00116 
00117   if (pending->function)
00118     {
00119       void *user_data;
00120       user_data = dbus_pending_call_get_data (pending,
00121                                               notify_user_data_slot);
00122       
00123       (* pending->function) (pending, user_data);
00124     }
00125 }
00126 
00153 DBusPendingCall *
00154 dbus_pending_call_ref (DBusPendingCall *pending)
00155 {
00156   _dbus_return_val_if_fail (pending != NULL, NULL);
00157 
00158   _dbus_atomic_inc (&pending->refcount);
00159 
00160   return pending;
00161 }
00162 
00169 void
00170 dbus_pending_call_unref (DBusPendingCall *pending)
00171 {
00172   dbus_bool_t last_unref;
00173 
00174   _dbus_return_if_fail (pending != NULL);
00175 
00176   last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
00177 
00178   if (last_unref)
00179     {
00180       /* If we get here, we should be already detached
00181        * from the connection, or never attached.
00182        */
00183       _dbus_assert (pending->connection == NULL);
00184       _dbus_assert (!pending->timeout_added);  
00185 
00186       /* this assumes we aren't holding connection lock... */
00187       _dbus_data_slot_list_free (&pending->slot_list);
00188       
00189       if (pending->timeout != NULL)
00190         _dbus_timeout_unref (pending->timeout);
00191       
00192       if (pending->timeout_link)
00193         {
00194           dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
00195           _dbus_list_free_link (pending->timeout_link);
00196           pending->timeout_link = NULL;
00197         }
00198 
00199       if (pending->reply)
00200         {
00201           dbus_message_unref (pending->reply);
00202           pending->reply = NULL;
00203         }
00204       
00205       dbus_free (pending);
00206 
00207       dbus_pending_call_free_data_slot (&notify_user_data_slot);
00208     }
00209 }
00210 
00221 dbus_bool_t
00222 dbus_pending_call_set_notify (DBusPendingCall              *pending,
00223                               DBusPendingCallNotifyFunction function,
00224                               void                         *user_data,
00225                               DBusFreeFunction              free_user_data)
00226 {
00227   _dbus_return_val_if_fail (pending != NULL, FALSE);
00228 
00229   /* could invoke application code! */
00230   if (!dbus_pending_call_set_data (pending, notify_user_data_slot,
00231                                    user_data, free_user_data))
00232     return FALSE;
00233   
00234   pending->function = function;
00235 
00236   return TRUE;
00237 }
00238 
00248 void
00249 dbus_pending_call_cancel (DBusPendingCall *pending)
00250 {
00251   if (pending->connection)
00252     _dbus_connection_remove_pending_call (pending->connection,
00253                                           pending);
00254 }
00255 
00264 dbus_bool_t
00265 dbus_pending_call_get_completed (DBusPendingCall *pending)
00266 {
00267   return pending->completed;
00268 }
00269 
00279 DBusMessage*
00280 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00281 {
00282   DBusMessage *message;
00283   
00284   _dbus_return_val_if_fail (pending->completed, NULL);
00285   _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00286   
00287   message = pending->reply;
00288   pending->reply = NULL;
00289 
00290   return message;
00291 }
00292 
00305 DBusMessage*
00306 dbus_pending_call_get_reply (DBusPendingCall *pending)
00307 {
00308   return pending->reply;
00309 }
00310 
00325 void
00326 dbus_pending_call_block (DBusPendingCall *pending)
00327 {
00328   _dbus_connection_block_pending_call (pending);
00329 }
00330 
00331 static DBusDataSlotAllocator slot_allocator;
00332 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
00333 
00348 dbus_bool_t
00349 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00350 {
00351   return _dbus_data_slot_allocator_alloc (&slot_allocator,
00352                                           _DBUS_LOCK_NAME (pending_call_slots),
00353                                           slot_p);
00354 }
00355 
00367 void
00368 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00369 {
00370   _dbus_return_if_fail (*slot_p >= 0);
00371   
00372   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00373 }
00374 
00388 dbus_bool_t
00389 dbus_pending_call_set_data (DBusPendingCall  *pending,
00390                             dbus_int32_t      slot,
00391                             void             *data,
00392                             DBusFreeFunction  free_data_func)
00393 {
00394   DBusFreeFunction old_free_func;
00395   void *old_data;
00396   dbus_bool_t retval;
00397 
00398   _dbus_return_val_if_fail (pending != NULL, FALSE);
00399   _dbus_return_val_if_fail (slot >= 0, FALSE);
00400 
00401   retval = _dbus_data_slot_list_set (&slot_allocator,
00402                                      &pending->slot_list,
00403                                      slot, data, free_data_func,
00404                                      &old_free_func, &old_data);
00405 
00406   if (retval)
00407     {
00408       if (old_free_func)
00409         (* old_free_func) (old_data);
00410     }
00411 
00412   return retval;
00413 }
00414 
00423 void*
00424 dbus_pending_call_get_data (DBusPendingCall   *pending,
00425                             dbus_int32_t       slot)
00426 {
00427   void *res;
00428 
00429   _dbus_return_val_if_fail (pending != NULL, NULL);
00430 
00431   res = _dbus_data_slot_list_get (&slot_allocator,
00432                                   &pending->slot_list,
00433                                   slot);
00434 
00435   return res;
00436 }
00437 
00440 #ifdef DBUS_BUILD_TESTS
00441 
00448 dbus_bool_t
00449 _dbus_pending_call_test (const char *test_data_dir)
00450 {  
00451 
00452   return TRUE;
00453 }
00454 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Dec 20 14:16:42 2005 for D-BUS by  doxygen 1.4.2