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-message-internal.h"
00028 #include "dbus-pending-call-internal.h"
00029 #include "dbus-pending-call.h"
00030 #include "dbus-list.h"
00031 #include "dbus-threads.h"
00032 #include "dbus-test.h"
00033
00053 #define CONNECTION_LOCK(connection) _dbus_connection_lock(connection)
00054
00057 #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection)
00058
00062 struct DBusPendingCall
00063 {
00064 DBusAtomic refcount;
00066 DBusDataSlotList slot_list;
00068 DBusPendingCallNotifyFunction function;
00070 DBusConnection *connection;
00071 DBusMessage *reply;
00072 DBusTimeout *timeout;
00074 DBusList *timeout_link;
00076 dbus_uint32_t reply_serial;
00078 unsigned int completed : 1;
00079 unsigned int timeout_added : 1;
00080 };
00081
00082 static void
00083 _dbus_pending_call_trace_ref (DBusPendingCall *pending_call,
00084 int old_refcount,
00085 int new_refcount,
00086 const char *why)
00087 {
00088 #ifdef DBUS_ENABLE_VERBOSE_MODE
00089 static int enabled = -1;
00090
00091 _dbus_trace_ref ("DBusPendingCall", pending_call, old_refcount,
00092 new_refcount, why, "DBUS_PENDING_CALL_TRACE", &enabled);
00093 #endif
00094 }
00095
00096 static dbus_int32_t notify_user_data_slot = -1;
00097
00108 DBusPendingCall*
00109 _dbus_pending_call_new_unlocked (DBusConnection *connection,
00110 int timeout_milliseconds,
00111 DBusTimeoutHandler timeout_handler)
00112 {
00113 DBusPendingCall *pending;
00114 DBusTimeout *timeout;
00115
00116 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
00117
00118 if (timeout_milliseconds == -1)
00119 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
00120
00121 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot))
00122 return NULL;
00123
00124 pending = dbus_new0 (DBusPendingCall, 1);
00125
00126 if (pending == NULL)
00127 {
00128 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00129 return NULL;
00130 }
00131
00132 if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
00133 {
00134 timeout = _dbus_timeout_new (timeout_milliseconds,
00135 timeout_handler,
00136 pending, NULL);
00137
00138 if (timeout == NULL)
00139 {
00140 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00141 dbus_free (pending);
00142 return NULL;
00143 }
00144
00145 pending->timeout = timeout;
00146 }
00147 else
00148 {
00149 pending->timeout = NULL;
00150 }
00151
00152 _dbus_atomic_inc (&pending->refcount);
00153 pending->connection = connection;
00154 _dbus_connection_ref_unlocked (pending->connection);
00155
00156 _dbus_data_slot_list_init (&pending->slot_list);
00157
00158 _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked");
00159
00160 return pending;
00161 }
00162
00171 void
00172 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
00173 DBusMessage *message)
00174 {
00175 if (message == NULL)
00176 {
00177 message = pending->timeout_link->data;
00178 _dbus_list_clear (&pending->timeout_link);
00179 }
00180 else
00181 dbus_message_ref (message);
00182
00183 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n",
00184 message,
00185 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
00186 "method return" :
00187 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
00188 "error" : "other type",
00189 pending->reply_serial);
00190
00191 _dbus_assert (pending->reply == NULL);
00192 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
00193 pending->reply = message;
00194 }
00195
00203 void
00204 _dbus_pending_call_complete (DBusPendingCall *pending)
00205 {
00206 _dbus_assert (!pending->completed);
00207
00208 pending->completed = TRUE;
00209
00210 if (pending->function)
00211 {
00212 void *user_data;
00213 user_data = dbus_pending_call_get_data (pending,
00214 notify_user_data_slot);
00215
00216 (* pending->function) (pending, user_data);
00217 }
00218 }
00219
00227 void
00228 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
00229 DBusConnection *connection)
00230 {
00231 _dbus_assert (connection == pending->connection);
00232
00233 if (pending->timeout_link)
00234 {
00235 _dbus_connection_queue_synthesized_message_link (connection,
00236 pending->timeout_link);
00237 pending->timeout_link = NULL;
00238 }
00239 }
00240
00247 dbus_bool_t
00248 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending)
00249 {
00250 _dbus_assert (pending != NULL);
00251
00252 return pending->timeout_added;
00253 }
00254
00255
00262 void
00263 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending,
00264 dbus_bool_t is_added)
00265 {
00266 _dbus_assert (pending != NULL);
00267
00268 pending->timeout_added = is_added;
00269 }
00270
00271
00278 DBusTimeout *
00279 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending)
00280 {
00281 _dbus_assert (pending != NULL);
00282
00283 return pending->timeout;
00284 }
00285
00292 dbus_uint32_t
00293 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending)
00294 {
00295 _dbus_assert (pending != NULL);
00296
00297 return pending->reply_serial;
00298 }
00299
00306 void
00307 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending,
00308 dbus_uint32_t serial)
00309 {
00310 _dbus_assert (pending != NULL);
00311 _dbus_assert (pending->reply_serial == 0);
00312
00313 pending->reply_serial = serial;
00314 }
00315
00322 DBusConnection *
00323 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
00324 {
00325 _dbus_assert (pending != NULL);
00326
00327 CONNECTION_LOCK (pending->connection);
00328 return pending->connection;
00329 }
00330
00337 DBusConnection *
00338 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
00339 {
00340 _dbus_assert (pending != NULL);
00341
00342 return pending->connection;
00343 }
00344
00353 dbus_bool_t
00354 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
00355 DBusMessage *message,
00356 dbus_uint32_t serial)
00357 {
00358 DBusList *reply_link;
00359 DBusMessage *reply;
00360
00361 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
00362 "Did not receive a reply. Possible causes include: "
00363 "the remote application did not send a reply, "
00364 "the message bus security policy blocked the reply, "
00365 "the reply timeout expired, or "
00366 "the network connection was broken.");
00367 if (reply == NULL)
00368 return FALSE;
00369
00370 reply_link = _dbus_list_alloc_link (reply);
00371 if (reply_link == NULL)
00372 {
00373
00374
00375 dbus_message_unref (reply);
00376 return FALSE;
00377 }
00378
00379 pending->timeout_link = reply_link;
00380
00381 _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
00382
00383 return TRUE;
00384 }
00385
00393 DBusPendingCall *
00394 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
00395 {
00396 dbus_int32_t old_refcount;
00397
00398 old_refcount = _dbus_atomic_inc (&pending->refcount);
00399 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
00400 "ref_unlocked");
00401
00402 return pending;
00403 }
00404
00405
00406 static void
00407 _dbus_pending_call_last_unref (DBusPendingCall *pending)
00408 {
00409 DBusConnection *connection;
00410
00411
00412
00413
00414 _dbus_assert (!pending->timeout_added);
00415
00416 connection = pending->connection;
00417
00418
00419 _dbus_data_slot_list_free (&pending->slot_list);
00420
00421 if (pending->timeout != NULL)
00422 _dbus_timeout_unref (pending->timeout);
00423
00424 if (pending->timeout_link)
00425 {
00426 dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
00427 _dbus_list_free_link (pending->timeout_link);
00428 pending->timeout_link = NULL;
00429 }
00430
00431 if (pending->reply)
00432 {
00433 dbus_message_unref (pending->reply);
00434 pending->reply = NULL;
00435 }
00436
00437 dbus_free (pending);
00438
00439 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00440
00441
00442
00443
00444
00445
00446 dbus_connection_unref (connection);
00447 }
00448
00456 void
00457 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
00458 {
00459 dbus_int32_t old_refcount;
00460
00461 old_refcount = _dbus_atomic_dec (&pending->refcount);
00462 _dbus_assert (old_refcount > 0);
00463 _dbus_pending_call_trace_ref (pending, old_refcount,
00464 old_refcount - 1, "unref_and_unlock");
00465
00466 CONNECTION_UNLOCK (pending->connection);
00467
00468 if (old_refcount == 1)
00469 _dbus_pending_call_last_unref (pending);
00470 }
00471
00479 dbus_bool_t
00480 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending)
00481 {
00482 return pending->completed;
00483 }
00484
00485 static DBusDataSlotAllocator slot_allocator =
00486 _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (pending_call_slots));
00487
00501 dbus_bool_t
00502 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
00503 dbus_int32_t slot,
00504 void *data,
00505 DBusFreeFunction free_data_func)
00506 {
00507 DBusFreeFunction old_free_func;
00508 void *old_data;
00509 dbus_bool_t retval;
00510
00511 retval = _dbus_data_slot_list_set (&slot_allocator,
00512 &pending->slot_list,
00513 slot, data, free_data_func,
00514 &old_free_func, &old_data);
00515
00516
00517 CONNECTION_UNLOCK (pending->connection);
00518
00519 if (retval)
00520 {
00521 if (old_free_func)
00522 (* old_free_func) (old_data);
00523 }
00524
00525 CONNECTION_LOCK (pending->connection);
00526
00527 return retval;
00528 }
00529
00576 DBusPendingCall *
00577 dbus_pending_call_ref (DBusPendingCall *pending)
00578 {
00579 dbus_int32_t old_refcount;
00580
00581 _dbus_return_val_if_fail (pending != NULL, NULL);
00582
00583 old_refcount = _dbus_atomic_inc (&pending->refcount);
00584 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
00585 "ref");
00586
00587 return pending;
00588 }
00589
00596 void
00597 dbus_pending_call_unref (DBusPendingCall *pending)
00598 {
00599 dbus_int32_t old_refcount;
00600
00601 _dbus_return_if_fail (pending != NULL);
00602
00603 old_refcount = _dbus_atomic_dec (&pending->refcount);
00604 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1,
00605 "unref");
00606
00607 if (old_refcount == 1)
00608 _dbus_pending_call_last_unref(pending);
00609 }
00610
00621 dbus_bool_t
00622 dbus_pending_call_set_notify (DBusPendingCall *pending,
00623 DBusPendingCallNotifyFunction function,
00624 void *user_data,
00625 DBusFreeFunction free_user_data)
00626 {
00627 dbus_bool_t ret = FALSE;
00628
00629 _dbus_return_val_if_fail (pending != NULL, FALSE);
00630
00631 CONNECTION_LOCK (pending->connection);
00632
00633
00634 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
00635 user_data, free_user_data))
00636 goto out;
00637
00638 pending->function = function;
00639 ret = TRUE;
00640
00641 out:
00642 CONNECTION_UNLOCK (pending->connection);
00643
00644 return ret;
00645 }
00646
00662 void
00663 dbus_pending_call_cancel (DBusPendingCall *pending)
00664 {
00665 _dbus_return_if_fail (pending != NULL);
00666
00667 _dbus_connection_remove_pending_call (pending->connection,
00668 pending);
00669 }
00670
00678 dbus_bool_t
00679 dbus_pending_call_get_completed (DBusPendingCall *pending)
00680 {
00681 dbus_bool_t completed;
00682
00683 _dbus_return_val_if_fail (pending != NULL, FALSE);
00684
00685 CONNECTION_LOCK (pending->connection);
00686 completed = pending->completed;
00687 CONNECTION_UNLOCK (pending->connection);
00688
00689 return completed;
00690 }
00691
00701 DBusMessage*
00702 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00703 {
00704 DBusMessage *message;
00705
00706 _dbus_return_val_if_fail (pending != NULL, NULL);
00707 _dbus_return_val_if_fail (pending->completed, NULL);
00708 _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00709
00710 CONNECTION_LOCK (pending->connection);
00711
00712 message = pending->reply;
00713 pending->reply = NULL;
00714
00715 CONNECTION_UNLOCK (pending->connection);
00716
00717 _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply");
00718 return message;
00719 }
00720
00736 void
00737 dbus_pending_call_block (DBusPendingCall *pending)
00738 {
00739 _dbus_return_if_fail (pending != NULL);
00740
00741 _dbus_connection_block_pending_call (pending);
00742 }
00743
00758 dbus_bool_t
00759 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00760 {
00761 _dbus_return_val_if_fail (slot_p != NULL, FALSE);
00762
00763 return _dbus_data_slot_allocator_alloc (&slot_allocator,
00764 slot_p);
00765 }
00766
00778 void
00779 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00780 {
00781 _dbus_return_if_fail (slot_p != NULL);
00782 _dbus_return_if_fail (*slot_p >= 0);
00783
00784 _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00785 }
00786
00800 dbus_bool_t
00801 dbus_pending_call_set_data (DBusPendingCall *pending,
00802 dbus_int32_t slot,
00803 void *data,
00804 DBusFreeFunction free_data_func)
00805 {
00806 dbus_bool_t retval;
00807
00808 _dbus_return_val_if_fail (pending != NULL, FALSE);
00809 _dbus_return_val_if_fail (slot >= 0, FALSE);
00810
00811
00812 CONNECTION_LOCK (pending->connection);
00813 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
00814 CONNECTION_UNLOCK (pending->connection);
00815 return retval;
00816 }
00817
00826 void*
00827 dbus_pending_call_get_data (DBusPendingCall *pending,
00828 dbus_int32_t slot)
00829 {
00830 void *res;
00831
00832 _dbus_return_val_if_fail (pending != NULL, NULL);
00833
00834 CONNECTION_LOCK (pending->connection);
00835 res = _dbus_data_slot_list_get (&slot_allocator,
00836 &pending->slot_list,
00837 slot);
00838 CONNECTION_UNLOCK (pending->connection);
00839
00840 return res;
00841 }
00842