D-Bus 1.2.24
|
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 "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 /* If we get here, we should be already detached 00386 * from the connection, or never attached. 00387 */ 00388 _dbus_assert (!pending->timeout_added); 00389 00390 connection = pending->connection; 00391 00392 /* this assumes we aren't holding connection lock... */ 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 /* connection lock should not be held. */ 00416 /* Free the connection last to avoid a weird state while 00417 * calling out to application code where the pending exists 00418 * but not the connection. 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 /* Drop locks to call out to app code */ 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 /* The connection lock is better than the global 00535 * lock in the atomic increment fallback 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 /* More efficient to use the connection lock instead of atomic 00564 * int fallback if we lack atomic int decrement 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 /* could invoke application code! */ 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 /* DBUS_BUILD_TESTS */