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