00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "dbus-internals.h"
00026 #include "dbus-connection-internal.h"
00027 #include "dbus-pending-call-internal.h"
00028 #include "dbus-pending-call.h"
00029 #include "dbus-list.h"
00030 #include "dbus-threads.h"
00031 #include "dbus-test.h"
00032
00052 #define CONNECTION_LOCK(connection) _dbus_connection_lock(connection)
00053
00056 #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection)
00057
00061 struct DBusPendingCall
00062 {
00063 DBusAtomic refcount;
00065 DBusDataSlotList slot_list;
00067 DBusPendingCallNotifyFunction function;
00069 DBusConnection *connection;
00070 DBusMessage *reply;
00071 DBusTimeout *timeout;
00073 DBusList *timeout_link;
00075 dbus_uint32_t reply_serial;
00077 unsigned int completed : 1;
00078 unsigned int timeout_added : 1;
00079 };
00080
00081 static dbus_int32_t notify_user_data_slot = -1;
00082
00093 DBusPendingCall*
00094 _dbus_pending_call_new_unlocked (DBusConnection *connection,
00095 int timeout_milliseconds,
00096 DBusTimeoutHandler timeout_handler)
00097 {
00098 DBusPendingCall *pending;
00099 DBusTimeout *timeout;
00100
00101 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
00102
00103 if (timeout_milliseconds == -1)
00104 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
00105
00106 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot))
00107 return NULL;
00108
00109 pending = dbus_new0 (DBusPendingCall, 1);
00110
00111 if (pending == NULL)
00112 {
00113 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00114 return NULL;
00115 }
00116
00117 if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
00118 {
00119 timeout = _dbus_timeout_new (timeout_milliseconds,
00120 timeout_handler,
00121 pending, NULL);
00122
00123 if (timeout == NULL)
00124 {
00125 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00126 dbus_free (pending);
00127 return NULL;
00128 }
00129
00130 pending->timeout = timeout;
00131 }
00132 else
00133 {
00134 pending->timeout = NULL;
00135 }
00136
00137 _dbus_atomic_inc (&pending->refcount);
00138 pending->connection = connection;
00139 _dbus_connection_ref_unlocked (pending->connection);
00140
00141 _dbus_data_slot_list_init (&pending->slot_list);
00142
00143 return pending;
00144 }
00145
00154 void
00155 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
00156 DBusMessage *message)
00157 {
00158 if (message == NULL)
00159 {
00160 message = pending->timeout_link->data;
00161 _dbus_list_clear (&pending->timeout_link);
00162 }
00163 else
00164 dbus_message_ref (message);
00165
00166 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n",
00167 message,
00168 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
00169 "method return" :
00170 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
00171 "error" : "other type",
00172 pending->reply_serial);
00173
00174 _dbus_assert (pending->reply == NULL);
00175 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
00176 pending->reply = message;
00177 }
00178
00186 void
00187 _dbus_pending_call_complete (DBusPendingCall *pending)
00188 {
00189 _dbus_assert (!pending->completed);
00190
00191 pending->completed = TRUE;
00192
00193 if (pending->function)
00194 {
00195 void *user_data;
00196 user_data = dbus_pending_call_get_data (pending,
00197 notify_user_data_slot);
00198
00199 (* pending->function) (pending, user_data);
00200 }
00201 }
00202
00210 void
00211 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
00212 DBusConnection *connection)
00213 {
00214 _dbus_assert (connection == pending->connection);
00215
00216 if (pending->timeout_link)
00217 {
00218 _dbus_connection_queue_synthesized_message_link (connection,
00219 pending->timeout_link);
00220 pending->timeout_link = NULL;
00221 }
00222 }
00223
00230 dbus_bool_t
00231 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending)
00232 {
00233 _dbus_assert (pending != NULL);
00234
00235 return pending->timeout_added;
00236 }
00237
00238
00245 void
00246 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending,
00247 dbus_bool_t is_added)
00248 {
00249 _dbus_assert (pending != NULL);
00250
00251 pending->timeout_added = is_added;
00252 }
00253
00254
00261 DBusTimeout *
00262 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending)
00263 {
00264 _dbus_assert (pending != NULL);
00265
00266 return pending->timeout;
00267 }
00268
00275 dbus_uint32_t
00276 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending)
00277 {
00278 _dbus_assert (pending != NULL);
00279
00280 return pending->reply_serial;
00281 }
00282
00289 void
00290 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending,
00291 dbus_uint32_t serial)
00292 {
00293 _dbus_assert (pending != NULL);
00294 _dbus_assert (pending->reply_serial == 0);
00295
00296 pending->reply_serial = serial;
00297 }
00298
00305 DBusConnection *
00306 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
00307 {
00308 _dbus_assert (pending != NULL);
00309
00310 CONNECTION_LOCK (pending->connection);
00311 return pending->connection;
00312 }
00313
00320 DBusConnection *
00321 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
00322 {
00323 _dbus_assert (pending != NULL);
00324
00325 return pending->connection;
00326 }
00327
00336 dbus_bool_t
00337 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
00338 DBusMessage *message,
00339 dbus_uint32_t serial)
00340 {
00341 DBusList *reply_link;
00342 DBusMessage *reply;
00343
00344 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
00345 "Did not receive a reply. Possible causes include: "
00346 "the remote application did not send a reply, "
00347 "the message bus security policy blocked the reply, "
00348 "the reply timeout expired, or "
00349 "the network connection was broken.");
00350 if (reply == NULL)
00351 return FALSE;
00352
00353 reply_link = _dbus_list_alloc_link (reply);
00354 if (reply_link == NULL)
00355 {
00356 dbus_message_unref (reply);
00357 return FALSE;
00358 }
00359
00360 pending->timeout_link = reply_link;
00361
00362 _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
00363
00364 return TRUE;
00365 }
00366
00374 DBusPendingCall *
00375 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
00376 {
00377 _dbus_atomic_inc (&pending->refcount);
00378
00379 return pending;
00380 }
00381
00382
00383 static void
00384 _dbus_pending_call_last_unref (DBusPendingCall *pending)
00385 {
00386 DBusConnection *connection;
00387
00388
00389
00390
00391 _dbus_assert (!pending->timeout_added);
00392
00393 connection = pending->connection;
00394
00395
00396 _dbus_data_slot_list_free (&pending->slot_list);
00397
00398 if (pending->timeout != NULL)
00399 _dbus_timeout_unref (pending->timeout);
00400
00401 if (pending->timeout_link)
00402 {
00403 dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
00404 _dbus_list_free_link (pending->timeout_link);
00405 pending->timeout_link = NULL;
00406 }
00407
00408 if (pending->reply)
00409 {
00410 dbus_message_unref (pending->reply);
00411 pending->reply = NULL;
00412 }
00413
00414 dbus_free (pending);
00415
00416 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00417
00418
00419
00420
00421
00422
00423 dbus_connection_unref (connection);
00424 }
00425
00433 void
00434 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
00435 {
00436 dbus_int32_t old_refcount;
00437
00438 old_refcount = _dbus_atomic_dec (&pending->refcount);
00439 _dbus_assert (old_refcount > 0);
00440
00441 CONNECTION_UNLOCK (pending->connection);
00442
00443 if (old_refcount == 1)
00444 _dbus_pending_call_last_unref (pending);
00445 }
00446
00454 dbus_bool_t
00455 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending)
00456 {
00457 return pending->completed;
00458 }
00459
00460 static DBusDataSlotAllocator slot_allocator;
00461 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
00462
00476 dbus_bool_t
00477 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
00478 dbus_int32_t slot,
00479 void *data,
00480 DBusFreeFunction free_data_func)
00481 {
00482 DBusFreeFunction old_free_func;
00483 void *old_data;
00484 dbus_bool_t retval;
00485
00486 retval = _dbus_data_slot_list_set (&slot_allocator,
00487 &pending->slot_list,
00488 slot, data, free_data_func,
00489 &old_free_func, &old_data);
00490
00491
00492 CONNECTION_UNLOCK (pending->connection);
00493
00494 if (retval)
00495 {
00496 if (old_free_func)
00497 (* old_free_func) (old_data);
00498 }
00499
00500 CONNECTION_LOCK (pending->connection);
00501
00502 return retval;
00503 }
00504
00551 DBusPendingCall *
00552 dbus_pending_call_ref (DBusPendingCall *pending)
00553 {
00554 _dbus_return_val_if_fail (pending != NULL, NULL);
00555
00556 _dbus_atomic_inc (&pending->refcount);
00557
00558 return pending;
00559 }
00560
00567 void
00568 dbus_pending_call_unref (DBusPendingCall *pending)
00569 {
00570 dbus_bool_t last_unref;
00571
00572 _dbus_return_if_fail (pending != NULL);
00573
00574 last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
00575
00576 if (last_unref)
00577 _dbus_pending_call_last_unref(pending);
00578 }
00579
00590 dbus_bool_t
00591 dbus_pending_call_set_notify (DBusPendingCall *pending,
00592 DBusPendingCallNotifyFunction function,
00593 void *user_data,
00594 DBusFreeFunction free_user_data)
00595 {
00596 _dbus_return_val_if_fail (pending != NULL, FALSE);
00597
00598 CONNECTION_LOCK (pending->connection);
00599
00600
00601 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
00602 user_data, free_user_data))
00603 return FALSE;
00604
00605 pending->function = function;
00606
00607 CONNECTION_UNLOCK (pending->connection);
00608
00609 return TRUE;
00610 }
00611
00627 void
00628 dbus_pending_call_cancel (DBusPendingCall *pending)
00629 {
00630 _dbus_return_if_fail (pending != NULL);
00631
00632 _dbus_connection_remove_pending_call (pending->connection,
00633 pending);
00634 }
00635
00643 dbus_bool_t
00644 dbus_pending_call_get_completed (DBusPendingCall *pending)
00645 {
00646 dbus_bool_t completed;
00647
00648 _dbus_return_val_if_fail (pending != NULL, FALSE);
00649
00650 CONNECTION_LOCK (pending->connection);
00651 completed = pending->completed;
00652 CONNECTION_UNLOCK (pending->connection);
00653
00654 return completed;
00655 }
00656
00666 DBusMessage*
00667 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00668 {
00669 DBusMessage *message;
00670
00671 _dbus_return_val_if_fail (pending != NULL, NULL);
00672 _dbus_return_val_if_fail (pending->completed, NULL);
00673 _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00674
00675 CONNECTION_LOCK (pending->connection);
00676
00677 message = pending->reply;
00678 pending->reply = NULL;
00679
00680 CONNECTION_UNLOCK (pending->connection);
00681
00682 return message;
00683 }
00684
00700 void
00701 dbus_pending_call_block (DBusPendingCall *pending)
00702 {
00703 _dbus_return_if_fail (pending != NULL);
00704
00705 _dbus_connection_block_pending_call (pending);
00706 }
00707
00722 dbus_bool_t
00723 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00724 {
00725 _dbus_return_val_if_fail (slot_p != NULL, FALSE);
00726
00727 return _dbus_data_slot_allocator_alloc (&slot_allocator,
00728 &_DBUS_LOCK_NAME (pending_call_slots),
00729 slot_p);
00730 }
00731
00743 void
00744 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00745 {
00746 _dbus_return_if_fail (slot_p != NULL);
00747 _dbus_return_if_fail (*slot_p >= 0);
00748
00749 _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00750 }
00751
00765 dbus_bool_t
00766 dbus_pending_call_set_data (DBusPendingCall *pending,
00767 dbus_int32_t slot,
00768 void *data,
00769 DBusFreeFunction free_data_func)
00770 {
00771 dbus_bool_t retval;
00772
00773 _dbus_return_val_if_fail (pending != NULL, FALSE);
00774 _dbus_return_val_if_fail (slot >= 0, FALSE);
00775
00776
00777 CONNECTION_LOCK (pending->connection);
00778 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
00779 CONNECTION_UNLOCK (pending->connection);
00780 return retval;
00781 }
00782
00791 void*
00792 dbus_pending_call_get_data (DBusPendingCall *pending,
00793 dbus_int32_t slot)
00794 {
00795 void *res;
00796
00797 _dbus_return_val_if_fail (pending != NULL, NULL);
00798
00799 CONNECTION_LOCK (pending->connection);
00800 res = _dbus_data_slot_list_get (&slot_allocator,
00801 &pending->slot_list,
00802 slot);
00803 CONNECTION_UNLOCK (pending->connection);
00804
00805 return res;
00806 }
00807
00810 #ifdef DBUS_BUILD_TESTS
00811
00818 dbus_bool_t
00819 _dbus_pending_call_test (const char *test_data_dir)
00820 {
00821
00822 return TRUE;
00823 }
00824 #endif