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 _dbus_atomic_inc (&pending->refcount);
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
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
00531 DBusPendingCall *
00532 dbus_pending_call_ref (DBusPendingCall *pending)
00533 {
00534 _dbus_return_val_if_fail (pending != NULL, NULL);
00535
00536 _dbus_atomic_inc (&pending->refcount);
00537
00538 return pending;
00539 }
00540
00547 void
00548 dbus_pending_call_unref (DBusPendingCall *pending)
00549 {
00550 dbus_bool_t last_unref;
00551
00552 _dbus_return_if_fail (pending != NULL);
00553
00554 last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
00555
00556 if (last_unref)
00557 _dbus_pending_call_last_unref(pending);
00558 }
00559
00570 dbus_bool_t
00571 dbus_pending_call_set_notify (DBusPendingCall *pending,
00572 DBusPendingCallNotifyFunction function,
00573 void *user_data,
00574 DBusFreeFunction free_user_data)
00575 {
00576 _dbus_return_val_if_fail (pending != NULL, FALSE);
00577
00578 CONNECTION_LOCK (pending->connection);
00579
00580
00581 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
00582 user_data, free_user_data))
00583 return FALSE;
00584
00585 pending->function = function;
00586
00587 CONNECTION_UNLOCK (pending->connection);
00588
00589 return TRUE;
00590 }
00591
00607 void
00608 dbus_pending_call_cancel (DBusPendingCall *pending)
00609 {
00610 _dbus_return_if_fail (pending != NULL);
00611
00612 _dbus_connection_remove_pending_call (pending->connection,
00613 pending);
00614 }
00615
00623 dbus_bool_t
00624 dbus_pending_call_get_completed (DBusPendingCall *pending)
00625 {
00626 dbus_bool_t completed;
00627
00628 _dbus_return_val_if_fail (pending != NULL, FALSE);
00629
00630 CONNECTION_LOCK (pending->connection);
00631 completed = pending->completed;
00632 CONNECTION_UNLOCK (pending->connection);
00633
00634 return completed;
00635 }
00636
00646 DBusMessage*
00647 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00648 {
00649 DBusMessage *message;
00650
00651 _dbus_return_val_if_fail (pending != NULL, NULL);
00652 _dbus_return_val_if_fail (pending->completed, NULL);
00653 _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00654
00655 CONNECTION_LOCK (pending->connection);
00656
00657 message = pending->reply;
00658 pending->reply = NULL;
00659
00660 CONNECTION_UNLOCK (pending->connection);
00661
00662 return message;
00663 }
00664
00680 void
00681 dbus_pending_call_block (DBusPendingCall *pending)
00682 {
00683 _dbus_return_if_fail (pending != NULL);
00684
00685 _dbus_connection_block_pending_call (pending);
00686 }
00687
00702 dbus_bool_t
00703 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00704 {
00705 _dbus_return_val_if_fail (slot_p != NULL, FALSE);
00706
00707 return _dbus_data_slot_allocator_alloc (&slot_allocator,
00708 &_DBUS_LOCK_NAME (pending_call_slots),
00709 slot_p);
00710 }
00711
00723 void
00724 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00725 {
00726 _dbus_return_if_fail (slot_p != NULL);
00727 _dbus_return_if_fail (*slot_p >= 0);
00728
00729 _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00730 }
00731
00745 dbus_bool_t
00746 dbus_pending_call_set_data (DBusPendingCall *pending,
00747 dbus_int32_t slot,
00748 void *data,
00749 DBusFreeFunction free_data_func)
00750 {
00751 dbus_bool_t retval;
00752
00753 _dbus_return_val_if_fail (pending != NULL, FALSE);
00754 _dbus_return_val_if_fail (slot >= 0, FALSE);
00755
00756
00757 CONNECTION_LOCK (pending->connection);
00758 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
00759 CONNECTION_UNLOCK (pending->connection);
00760 return retval;
00761 }
00762
00771 void*
00772 dbus_pending_call_get_data (DBusPendingCall *pending,
00773 dbus_int32_t slot)
00774 {
00775 void *res;
00776
00777 _dbus_return_val_if_fail (pending != NULL, NULL);
00778
00779 CONNECTION_LOCK (pending->connection);
00780 res = _dbus_data_slot_list_get (&slot_allocator,
00781 &pending->slot_list,
00782 slot);
00783 CONNECTION_UNLOCK (pending->connection);
00784
00785 return res;
00786 }
00787
00790 #ifdef DBUS_BUILD_TESTS
00791
00798 dbus_bool_t
00799 _dbus_pending_call_test (const char *test_data_dir)
00800 {
00801
00802 return TRUE;
00803 }
00804 #endif