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 #ifdef DBUS_ENABLE_VERBOSE_MODE
00083 static void
00084 _dbus_pending_call_trace_ref (DBusPendingCall *pending_call,
00085 int old_refcount,
00086 int new_refcount,
00087 const char *why)
00088 {
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 }
00094 #else
00095 #define _dbus_pending_call_trace_ref(p, o, n, w) \
00096 do \
00097 {\
00098 (void) (o); \
00099 (void) (n); \
00100 } while (0)
00101 #endif
00102
00103 static dbus_int32_t notify_user_data_slot = -1;
00104
00115 DBusPendingCall*
00116 _dbus_pending_call_new_unlocked (DBusConnection *connection,
00117 int timeout_milliseconds,
00118 DBusTimeoutHandler timeout_handler)
00119 {
00120 DBusPendingCall *pending;
00121 DBusTimeout *timeout;
00122
00123 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
00124
00125 if (timeout_milliseconds == -1)
00126 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
00127
00128 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot))
00129 return NULL;
00130
00131 pending = dbus_new0 (DBusPendingCall, 1);
00132
00133 if (pending == NULL)
00134 {
00135 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00136 return NULL;
00137 }
00138
00139 if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
00140 {
00141 timeout = _dbus_timeout_new (timeout_milliseconds,
00142 timeout_handler,
00143 pending, NULL);
00144
00145 if (timeout == NULL)
00146 {
00147 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00148 dbus_free (pending);
00149 return NULL;
00150 }
00151
00152 pending->timeout = timeout;
00153 }
00154 else
00155 {
00156 pending->timeout = NULL;
00157 }
00158
00159 _dbus_atomic_inc (&pending->refcount);
00160 pending->connection = connection;
00161 _dbus_connection_ref_unlocked (pending->connection);
00162
00163 _dbus_data_slot_list_init (&pending->slot_list);
00164
00165 _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked");
00166
00167 return pending;
00168 }
00169
00178 void
00179 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
00180 DBusMessage *message)
00181 {
00182 if (message == NULL)
00183 {
00184 message = pending->timeout_link->data;
00185 _dbus_list_clear (&pending->timeout_link);
00186 }
00187 else
00188 dbus_message_ref (message);
00189
00190 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n",
00191 message,
00192 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
00193 "method return" :
00194 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
00195 "error" : "other type",
00196 pending->reply_serial);
00197
00198 _dbus_assert (pending->reply == NULL);
00199 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
00200 pending->reply = message;
00201 }
00202
00210 void
00211 _dbus_pending_call_complete (DBusPendingCall *pending)
00212 {
00213 _dbus_assert (!pending->completed);
00214
00215 pending->completed = TRUE;
00216
00217 if (pending->function)
00218 {
00219 void *user_data;
00220 user_data = dbus_pending_call_get_data (pending,
00221 notify_user_data_slot);
00222
00223 (* pending->function) (pending, user_data);
00224 }
00225 }
00226
00234 void
00235 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
00236 DBusConnection *connection)
00237 {
00238 _dbus_assert (connection == pending->connection);
00239
00240 if (pending->timeout_link)
00241 {
00242 _dbus_connection_queue_synthesized_message_link (connection,
00243 pending->timeout_link);
00244 pending->timeout_link = NULL;
00245 }
00246 }
00247
00254 dbus_bool_t
00255 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending)
00256 {
00257 _dbus_assert (pending != NULL);
00258
00259 return pending->timeout_added;
00260 }
00261
00262
00269 void
00270 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending,
00271 dbus_bool_t is_added)
00272 {
00273 _dbus_assert (pending != NULL);
00274
00275 pending->timeout_added = is_added;
00276 }
00277
00278
00285 DBusTimeout *
00286 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending)
00287 {
00288 _dbus_assert (pending != NULL);
00289
00290 return pending->timeout;
00291 }
00292
00299 dbus_uint32_t
00300 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending)
00301 {
00302 _dbus_assert (pending != NULL);
00303
00304 return pending->reply_serial;
00305 }
00306
00313 void
00314 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending,
00315 dbus_uint32_t serial)
00316 {
00317 _dbus_assert (pending != NULL);
00318 _dbus_assert (pending->reply_serial == 0);
00319
00320 pending->reply_serial = serial;
00321 }
00322
00329 DBusConnection *
00330 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
00331 {
00332 _dbus_assert (pending != NULL);
00333
00334 CONNECTION_LOCK (pending->connection);
00335 return pending->connection;
00336 }
00337
00344 DBusConnection *
00345 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
00346 {
00347 _dbus_assert (pending != NULL);
00348
00349 return pending->connection;
00350 }
00351
00360 dbus_bool_t
00361 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
00362 DBusMessage *message,
00363 dbus_uint32_t serial)
00364 {
00365 DBusList *reply_link;
00366 DBusMessage *reply;
00367
00368 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
00369 "Did not receive a reply. Possible causes include: "
00370 "the remote application did not send a reply, "
00371 "the message bus security policy blocked the reply, "
00372 "the reply timeout expired, or "
00373 "the network connection was broken.");
00374 if (reply == NULL)
00375 return FALSE;
00376
00377 reply_link = _dbus_list_alloc_link (reply);
00378 if (reply_link == NULL)
00379 {
00380
00381
00382 dbus_message_unref (reply);
00383 return FALSE;
00384 }
00385
00386 pending->timeout_link = reply_link;
00387
00388 _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
00389
00390 return TRUE;
00391 }
00392
00400 DBusPendingCall *
00401 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
00402 {
00403 dbus_int32_t old_refcount;
00404
00405 old_refcount = _dbus_atomic_inc (&pending->refcount);
00406 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
00407 "ref_unlocked");
00408
00409 return pending;
00410 }
00411
00412
00413 static void
00414 _dbus_pending_call_last_unref (DBusPendingCall *pending)
00415 {
00416 DBusConnection *connection;
00417
00418
00419
00420
00421 _dbus_assert (!pending->timeout_added);
00422
00423 connection = pending->connection;
00424
00425
00426 _dbus_data_slot_list_free (&pending->slot_list);
00427
00428 if (pending->timeout != NULL)
00429 _dbus_timeout_unref (pending->timeout);
00430
00431 if (pending->timeout_link)
00432 {
00433 dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
00434 _dbus_list_free_link (pending->timeout_link);
00435 pending->timeout_link = NULL;
00436 }
00437
00438 if (pending->reply)
00439 {
00440 dbus_message_unref (pending->reply);
00441 pending->reply = NULL;
00442 }
00443
00444 dbus_free (pending);
00445
00446 dbus_pending_call_free_data_slot (¬ify_user_data_slot);
00447
00448
00449
00450
00451
00452
00453 dbus_connection_unref (connection);
00454 }
00455
00463 void
00464 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
00465 {
00466 dbus_int32_t old_refcount;
00467
00468 old_refcount = _dbus_atomic_dec (&pending->refcount);
00469 _dbus_assert (old_refcount > 0);
00470 _dbus_pending_call_trace_ref (pending, old_refcount,
00471 old_refcount - 1, "unref_and_unlock");
00472
00473 CONNECTION_UNLOCK (pending->connection);
00474
00475 if (old_refcount == 1)
00476 _dbus_pending_call_last_unref (pending);
00477 }
00478
00486 dbus_bool_t
00487 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending)
00488 {
00489 return pending->completed;
00490 }
00491
00492 static DBusDataSlotAllocator slot_allocator;
00493 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
00494
00508 dbus_bool_t
00509 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
00510 dbus_int32_t slot,
00511 void *data,
00512 DBusFreeFunction free_data_func)
00513 {
00514 DBusFreeFunction old_free_func;
00515 void *old_data;
00516 dbus_bool_t retval;
00517
00518 retval = _dbus_data_slot_list_set (&slot_allocator,
00519 &pending->slot_list,
00520 slot, data, free_data_func,
00521 &old_free_func, &old_data);
00522
00523
00524 CONNECTION_UNLOCK (pending->connection);
00525
00526 if (retval)
00527 {
00528 if (old_free_func)
00529 (* old_free_func) (old_data);
00530 }
00531
00532 CONNECTION_LOCK (pending->connection);
00533
00534 return retval;
00535 }
00536
00583 DBusPendingCall *
00584 dbus_pending_call_ref (DBusPendingCall *pending)
00585 {
00586 dbus_int32_t old_refcount;
00587
00588 _dbus_return_val_if_fail (pending != NULL, NULL);
00589
00590 old_refcount = _dbus_atomic_inc (&pending->refcount);
00591 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
00592 "ref");
00593
00594 return pending;
00595 }
00596
00603 void
00604 dbus_pending_call_unref (DBusPendingCall *pending)
00605 {
00606 dbus_int32_t old_refcount;
00607
00608 _dbus_return_if_fail (pending != NULL);
00609
00610 old_refcount = _dbus_atomic_dec (&pending->refcount);
00611 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1,
00612 "unref");
00613
00614 if (old_refcount == 1)
00615 _dbus_pending_call_last_unref(pending);
00616 }
00617
00628 dbus_bool_t
00629 dbus_pending_call_set_notify (DBusPendingCall *pending,
00630 DBusPendingCallNotifyFunction function,
00631 void *user_data,
00632 DBusFreeFunction free_user_data)
00633 {
00634 dbus_bool_t ret = FALSE;
00635
00636 _dbus_return_val_if_fail (pending != NULL, FALSE);
00637
00638 CONNECTION_LOCK (pending->connection);
00639
00640
00641 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
00642 user_data, free_user_data))
00643 goto out;
00644
00645 pending->function = function;
00646 ret = TRUE;
00647
00648 out:
00649 CONNECTION_UNLOCK (pending->connection);
00650
00651 return ret;
00652 }
00653
00669 void
00670 dbus_pending_call_cancel (DBusPendingCall *pending)
00671 {
00672 _dbus_return_if_fail (pending != NULL);
00673
00674 _dbus_connection_remove_pending_call (pending->connection,
00675 pending);
00676 }
00677
00685 dbus_bool_t
00686 dbus_pending_call_get_completed (DBusPendingCall *pending)
00687 {
00688 dbus_bool_t completed;
00689
00690 _dbus_return_val_if_fail (pending != NULL, FALSE);
00691
00692 CONNECTION_LOCK (pending->connection);
00693 completed = pending->completed;
00694 CONNECTION_UNLOCK (pending->connection);
00695
00696 return completed;
00697 }
00698
00708 DBusMessage*
00709 dbus_pending_call_steal_reply (DBusPendingCall *pending)
00710 {
00711 DBusMessage *message;
00712
00713 _dbus_return_val_if_fail (pending != NULL, NULL);
00714 _dbus_return_val_if_fail (pending->completed, NULL);
00715 _dbus_return_val_if_fail (pending->reply != NULL, NULL);
00716
00717 CONNECTION_LOCK (pending->connection);
00718
00719 message = pending->reply;
00720 pending->reply = NULL;
00721
00722 CONNECTION_UNLOCK (pending->connection);
00723
00724 _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply");
00725 return message;
00726 }
00727
00743 void
00744 dbus_pending_call_block (DBusPendingCall *pending)
00745 {
00746 _dbus_return_if_fail (pending != NULL);
00747
00748 _dbus_connection_block_pending_call (pending);
00749 }
00750
00765 dbus_bool_t
00766 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
00767 {
00768 _dbus_return_val_if_fail (slot_p != NULL, FALSE);
00769
00770 return _dbus_data_slot_allocator_alloc (&slot_allocator,
00771 &_DBUS_LOCK_NAME (pending_call_slots),
00772 slot_p);
00773 }
00774
00786 void
00787 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
00788 {
00789 _dbus_return_if_fail (slot_p != NULL);
00790 _dbus_return_if_fail (*slot_p >= 0);
00791
00792 _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00793 }
00794
00808 dbus_bool_t
00809 dbus_pending_call_set_data (DBusPendingCall *pending,
00810 dbus_int32_t slot,
00811 void *data,
00812 DBusFreeFunction free_data_func)
00813 {
00814 dbus_bool_t retval;
00815
00816 _dbus_return_val_if_fail (pending != NULL, FALSE);
00817 _dbus_return_val_if_fail (slot >= 0, FALSE);
00818
00819
00820 CONNECTION_LOCK (pending->connection);
00821 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
00822 CONNECTION_UNLOCK (pending->connection);
00823 return retval;
00824 }
00825
00834 void*
00835 dbus_pending_call_get_data (DBusPendingCall *pending,
00836 dbus_int32_t slot)
00837 {
00838 void *res;
00839
00840 _dbus_return_val_if_fail (pending != NULL, NULL);
00841
00842 CONNECTION_LOCK (pending->connection);
00843 res = _dbus_data_slot_list_get (&slot_allocator,
00844 &pending->slot_list,
00845 slot);
00846 CONNECTION_UNLOCK (pending->connection);
00847
00848 return res;
00849 }
00850