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
00047 #define CONNECTION_LOCK(connection) _dbus_connection_lock(connection)
00048 #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection)
00049
00050 struct DBusPendingCall
00051 {
00052 DBusAtomic refcount;
00054 DBusDataSlotList slot_list;
00056 DBusPendingCallNotifyFunction function;
00058 DBusConnection *connection;
00059 DBusMessage *reply;
00060 DBusTimeout *timeout;
00062 DBusList *timeout_link;
00064 dbus_uint32_t reply_serial;
00066 unsigned int completed : 1;
00067 unsigned int timeout_added : 1;
00068 };
00069
00070 static dbus_int32_t notify_user_data_slot = -1;
00071
00080 DBusPendingCall*
00081 _dbus_pending_call_new_unlocked (DBusConnection *connection,
00082 int timeout_milliseconds,
00083 DBusTimeoutHandler timeout_handler)
00084 {
00085 DBusPendingCall *pending;
00086 DBusTimeout *timeout;
00087
00088 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
00089
00090 if (timeout_milliseconds == -1)
00091 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
00092
00093
00094
00095
00096
00097
00098 if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
00099 timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
00100
00101 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot))
00102 return NULL;
00103
00104 pending = dbus_new0 (DBusPendingCall, 1);
00105
00106 if (pending == NULL)
00107 {
00108 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00109 return NULL;
00110 }
00111
00112 timeout = _dbus_timeout_new (timeout_milliseconds,
00113 timeout_handler,
00114 pending, NULL);
00115
00116 if (timeout == NULL)
00117 {
00118 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00119 dbus_free (pending);
00120 return NULL;
00121 }
00122
00123 pending->refcount.value = 1;
00124 pending->connection = connection;
00125 _dbus_connection_ref_unlocked (pending->connection);
00126
00127 pending->timeout = timeout;
00128
00129
00130 _dbus_data_slot_list_init (&pending->slot_list);
00131
00132 return pending;
00133 }
00134
00143 void
00144 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
00145 DBusMessage *message)
00146 {
00147 if (message == NULL)
00148 {
00149 message = pending->timeout_link->data;
00150 _dbus_list_clear (&pending->timeout_link);
00151 }
00152 else
00153 dbus_message_ref (message);
00154
00155 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n",
00156 message,
00157 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
00158 "method return" :
00159 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
00160 "error" : "other type",
00161 pending->reply_serial);
00162
00163 _dbus_assert (pending->reply == NULL);
00164 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
00165 pending->reply = message;
00166 }
00167
00175 void
00176 _dbus_pending_call_complete (DBusPendingCall *pending)
00177 {
00178 _dbus_assert (!pending->completed);
00179
00180 pending->completed = TRUE;
00181
00182 if (pending->function)
00183 {
00184 void *user_data;
00185 user_data = dbus_pending_call_get_data (pending,
00186 notify_user_data_slot);
00187
00188 (* pending->function) (pending, user_data);
00189 }
00190 }
00191
00192 void
00193 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
00194 DBusConnection *connection)
00195 {
00196 _dbus_assert (connection == pending->connection);
00197
00198 if (pending->timeout_link)
00199 {
00200 _dbus_connection_queue_synthesized_message_link (connection,
00201 pending->timeout_link);
00202 pending->timeout_link = NULL;
00203 }
00204 }
00205
00212 dbus_bool_t
00213 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending)
00214 {
00215 _dbus_assert (pending != NULL);
00216
00217 return pending->timeout_added;
00218 }
00219
00220
00227 void
00228 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending,
00229 dbus_bool_t is_added)
00230 {
00231 _dbus_assert (pending != NULL);
00232
00233 pending->timeout_added = is_added;
00234 }
00235
00236
00243 DBusTimeout *
00244 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending)
00245 {
00246 _dbus_assert (pending != NULL);
00247
00248 return pending->timeout;
00249 }
00250
00257 dbus_uint32_t
00258 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending)
00259 {
00260 _dbus_assert (pending != NULL);
00261
00262 return pending->reply_serial;
00263 }
00264
00271 void
00272 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending,
00273 dbus_uint32_t serial)
00274 {
00275 _dbus_assert (pending != NULL);
00276 _dbus_assert (pending->reply_serial == 0);
00277
00278 pending->reply_serial = serial;
00279 }
00280
00287 DBusConnection *
00288 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
00289 {
00290 _dbus_assert (pending != NULL);
00291
00292 CONNECTION_LOCK (pending->connection);
00293 return pending->connection;
00294 }
00295
00302 DBusConnection *
00303 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
00304 {
00305 _dbus_assert (pending != NULL);
00306
00307 return pending->connection;
00308 }
00309
00318 dbus_bool_t
00319 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
00320 DBusMessage *message,
00321 dbus_uint32_t serial)
00322 {
00323 DBusList *reply_link;
00324 DBusMessage *reply;
00325
00326 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
00327 "Did not receive a reply. Possible causes include: "
00328 "the remote application did not send a reply, "
00329 "the message bus security policy blocked the reply, "
00330 "the reply timeout expired, or "
00331 "the network connection was broken.");
00332 if (reply == NULL)
00333 return FALSE;
00334
00335 reply_link = _dbus_list_alloc_link (reply);
00336 if (reply_link == NULL)
00337 {
00338 dbus_message_unref (reply);
00339 return FALSE;
00340 }
00341
00342 pending->timeout_link = reply_link;
00343
00344 _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
00345
00346 return TRUE;
00347 }
00348
00376 DBusPendingCall *
00377 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
00378 {
00379 pending->refcount.value += 1;
00380
00381 return pending;
00382 }
00383
00390 DBusPendingCall *
00391 dbus_pending_call_ref (DBusPendingCall *pending)
00392 {
00393 _dbus_return_val_if_fail (pending != NULL, NULL);
00394
00395
00396
00397
00398 #ifdef DBUS_HAVE_ATOMIC_INT
00399 _dbus_atomic_inc (&pending->refcount);
00400 #else
00401 CONNECTION_LOCK (pending->connection);
00402 _dbus_assert (pending->refcount.value > 0);
00403
00404 pending->refcount.value += 1;
00405 CONNECTION_UNLOCK (pending->connection);
00406 #endif
00407
00408 return pending;
00409 }
00410
00411 static void
00412 _dbus_pending_call_last_unref (DBusPendingCall *pending)
00413 {
00414 DBusConnection *connection;
00415
00416
00417
00418
00419 _dbus_assert (!pending->timeout_added);
00420
00421 connection = pending->connection;
00422
00423
00424 _dbus_data_slot_list_free (&pending->slot_list);
00425
00426 if (pending->timeout != NULL)
00427 _dbus_timeout_unref (pending->timeout);
00428
00429 if (pending->timeout_link)
00430 {
00431 dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
00432 _dbus_list_free_link (pending->timeout_link);
00433 pending->timeout_link = NULL;
00434 }
00435
00436 if (pending->reply)
00437 {
00438 dbus_message_unref (pending->reply);
00439 pending->reply = NULL;
00440 }
00441
00442 dbus_free (pending);
00443
00444 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00445
00446
00447
00448
00449
00450
00451 dbus_connection_unref (connection);
00452 }
00453
00461 void
00462 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
00463 {
00464 dbus_bool_t last_unref;
00465
00466 _dbus_assert (pending->refcount.value > 0);
00467
00468 pending->refcount.value -= 1;
00469 last_unref = pending->refcount.value == 0;
00470
00471 CONNECTION_UNLOCK (pending->connection);
00472 if (last_unref)
00473 _dbus_pending_call_last_unref (pending);
00474 }
00475
00482 void
00483 dbus_pending_call_unref (DBusPendingCall *pending)
00484 {
00485 dbus_bool_t last_unref;
00486
00487 _dbus_return_if_fail (pending != NULL);
00488
00489
00490
00491
00492 #ifdef DBUS_HAVE_ATOMIC_INT
00493 last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
00494 #else
00495 CONNECTION_LOCK (pending->connection);
00496 _dbus_assert (pending->refcount.value > 0);
00497 pending->refcount.value -= 1;
00498 last_unref = pending->refcount.value == 0;
00499 CONNECTION_UNLOCK (pending->connection);
00500 #endif
00501
00502 if (last_unref)
00503 _dbus_pending_call_last_unref(pending);
00504 }
00505
00516 dbus_bool_t
00517 dbus_pending_call_set_notify (DBusPendingCall *pending,
00518 DBusPendingCallNotifyFunction function,
00519 void *user_data,
00520 DBusFreeFunction free_user_data)
00521 {
00522 _dbus_return_val_if_fail (pending != NULL, FALSE);
00523
00524 CONNECTION_LOCK (pending->connection);
00525
00526
00527 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
00528 user_data, free_user_data))
00529 return FALSE;
00530
00531 pending->function = function;
00532
00533 CONNECTION_UNLOCK (pending->connection);
00534
00535 return TRUE;
00536 }
00537
00547 void
00548 dbus_pending_call_cancel (DBusPendingCall *pending)
00549 {
00550 _dbus_return_if_fail (pending != NULL);
00551
00552 _dbus_connection_remove_pending_call (pending->connection,
00553 pending);
00554 }
00555
00563 dbus_bool_t
00564 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending)
00565 {
00566 return pending->completed;
00567 }
00568
00576 dbus_bool_t
00577 dbus_pending_call_get_completed (DBusPendingCall *pending)
00578 {
00579 dbus_bool_t completed;
00580
00581 _dbus_return_val_if_fail (pending != NULL, FALSE);
00582
00583 CONNECTION_LOCK (pending->connection);
00584 completed = pending->completed;
00585 CONNECTION_UNLOCK (pending->connection);
00586
00587 return completed;
00588 }
00589
00599 DBusMessage*
00600 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00601 {
00602 DBusMessage *message;
00603
00604 _dbus_return_val_if_fail (pending != NULL, NULL);
00605 _dbus_return_val_if_fail (pending->completed, NULL);
00606 _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00607
00608 CONNECTION_LOCK (pending->connection);
00609
00610 message = pending->reply;
00611 pending->reply = NULL;
00612
00613 CONNECTION_UNLOCK (pending->connection);
00614
00615 return message;
00616 }
00617
00633 void
00634 dbus_pending_call_block (DBusPendingCall *pending)
00635 {
00636 _dbus_return_if_fail (pending != NULL);
00637
00638 _dbus_connection_block_pending_call (pending);
00639 }
00640
00641 static DBusDataSlotAllocator slot_allocator;
00642 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
00643
00658 dbus_bool_t
00659 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00660 {
00661 _dbus_return_val_if_fail (slot_p != NULL, FALSE);
00662
00663 return _dbus_data_slot_allocator_alloc (&slot_allocator,
00664 &_DBUS_LOCK_NAME (pending_call_slots),
00665 slot_p);
00666 }
00667
00679 void
00680 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00681 {
00682 _dbus_return_if_fail (slot_p != NULL);
00683 _dbus_return_if_fail (*slot_p >= 0);
00684
00685 _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00686 }
00687
00701 dbus_bool_t
00702 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
00703 dbus_int32_t slot,
00704 void *data,
00705 DBusFreeFunction free_data_func)
00706 {
00707 DBusFreeFunction old_free_func;
00708 void *old_data;
00709 dbus_bool_t retval;
00710
00711 retval = _dbus_data_slot_list_set (&slot_allocator,
00712 &pending->slot_list,
00713 slot, data, free_data_func,
00714 &old_free_func, &old_data);
00715
00716
00717 CONNECTION_UNLOCK (pending->connection);
00718
00719 if (retval)
00720 {
00721 if (old_free_func)
00722 (* old_free_func) (old_data);
00723 }
00724
00725 CONNECTION_LOCK (pending->connection);
00726
00727 return retval;
00728 }
00729
00743 dbus_bool_t
00744 dbus_pending_call_set_data (DBusPendingCall *pending,
00745 dbus_int32_t slot,
00746 void *data,
00747 DBusFreeFunction free_data_func)
00748 {
00749 dbus_bool_t retval;
00750
00751 _dbus_return_val_if_fail (pending != NULL, FALSE);
00752 _dbus_return_val_if_fail (slot >= 0, FALSE);
00753
00754
00755 CONNECTION_LOCK (pending->connection);
00756 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
00757 CONNECTION_UNLOCK (pending->connection);
00758 return retval;
00759 }
00760
00769 void*
00770 dbus_pending_call_get_data (DBusPendingCall *pending,
00771 dbus_int32_t slot)
00772 {
00773 void *res;
00774
00775 _dbus_return_val_if_fail (pending != NULL, NULL);
00776
00777 CONNECTION_LOCK (pending->connection);
00778 res = _dbus_data_slot_list_get (&slot_allocator,
00779 &pending->slot_list,
00780 slot);
00781 CONNECTION_UNLOCK (pending->connection);
00782
00783 return res;
00784 }
00785
00788 #ifdef DBUS_BUILD_TESTS
00789
00796 dbus_bool_t
00797 _dbus_pending_call_test (const char *test_data_dir)
00798 {
00799
00800 return TRUE;
00801 }
00802 #endif