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
00091 DBusPendingCall*
00092 _dbus_pending_call_new_unlocked (DBusConnection *connection,
00093 int timeout_milliseconds,
00094 DBusTimeoutHandler timeout_handler)
00095 {
00096 DBusPendingCall *pending;
00097 DBusTimeout *timeout;
00098
00099 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
00100
00101 if (timeout_milliseconds == -1)
00102 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
00103
00104 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot))
00105 return NULL;
00106
00107 pending = dbus_new0 (DBusPendingCall, 1);
00108
00109 if (pending == NULL)
00110 {
00111 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00112 return NULL;
00113 }
00114
00115 if (timeout_milliseconds != _DBUS_INT_MAX)
00116 {
00117 timeout = _dbus_timeout_new (timeout_milliseconds,
00118 timeout_handler,
00119 pending, NULL);
00120
00121 if (timeout == NULL)
00122 {
00123 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00124 dbus_free (pending);
00125 return NULL;
00126 }
00127
00128 pending->timeout = timeout;
00129 }
00130 else
00131 {
00132 pending->timeout = NULL;
00133 }
00134
00135 pending->refcount.value = 1;
00136 pending->connection = connection;
00137 _dbus_connection_ref_unlocked (pending->connection);
00138
00139 _dbus_data_slot_list_init (&pending->slot_list);
00140
00141 return pending;
00142 }
00143
00152 void
00153 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
00154 DBusMessage *message)
00155 {
00156 if (message == NULL)
00157 {
00158 message = pending->timeout_link->data;
00159 _dbus_list_clear (&pending->timeout_link);
00160 }
00161 else
00162 dbus_message_ref (message);
00163
00164 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n",
00165 message,
00166 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
00167 "method return" :
00168 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
00169 "error" : "other type",
00170 pending->reply_serial);
00171
00172 _dbus_assert (pending->reply == NULL);
00173 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
00174 pending->reply = message;
00175 }
00176
00184 void
00185 _dbus_pending_call_complete (DBusPendingCall *pending)
00186 {
00187 _dbus_assert (!pending->completed);
00188
00189 pending->completed = TRUE;
00190
00191 if (pending->function)
00192 {
00193 void *user_data;
00194 user_data = dbus_pending_call_get_data (pending,
00195 notify_user_data_slot);
00196
00197 (* pending->function) (pending, user_data);
00198 }
00199 }
00200
00208 void
00209 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
00210 DBusConnection *connection)
00211 {
00212 _dbus_assert (connection == pending->connection);
00213
00214 if (pending->timeout_link)
00215 {
00216 _dbus_connection_queue_synthesized_message_link (connection,
00217 pending->timeout_link);
00218 pending->timeout_link = NULL;
00219 }
00220 }
00221
00228 dbus_bool_t
00229 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending)
00230 {
00231 _dbus_assert (pending != NULL);
00232
00233 return pending->timeout_added;
00234 }
00235
00236
00243 void
00244 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending,
00245 dbus_bool_t is_added)
00246 {
00247 _dbus_assert (pending != NULL);
00248
00249 pending->timeout_added = is_added;
00250 }
00251
00252
00259 DBusTimeout *
00260 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending)
00261 {
00262 _dbus_assert (pending != NULL);
00263
00264 return pending->timeout;
00265 }
00266
00273 dbus_uint32_t
00274 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending)
00275 {
00276 _dbus_assert (pending != NULL);
00277
00278 return pending->reply_serial;
00279 }
00280
00287 void
00288 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending,
00289 dbus_uint32_t serial)
00290 {
00291 _dbus_assert (pending != NULL);
00292 _dbus_assert (pending->reply_serial == 0);
00293
00294 pending->reply_serial = serial;
00295 }
00296
00303 DBusConnection *
00304 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
00305 {
00306 _dbus_assert (pending != NULL);
00307
00308 CONNECTION_LOCK (pending->connection);
00309 return pending->connection;
00310 }
00311
00318 DBusConnection *
00319 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
00320 {
00321 _dbus_assert (pending != NULL);
00322
00323 return pending->connection;
00324 }
00325
00334 dbus_bool_t
00335 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
00336 DBusMessage *message,
00337 dbus_uint32_t serial)
00338 {
00339 DBusList *reply_link;
00340 DBusMessage *reply;
00341
00342 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
00343 "Did not receive a reply. Possible causes include: "
00344 "the remote application did not send a reply, "
00345 "the message bus security policy blocked the reply, "
00346 "the reply timeout expired, or "
00347 "the network connection was broken.");
00348 if (reply == NULL)
00349 return FALSE;
00350
00351 reply_link = _dbus_list_alloc_link (reply);
00352 if (reply_link == NULL)
00353 {
00354 dbus_message_unref (reply);
00355 return FALSE;
00356 }
00357
00358 pending->timeout_link = reply_link;
00359
00360 _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
00361
00362 return TRUE;
00363 }
00364
00372 DBusPendingCall *
00373 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
00374 {
00375 pending->refcount.value += 1;
00376
00377 return pending;
00378 }
00379
00380
00381 static void
00382 _dbus_pending_call_last_unref (DBusPendingCall *pending)
00383 {
00384 DBusConnection *connection;
00385
00386
00387
00388
00389 _dbus_assert (!pending->timeout_added);
00390
00391 connection = pending->connection;
00392
00393
00394 _dbus_data_slot_list_free (&pending->slot_list);
00395
00396 if (pending->timeout != NULL)
00397 _dbus_timeout_unref (pending->timeout);
00398
00399 if (pending->timeout_link)
00400 {
00401 dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
00402 _dbus_list_free_link (pending->timeout_link);
00403 pending->timeout_link = NULL;
00404 }
00405
00406 if (pending->reply)
00407 {
00408 dbus_message_unref (pending->reply);
00409 pending->reply = NULL;
00410 }
00411
00412 dbus_free (pending);
00413
00414 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00415
00416
00417
00418
00419
00420
00421 dbus_connection_unref (connection);
00422 }
00423
00431 void
00432 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
00433 {
00434 dbus_bool_t last_unref;
00435
00436 _dbus_assert (pending->refcount.value > 0);
00437
00438 pending->refcount.value -= 1;
00439 last_unref = pending->refcount.value == 0;
00440
00441 CONNECTION_UNLOCK (pending->connection);
00442 if (last_unref)
00443 _dbus_pending_call_last_unref (pending);
00444 }
00445
00453 dbus_bool_t
00454 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending)
00455 {
00456 return pending->completed;
00457 }
00458
00459 static DBusDataSlotAllocator slot_allocator;
00460 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
00461
00475 dbus_bool_t
00476 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
00477 dbus_int32_t slot,
00478 void *data,
00479 DBusFreeFunction free_data_func)
00480 {
00481 DBusFreeFunction old_free_func;
00482 void *old_data;
00483 dbus_bool_t retval;
00484
00485 retval = _dbus_data_slot_list_set (&slot_allocator,
00486 &pending->slot_list,
00487 slot, data, free_data_func,
00488 &old_free_func, &old_data);
00489
00490
00491 CONNECTION_UNLOCK (pending->connection);
00492
00493 if (retval)
00494 {
00495 if (old_free_func)
00496 (* old_free_func) (old_data);
00497 }
00498
00499 CONNECTION_LOCK (pending->connection);
00500
00501 return retval;
00502 }
00503
00530 DBusPendingCall *
00531 dbus_pending_call_ref (DBusPendingCall *pending)
00532 {
00533 _dbus_return_val_if_fail (pending != NULL, NULL);
00534
00535
00536
00537
00538 #ifdef DBUS_HAVE_ATOMIC_INT
00539 _dbus_atomic_inc (&pending->refcount);
00540 #else
00541 CONNECTION_LOCK (pending->connection);
00542 _dbus_assert (pending->refcount.value > 0);
00543
00544 pending->refcount.value += 1;
00545 CONNECTION_UNLOCK (pending->connection);
00546 #endif
00547
00548 return pending;
00549 }
00550
00557 void
00558 dbus_pending_call_unref (DBusPendingCall *pending)
00559 {
00560 dbus_bool_t last_unref;
00561
00562 _dbus_return_if_fail (pending != NULL);
00563
00564
00565
00566
00567 #ifdef DBUS_HAVE_ATOMIC_INT
00568 last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
00569 #else
00570 CONNECTION_LOCK (pending->connection);
00571 _dbus_assert (pending->refcount.value > 0);
00572 pending->refcount.value -= 1;
00573 last_unref = pending->refcount.value == 0;
00574 CONNECTION_UNLOCK (pending->connection);
00575 #endif
00576
00577 if (last_unref)
00578 _dbus_pending_call_last_unref(pending);
00579 }
00580
00591 dbus_bool_t
00592 dbus_pending_call_set_notify (DBusPendingCall *pending,
00593 DBusPendingCallNotifyFunction function,
00594 void *user_data,
00595 DBusFreeFunction free_user_data)
00596 {
00597 _dbus_return_val_if_fail (pending != NULL, FALSE);
00598
00599 CONNECTION_LOCK (pending->connection);
00600
00601
00602 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
00603 user_data, free_user_data))
00604 return FALSE;
00605
00606 pending->function = function;
00607
00608 CONNECTION_UNLOCK (pending->connection);
00609
00610 return TRUE;
00611 }
00612
00628 void
00629 dbus_pending_call_cancel (DBusPendingCall *pending)
00630 {
00631 _dbus_return_if_fail (pending != NULL);
00632
00633 _dbus_connection_remove_pending_call (pending->connection,
00634 pending);
00635 }
00636
00644 dbus_bool_t
00645 dbus_pending_call_get_completed (DBusPendingCall *pending)
00646 {
00647 dbus_bool_t completed;
00648
00649 _dbus_return_val_if_fail (pending != NULL, FALSE);
00650
00651 CONNECTION_LOCK (pending->connection);
00652 completed = pending->completed;
00653 CONNECTION_UNLOCK (pending->connection);
00654
00655 return completed;
00656 }
00657
00667 DBusMessage*
00668 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00669 {
00670 DBusMessage *message;
00671
00672 _dbus_return_val_if_fail (pending != NULL, NULL);
00673 _dbus_return_val_if_fail (pending->completed, NULL);
00674 _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00675
00676 CONNECTION_LOCK (pending->connection);
00677
00678 message = pending->reply;
00679 pending->reply = NULL;
00680
00681 CONNECTION_UNLOCK (pending->connection);
00682
00683 return message;
00684 }
00685
00701 void
00702 dbus_pending_call_block (DBusPendingCall *pending)
00703 {
00704 _dbus_return_if_fail (pending != NULL);
00705
00706 _dbus_connection_block_pending_call (pending);
00707 }
00708
00723 dbus_bool_t
00724 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00725 {
00726 _dbus_return_val_if_fail (slot_p != NULL, FALSE);
00727
00728 return _dbus_data_slot_allocator_alloc (&slot_allocator,
00729 &_DBUS_LOCK_NAME (pending_call_slots),
00730 slot_p);
00731 }
00732
00744 void
00745 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00746 {
00747 _dbus_return_if_fail (slot_p != NULL);
00748 _dbus_return_if_fail (*slot_p >= 0);
00749
00750 _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00751 }
00752
00766 dbus_bool_t
00767 dbus_pending_call_set_data (DBusPendingCall *pending,
00768 dbus_int32_t slot,
00769 void *data,
00770 DBusFreeFunction free_data_func)
00771 {
00772 dbus_bool_t retval;
00773
00774 _dbus_return_val_if_fail (pending != NULL, FALSE);
00775 _dbus_return_val_if_fail (slot >= 0, FALSE);
00776
00777
00778 CONNECTION_LOCK (pending->connection);
00779 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
00780 CONNECTION_UNLOCK (pending->connection);
00781 return retval;
00782 }
00783
00792 void*
00793 dbus_pending_call_get_data (DBusPendingCall *pending,
00794 dbus_int32_t slot)
00795 {
00796 void *res;
00797
00798 _dbus_return_val_if_fail (pending != NULL, NULL);
00799
00800 CONNECTION_LOCK (pending->connection);
00801 res = _dbus_data_slot_list_get (&slot_allocator,
00802 &pending->slot_list,
00803 slot);
00804 CONNECTION_UNLOCK (pending->connection);
00805
00806 return res;
00807 }
00808
00811 #ifdef DBUS_BUILD_TESTS
00812
00819 dbus_bool_t
00820 _dbus_pending_call_test (const char *test_data_dir)
00821 {
00822
00823 return TRUE;
00824 }
00825 #endif