|
D-Bus 1.4.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-pending-call.c Object representing a call in progress. 00003 * 00004 * Copyright (C) 2002, 2003 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 00093 DBusPendingCall* 00094 _dbus_pending_call_new_unlocked (DBusConnection *connection, 00095 int timeout_milliseconds, 00096 DBusTimeoutHandler timeout_handler) 00097 { 00098 DBusPendingCall *pending; 00099 DBusTimeout *timeout; 00100 00101 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1); 00102 00103 if (timeout_milliseconds == -1) 00104 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; 00105 00106 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) 00107 return NULL; 00108 00109 pending = dbus_new0 (DBusPendingCall, 1); 00110 00111 if (pending == NULL) 00112 { 00113 dbus_pending_call_free_data_slot (¬ify_user_data_slot); 00114 return NULL; 00115 } 00116 00117 if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE) 00118 { 00119 timeout = _dbus_timeout_new (timeout_milliseconds, 00120 timeout_handler, 00121 pending, NULL); 00122 00123 if (timeout == NULL) 00124 { 00125 dbus_pending_call_free_data_slot (¬ify_user_data_slot); 00126 dbus_free (pending); 00127 return NULL; 00128 } 00129 00130 pending->timeout = timeout; 00131 } 00132 else 00133 { 00134 pending->timeout = NULL; 00135 } 00136 00137 pending->refcount.value = 1; 00138 pending->connection = connection; 00139 _dbus_connection_ref_unlocked (pending->connection); 00140 00141 _dbus_data_slot_list_init (&pending->slot_list); 00142 00143 return pending; 00144 } 00145 00154 void 00155 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending, 00156 DBusMessage *message) 00157 { 00158 if (message == NULL) 00159 { 00160 message = pending->timeout_link->data; 00161 _dbus_list_clear (&pending->timeout_link); 00162 } 00163 else 00164 dbus_message_ref (message); 00165 00166 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n", 00167 message, 00168 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? 00169 "method return" : 00170 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? 00171 "error" : "other type", 00172 pending->reply_serial); 00173 00174 _dbus_assert (pending->reply == NULL); 00175 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message)); 00176 pending->reply = message; 00177 } 00178 00186 void 00187 _dbus_pending_call_complete (DBusPendingCall *pending) 00188 { 00189 _dbus_assert (!pending->completed); 00190 00191 pending->completed = TRUE; 00192 00193 if (pending->function) 00194 { 00195 void *user_data; 00196 user_data = dbus_pending_call_get_data (pending, 00197 notify_user_data_slot); 00198 00199 (* pending->function) (pending, user_data); 00200 } 00201 } 00202 00210 void 00211 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, 00212 DBusConnection *connection) 00213 { 00214 _dbus_assert (connection == pending->connection); 00215 00216 if (pending->timeout_link) 00217 { 00218 _dbus_connection_queue_synthesized_message_link (connection, 00219 pending->timeout_link); 00220 pending->timeout_link = NULL; 00221 } 00222 } 00223 00230 dbus_bool_t 00231 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending) 00232 { 00233 _dbus_assert (pending != NULL); 00234 00235 return pending->timeout_added; 00236 } 00237 00238 00245 void 00246 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending, 00247 dbus_bool_t is_added) 00248 { 00249 _dbus_assert (pending != NULL); 00250 00251 pending->timeout_added = is_added; 00252 } 00253 00254 00261 DBusTimeout * 00262 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending) 00263 { 00264 _dbus_assert (pending != NULL); 00265 00266 return pending->timeout; 00267 } 00268 00275 dbus_uint32_t 00276 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending) 00277 { 00278 _dbus_assert (pending != NULL); 00279 00280 return pending->reply_serial; 00281 } 00282 00289 void 00290 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, 00291 dbus_uint32_t serial) 00292 { 00293 _dbus_assert (pending != NULL); 00294 _dbus_assert (pending->reply_serial == 0); 00295 00296 pending->reply_serial = serial; 00297 } 00298 00305 DBusConnection * 00306 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending) 00307 { 00308 _dbus_assert (pending != NULL); 00309 00310 CONNECTION_LOCK (pending->connection); 00311 return pending->connection; 00312 } 00313 00320 DBusConnection * 00321 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending) 00322 { 00323 _dbus_assert (pending != NULL); 00324 00325 return pending->connection; 00326 } 00327 00336 dbus_bool_t 00337 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, 00338 DBusMessage *message, 00339 dbus_uint32_t serial) 00340 { 00341 DBusList *reply_link; 00342 DBusMessage *reply; 00343 00344 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, 00345 "Did not receive a reply. Possible causes include: " 00346 "the remote application did not send a reply, " 00347 "the message bus security policy blocked the reply, " 00348 "the reply timeout expired, or " 00349 "the network connection was broken."); 00350 if (reply == NULL) 00351 return FALSE; 00352 00353 reply_link = _dbus_list_alloc_link (reply); 00354 if (reply_link == NULL) 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 pending->refcount.value += 1; 00378 00379 return pending; 00380 } 00381 00382 00383 static void 00384 _dbus_pending_call_last_unref (DBusPendingCall *pending) 00385 { 00386 DBusConnection *connection; 00387 00388 /* If we get here, we should be already detached 00389 * from the connection, or never attached. 00390 */ 00391 _dbus_assert (!pending->timeout_added); 00392 00393 connection = pending->connection; 00394 00395 /* this assumes we aren't holding connection lock... */ 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 /* connection lock should not be held. */ 00419 /* Free the connection last to avoid a weird state while 00420 * calling out to application code where the pending exists 00421 * but not the connection. 00422 */ 00423 dbus_connection_unref (connection); 00424 } 00425 00433 void 00434 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) 00435 { 00436 dbus_bool_t last_unref; 00437 00438 _dbus_assert (pending->refcount.value > 0); 00439 00440 pending->refcount.value -= 1; 00441 last_unref = pending->refcount.value == 0; 00442 00443 CONNECTION_UNLOCK (pending->connection); 00444 if (last_unref) 00445 _dbus_pending_call_last_unref (pending); 00446 } 00447 00455 dbus_bool_t 00456 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending) 00457 { 00458 return pending->completed; 00459 } 00460 00461 static DBusDataSlotAllocator slot_allocator; 00462 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots); 00463 00477 dbus_bool_t 00478 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, 00479 dbus_int32_t slot, 00480 void *data, 00481 DBusFreeFunction free_data_func) 00482 { 00483 DBusFreeFunction old_free_func; 00484 void *old_data; 00485 dbus_bool_t retval; 00486 00487 retval = _dbus_data_slot_list_set (&slot_allocator, 00488 &pending->slot_list, 00489 slot, data, free_data_func, 00490 &old_free_func, &old_data); 00491 00492 /* Drop locks to call out to app code */ 00493 CONNECTION_UNLOCK (pending->connection); 00494 00495 if (retval) 00496 { 00497 if (old_free_func) 00498 (* old_free_func) (old_data); 00499 } 00500 00501 CONNECTION_LOCK (pending->connection); 00502 00503 return retval; 00504 } 00505 00552 DBusPendingCall * 00553 dbus_pending_call_ref (DBusPendingCall *pending) 00554 { 00555 _dbus_return_val_if_fail (pending != NULL, NULL); 00556 00557 /* The connection lock is better than the global 00558 * lock in the atomic increment fallback 00559 */ 00560 #ifdef DBUS_HAVE_ATOMIC_INT 00561 _dbus_atomic_inc (&pending->refcount); 00562 #else 00563 CONNECTION_LOCK (pending->connection); 00564 _dbus_assert (pending->refcount.value > 0); 00565 00566 pending->refcount.value += 1; 00567 CONNECTION_UNLOCK (pending->connection); 00568 #endif 00569 00570 return pending; 00571 } 00572 00579 void 00580 dbus_pending_call_unref (DBusPendingCall *pending) 00581 { 00582 dbus_bool_t last_unref; 00583 00584 _dbus_return_if_fail (pending != NULL); 00585 00586 /* More efficient to use the connection lock instead of atomic 00587 * int fallback if we lack atomic int decrement 00588 */ 00589 #ifdef DBUS_HAVE_ATOMIC_INT 00590 last_unref = (_dbus_atomic_dec (&pending->refcount) == 1); 00591 #else 00592 CONNECTION_LOCK (pending->connection); 00593 _dbus_assert (pending->refcount.value > 0); 00594 pending->refcount.value -= 1; 00595 last_unref = pending->refcount.value == 0; 00596 CONNECTION_UNLOCK (pending->connection); 00597 #endif 00598 00599 if (last_unref) 00600 _dbus_pending_call_last_unref(pending); 00601 } 00602 00613 dbus_bool_t 00614 dbus_pending_call_set_notify (DBusPendingCall *pending, 00615 DBusPendingCallNotifyFunction function, 00616 void *user_data, 00617 DBusFreeFunction free_user_data) 00618 { 00619 _dbus_return_val_if_fail (pending != NULL, FALSE); 00620 00621 CONNECTION_LOCK (pending->connection); 00622 00623 /* could invoke application code! */ 00624 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot, 00625 user_data, free_user_data)) 00626 return FALSE; 00627 00628 pending->function = function; 00629 00630 CONNECTION_UNLOCK (pending->connection); 00631 00632 return TRUE; 00633 } 00634 00650 void 00651 dbus_pending_call_cancel (DBusPendingCall *pending) 00652 { 00653 _dbus_return_if_fail (pending != NULL); 00654 00655 _dbus_connection_remove_pending_call (pending->connection, 00656 pending); 00657 } 00658 00666 dbus_bool_t 00667 dbus_pending_call_get_completed (DBusPendingCall *pending) 00668 { 00669 dbus_bool_t completed; 00670 00671 _dbus_return_val_if_fail (pending != NULL, FALSE); 00672 00673 CONNECTION_LOCK (pending->connection); 00674 completed = pending->completed; 00675 CONNECTION_UNLOCK (pending->connection); 00676 00677 return completed; 00678 } 00679 00689 DBusMessage* 00690 dbus_pending_call_steal_reply (DBusPendingCall *pending) 00691 { 00692 DBusMessage *message; 00693 00694 _dbus_return_val_if_fail (pending != NULL, NULL); 00695 _dbus_return_val_if_fail (pending->completed, NULL); 00696 _dbus_return_val_if_fail (pending->reply != NULL, NULL); 00697 00698 CONNECTION_LOCK (pending->connection); 00699 00700 message = pending->reply; 00701 pending->reply = NULL; 00702 00703 CONNECTION_UNLOCK (pending->connection); 00704 00705 return message; 00706 } 00707 00723 void 00724 dbus_pending_call_block (DBusPendingCall *pending) 00725 { 00726 _dbus_return_if_fail (pending != NULL); 00727 00728 _dbus_connection_block_pending_call (pending); 00729 } 00730 00745 dbus_bool_t 00746 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) 00747 { 00748 _dbus_return_val_if_fail (slot_p != NULL, FALSE); 00749 00750 return _dbus_data_slot_allocator_alloc (&slot_allocator, 00751 &_DBUS_LOCK_NAME (pending_call_slots), 00752 slot_p); 00753 } 00754 00766 void 00767 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) 00768 { 00769 _dbus_return_if_fail (slot_p != NULL); 00770 _dbus_return_if_fail (*slot_p >= 0); 00771 00772 _dbus_data_slot_allocator_free (&slot_allocator, slot_p); 00773 } 00774 00788 dbus_bool_t 00789 dbus_pending_call_set_data (DBusPendingCall *pending, 00790 dbus_int32_t slot, 00791 void *data, 00792 DBusFreeFunction free_data_func) 00793 { 00794 dbus_bool_t retval; 00795 00796 _dbus_return_val_if_fail (pending != NULL, FALSE); 00797 _dbus_return_val_if_fail (slot >= 0, FALSE); 00798 00799 00800 CONNECTION_LOCK (pending->connection); 00801 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func); 00802 CONNECTION_UNLOCK (pending->connection); 00803 return retval; 00804 } 00805 00814 void* 00815 dbus_pending_call_get_data (DBusPendingCall *pending, 00816 dbus_int32_t slot) 00817 { 00818 void *res; 00819 00820 _dbus_return_val_if_fail (pending != NULL, NULL); 00821 00822 CONNECTION_LOCK (pending->connection); 00823 res = _dbus_data_slot_list_get (&slot_allocator, 00824 &pending->slot_list, 00825 slot); 00826 CONNECTION_UNLOCK (pending->connection); 00827 00828 return res; 00829 } 00830 00833 #ifdef DBUS_BUILD_TESTS 00834 00841 dbus_bool_t 00842 _dbus_pending_call_test (const char *test_data_dir) 00843 { 00844 00845 return TRUE; 00846 } 00847 #endif /* DBUS_BUILD_TESTS */
1.7.4