D-Bus
1.10.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-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 static void 00083 _dbus_pending_call_trace_ref (DBusPendingCall *pending_call, 00084 int old_refcount, 00085 int new_refcount, 00086 const char *why) 00087 { 00088 #ifdef DBUS_ENABLE_VERBOSE_MODE 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 #endif 00094 } 00095 00096 static dbus_int32_t notify_user_data_slot = -1; 00097 00108 DBusPendingCall* 00109 _dbus_pending_call_new_unlocked (DBusConnection *connection, 00110 int timeout_milliseconds, 00111 DBusTimeoutHandler timeout_handler) 00112 { 00113 DBusPendingCall *pending; 00114 DBusTimeout *timeout; 00115 00116 _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1); 00117 00118 if (timeout_milliseconds == -1) 00119 timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; 00120 00121 if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) 00122 return NULL; 00123 00124 pending = dbus_new0 (DBusPendingCall, 1); 00125 00126 if (pending == NULL) 00127 { 00128 dbus_pending_call_free_data_slot (¬ify_user_data_slot); 00129 return NULL; 00130 } 00131 00132 if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE) 00133 { 00134 timeout = _dbus_timeout_new (timeout_milliseconds, 00135 timeout_handler, 00136 pending, NULL); 00137 00138 if (timeout == NULL) 00139 { 00140 dbus_pending_call_free_data_slot (¬ify_user_data_slot); 00141 dbus_free (pending); 00142 return NULL; 00143 } 00144 00145 pending->timeout = timeout; 00146 } 00147 else 00148 { 00149 pending->timeout = NULL; 00150 } 00151 00152 _dbus_atomic_inc (&pending->refcount); 00153 pending->connection = connection; 00154 _dbus_connection_ref_unlocked (pending->connection); 00155 00156 _dbus_data_slot_list_init (&pending->slot_list); 00157 00158 _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked"); 00159 00160 return pending; 00161 } 00162 00171 void 00172 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending, 00173 DBusMessage *message) 00174 { 00175 if (message == NULL) 00176 { 00177 message = pending->timeout_link->data; 00178 _dbus_list_clear (&pending->timeout_link); 00179 } 00180 else 00181 dbus_message_ref (message); 00182 00183 _dbus_verbose (" handing message %p (%s) to pending call serial %u\n", 00184 message, 00185 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? 00186 "method return" : 00187 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? 00188 "error" : "other type", 00189 pending->reply_serial); 00190 00191 _dbus_assert (pending->reply == NULL); 00192 _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message)); 00193 pending->reply = message; 00194 } 00195 00203 void 00204 _dbus_pending_call_complete (DBusPendingCall *pending) 00205 { 00206 _dbus_assert (!pending->completed); 00207 00208 pending->completed = TRUE; 00209 00210 if (pending->function) 00211 { 00212 void *user_data; 00213 user_data = dbus_pending_call_get_data (pending, 00214 notify_user_data_slot); 00215 00216 (* pending->function) (pending, user_data); 00217 } 00218 } 00219 00227 void 00228 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, 00229 DBusConnection *connection) 00230 { 00231 _dbus_assert (connection == pending->connection); 00232 00233 if (pending->timeout_link) 00234 { 00235 _dbus_connection_queue_synthesized_message_link (connection, 00236 pending->timeout_link); 00237 pending->timeout_link = NULL; 00238 } 00239 } 00240 00247 dbus_bool_t 00248 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending) 00249 { 00250 _dbus_assert (pending != NULL); 00251 00252 return pending->timeout_added; 00253 } 00254 00255 00262 void 00263 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending, 00264 dbus_bool_t is_added) 00265 { 00266 _dbus_assert (pending != NULL); 00267 00268 pending->timeout_added = is_added; 00269 } 00270 00271 00278 DBusTimeout * 00279 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending) 00280 { 00281 _dbus_assert (pending != NULL); 00282 00283 return pending->timeout; 00284 } 00285 00292 dbus_uint32_t 00293 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending) 00294 { 00295 _dbus_assert (pending != NULL); 00296 00297 return pending->reply_serial; 00298 } 00299 00306 void 00307 _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, 00308 dbus_uint32_t serial) 00309 { 00310 _dbus_assert (pending != NULL); 00311 _dbus_assert (pending->reply_serial == 0); 00312 00313 pending->reply_serial = serial; 00314 } 00315 00322 DBusConnection * 00323 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending) 00324 { 00325 _dbus_assert (pending != NULL); 00326 00327 CONNECTION_LOCK (pending->connection); 00328 return pending->connection; 00329 } 00330 00337 DBusConnection * 00338 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending) 00339 { 00340 _dbus_assert (pending != NULL); 00341 00342 return pending->connection; 00343 } 00344 00353 dbus_bool_t 00354 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, 00355 DBusMessage *message, 00356 dbus_uint32_t serial) 00357 { 00358 DBusList *reply_link; 00359 DBusMessage *reply; 00360 00361 reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, 00362 "Did not receive a reply. Possible causes include: " 00363 "the remote application did not send a reply, " 00364 "the message bus security policy blocked the reply, " 00365 "the reply timeout expired, or " 00366 "the network connection was broken."); 00367 if (reply == NULL) 00368 return FALSE; 00369 00370 reply_link = _dbus_list_alloc_link (reply); 00371 if (reply_link == NULL) 00372 { 00373 /* it's OK to unref this, nothing that could have attached a callback 00374 * has ever seen it */ 00375 dbus_message_unref (reply); 00376 return FALSE; 00377 } 00378 00379 pending->timeout_link = reply_link; 00380 00381 _dbus_pending_call_set_reply_serial_unlocked (pending, serial); 00382 00383 return TRUE; 00384 } 00385 00393 DBusPendingCall * 00394 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending) 00395 { 00396 dbus_int32_t old_refcount; 00397 00398 old_refcount = _dbus_atomic_inc (&pending->refcount); 00399 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1, 00400 "ref_unlocked"); 00401 00402 return pending; 00403 } 00404 00405 00406 static void 00407 _dbus_pending_call_last_unref (DBusPendingCall *pending) 00408 { 00409 DBusConnection *connection; 00410 00411 /* If we get here, we should be already detached 00412 * from the connection, or never attached. 00413 */ 00414 _dbus_assert (!pending->timeout_added); 00415 00416 connection = pending->connection; 00417 00418 /* this assumes we aren't holding connection lock... */ 00419 _dbus_data_slot_list_free (&pending->slot_list); 00420 00421 if (pending->timeout != NULL) 00422 _dbus_timeout_unref (pending->timeout); 00423 00424 if (pending->timeout_link) 00425 { 00426 dbus_message_unref ((DBusMessage *)pending->timeout_link->data); 00427 _dbus_list_free_link (pending->timeout_link); 00428 pending->timeout_link = NULL; 00429 } 00430 00431 if (pending->reply) 00432 { 00433 dbus_message_unref (pending->reply); 00434 pending->reply = NULL; 00435 } 00436 00437 dbus_free (pending); 00438 00439 dbus_pending_call_free_data_slot (¬ify_user_data_slot); 00440 00441 /* connection lock should not be held. */ 00442 /* Free the connection last to avoid a weird state while 00443 * calling out to application code where the pending exists 00444 * but not the connection. 00445 */ 00446 dbus_connection_unref (connection); 00447 } 00448 00456 void 00457 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) 00458 { 00459 dbus_int32_t old_refcount; 00460 00461 old_refcount = _dbus_atomic_dec (&pending->refcount); 00462 _dbus_assert (old_refcount > 0); 00463 _dbus_pending_call_trace_ref (pending, old_refcount, 00464 old_refcount - 1, "unref_and_unlock"); 00465 00466 CONNECTION_UNLOCK (pending->connection); 00467 00468 if (old_refcount == 1) 00469 _dbus_pending_call_last_unref (pending); 00470 } 00471 00479 dbus_bool_t 00480 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending) 00481 { 00482 return pending->completed; 00483 } 00484 00485 static DBusDataSlotAllocator slot_allocator = 00486 _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (pending_call_slots)); 00487 00501 dbus_bool_t 00502 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, 00503 dbus_int32_t slot, 00504 void *data, 00505 DBusFreeFunction free_data_func) 00506 { 00507 DBusFreeFunction old_free_func; 00508 void *old_data; 00509 dbus_bool_t retval; 00510 00511 retval = _dbus_data_slot_list_set (&slot_allocator, 00512 &pending->slot_list, 00513 slot, data, free_data_func, 00514 &old_free_func, &old_data); 00515 00516 /* Drop locks to call out to app code */ 00517 CONNECTION_UNLOCK (pending->connection); 00518 00519 if (retval) 00520 { 00521 if (old_free_func) 00522 (* old_free_func) (old_data); 00523 } 00524 00525 CONNECTION_LOCK (pending->connection); 00526 00527 return retval; 00528 } 00529 00576 DBusPendingCall * 00577 dbus_pending_call_ref (DBusPendingCall *pending) 00578 { 00579 dbus_int32_t old_refcount; 00580 00581 _dbus_return_val_if_fail (pending != NULL, NULL); 00582 00583 old_refcount = _dbus_atomic_inc (&pending->refcount); 00584 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1, 00585 "ref"); 00586 00587 return pending; 00588 } 00589 00596 void 00597 dbus_pending_call_unref (DBusPendingCall *pending) 00598 { 00599 dbus_int32_t old_refcount; 00600 00601 _dbus_return_if_fail (pending != NULL); 00602 00603 old_refcount = _dbus_atomic_dec (&pending->refcount); 00604 _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1, 00605 "unref"); 00606 00607 if (old_refcount == 1) 00608 _dbus_pending_call_last_unref(pending); 00609 } 00610 00621 dbus_bool_t 00622 dbus_pending_call_set_notify (DBusPendingCall *pending, 00623 DBusPendingCallNotifyFunction function, 00624 void *user_data, 00625 DBusFreeFunction free_user_data) 00626 { 00627 dbus_bool_t ret = FALSE; 00628 00629 _dbus_return_val_if_fail (pending != NULL, FALSE); 00630 00631 CONNECTION_LOCK (pending->connection); 00632 00633 /* could invoke application code! */ 00634 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot, 00635 user_data, free_user_data)) 00636 goto out; 00637 00638 pending->function = function; 00639 ret = TRUE; 00640 00641 out: 00642 CONNECTION_UNLOCK (pending->connection); 00643 00644 return ret; 00645 } 00646 00662 void 00663 dbus_pending_call_cancel (DBusPendingCall *pending) 00664 { 00665 _dbus_return_if_fail (pending != NULL); 00666 00667 _dbus_connection_remove_pending_call (pending->connection, 00668 pending); 00669 } 00670 00678 dbus_bool_t 00679 dbus_pending_call_get_completed (DBusPendingCall *pending) 00680 { 00681 dbus_bool_t completed; 00682 00683 _dbus_return_val_if_fail (pending != NULL, FALSE); 00684 00685 CONNECTION_LOCK (pending->connection); 00686 completed = pending->completed; 00687 CONNECTION_UNLOCK (pending->connection); 00688 00689 return completed; 00690 } 00691 00701 DBusMessage* 00702 dbus_pending_call_steal_reply (DBusPendingCall *pending) 00703 { 00704 DBusMessage *message; 00705 00706 _dbus_return_val_if_fail (pending != NULL, NULL); 00707 _dbus_return_val_if_fail (pending->completed, NULL); 00708 _dbus_return_val_if_fail (pending->reply != NULL, NULL); 00709 00710 CONNECTION_LOCK (pending->connection); 00711 00712 message = pending->reply; 00713 pending->reply = NULL; 00714 00715 CONNECTION_UNLOCK (pending->connection); 00716 00717 _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply"); 00718 return message; 00719 } 00720 00736 void 00737 dbus_pending_call_block (DBusPendingCall *pending) 00738 { 00739 _dbus_return_if_fail (pending != NULL); 00740 00741 _dbus_connection_block_pending_call (pending); 00742 } 00743 00758 dbus_bool_t 00759 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) 00760 { 00761 _dbus_return_val_if_fail (slot_p != NULL, FALSE); 00762 00763 return _dbus_data_slot_allocator_alloc (&slot_allocator, 00764 slot_p); 00765 } 00766 00778 void 00779 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) 00780 { 00781 _dbus_return_if_fail (slot_p != NULL); 00782 _dbus_return_if_fail (*slot_p >= 0); 00783 00784 _dbus_data_slot_allocator_free (&slot_allocator, slot_p); 00785 } 00786 00800 dbus_bool_t 00801 dbus_pending_call_set_data (DBusPendingCall *pending, 00802 dbus_int32_t slot, 00803 void *data, 00804 DBusFreeFunction free_data_func) 00805 { 00806 dbus_bool_t retval; 00807 00808 _dbus_return_val_if_fail (pending != NULL, FALSE); 00809 _dbus_return_val_if_fail (slot >= 0, FALSE); 00810 00811 00812 CONNECTION_LOCK (pending->connection); 00813 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func); 00814 CONNECTION_UNLOCK (pending->connection); 00815 return retval; 00816 } 00817 00826 void* 00827 dbus_pending_call_get_data (DBusPendingCall *pending, 00828 dbus_int32_t slot) 00829 { 00830 void *res; 00831 00832 _dbus_return_val_if_fail (pending != NULL, NULL); 00833 00834 CONNECTION_LOCK (pending->connection); 00835 res = _dbus_data_slot_list_get (&slot_allocator, 00836 &pending->slot_list, 00837 slot); 00838 CONNECTION_UNLOCK (pending->connection); 00839 00840 return res; 00841 } 00842