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