|
D-Bus
1.5.8
|
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 _dbus_atomic_inc (&pending->refcount); 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 /* it's OK to unref this, nothing that could have attached a callback 00357 * has ever seen it */ 00358 dbus_message_unref (reply); 00359 return FALSE; 00360 } 00361 00362 pending->timeout_link = reply_link; 00363 00364 _dbus_pending_call_set_reply_serial_unlocked (pending, serial); 00365 00366 return TRUE; 00367 } 00368 00376 DBusPendingCall * 00377 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending) 00378 { 00379 _dbus_atomic_inc (&pending->refcount); 00380 00381 return pending; 00382 } 00383 00384 00385 static void 00386 _dbus_pending_call_last_unref (DBusPendingCall *pending) 00387 { 00388 DBusConnection *connection; 00389 00390 /* If we get here, we should be already detached 00391 * from the connection, or never attached. 00392 */ 00393 _dbus_assert (!pending->timeout_added); 00394 00395 connection = pending->connection; 00396 00397 /* this assumes we aren't holding connection lock... */ 00398 _dbus_data_slot_list_free (&pending->slot_list); 00399 00400 if (pending->timeout != NULL) 00401 _dbus_timeout_unref (pending->timeout); 00402 00403 if (pending->timeout_link) 00404 { 00405 dbus_message_unref ((DBusMessage *)pending->timeout_link->data); 00406 _dbus_list_free_link (pending->timeout_link); 00407 pending->timeout_link = NULL; 00408 } 00409 00410 if (pending->reply) 00411 { 00412 dbus_message_unref (pending->reply); 00413 pending->reply = NULL; 00414 } 00415 00416 dbus_free (pending); 00417 00418 dbus_pending_call_free_data_slot (¬ify_user_data_slot); 00419 00420 /* connection lock should not be held. */ 00421 /* Free the connection last to avoid a weird state while 00422 * calling out to application code where the pending exists 00423 * but not the connection. 00424 */ 00425 dbus_connection_unref (connection); 00426 } 00427 00435 void 00436 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) 00437 { 00438 dbus_int32_t old_refcount; 00439 00440 old_refcount = _dbus_atomic_dec (&pending->refcount); 00441 _dbus_assert (old_refcount > 0); 00442 00443 CONNECTION_UNLOCK (pending->connection); 00444 00445 if (old_refcount == 1) 00446 _dbus_pending_call_last_unref (pending); 00447 } 00448 00456 dbus_bool_t 00457 _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending) 00458 { 00459 return pending->completed; 00460 } 00461 00462 static DBusDataSlotAllocator slot_allocator; 00463 _DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots); 00464 00478 dbus_bool_t 00479 _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, 00480 dbus_int32_t slot, 00481 void *data, 00482 DBusFreeFunction free_data_func) 00483 { 00484 DBusFreeFunction old_free_func; 00485 void *old_data; 00486 dbus_bool_t retval; 00487 00488 retval = _dbus_data_slot_list_set (&slot_allocator, 00489 &pending->slot_list, 00490 slot, data, free_data_func, 00491 &old_free_func, &old_data); 00492 00493 /* Drop locks to call out to app code */ 00494 CONNECTION_UNLOCK (pending->connection); 00495 00496 if (retval) 00497 { 00498 if (old_free_func) 00499 (* old_free_func) (old_data); 00500 } 00501 00502 CONNECTION_LOCK (pending->connection); 00503 00504 return retval; 00505 } 00506 00553 DBusPendingCall * 00554 dbus_pending_call_ref (DBusPendingCall *pending) 00555 { 00556 _dbus_return_val_if_fail (pending != NULL, NULL); 00557 00558 _dbus_atomic_inc (&pending->refcount); 00559 00560 return pending; 00561 } 00562 00569 void 00570 dbus_pending_call_unref (DBusPendingCall *pending) 00571 { 00572 dbus_bool_t last_unref; 00573 00574 _dbus_return_if_fail (pending != NULL); 00575 00576 last_unref = (_dbus_atomic_dec (&pending->refcount) == 1); 00577 00578 if (last_unref) 00579 _dbus_pending_call_last_unref(pending); 00580 } 00581 00592 dbus_bool_t 00593 dbus_pending_call_set_notify (DBusPendingCall *pending, 00594 DBusPendingCallNotifyFunction function, 00595 void *user_data, 00596 DBusFreeFunction free_user_data) 00597 { 00598 _dbus_return_val_if_fail (pending != NULL, FALSE); 00599 00600 CONNECTION_LOCK (pending->connection); 00601 00602 /* could invoke application code! */ 00603 if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot, 00604 user_data, free_user_data)) 00605 return FALSE; 00606 00607 pending->function = function; 00608 00609 CONNECTION_UNLOCK (pending->connection); 00610 00611 return TRUE; 00612 } 00613 00629 void 00630 dbus_pending_call_cancel (DBusPendingCall *pending) 00631 { 00632 _dbus_return_if_fail (pending != NULL); 00633 00634 _dbus_connection_remove_pending_call (pending->connection, 00635 pending); 00636 } 00637 00645 dbus_bool_t 00646 dbus_pending_call_get_completed (DBusPendingCall *pending) 00647 { 00648 dbus_bool_t completed; 00649 00650 _dbus_return_val_if_fail (pending != NULL, FALSE); 00651 00652 CONNECTION_LOCK (pending->connection); 00653 completed = pending->completed; 00654 CONNECTION_UNLOCK (pending->connection); 00655 00656 return completed; 00657 } 00658 00668 DBusMessage* 00669 dbus_pending_call_steal_reply (DBusPendingCall *pending) 00670 { 00671 DBusMessage *message; 00672 00673 _dbus_return_val_if_fail (pending != NULL, NULL); 00674 _dbus_return_val_if_fail (pending->completed, NULL); 00675 _dbus_return_val_if_fail (pending->reply != NULL, NULL); 00676 00677 CONNECTION_LOCK (pending->connection); 00678 00679 message = pending->reply; 00680 pending->reply = NULL; 00681 00682 CONNECTION_UNLOCK (pending->connection); 00683 00684 return message; 00685 } 00686 00702 void 00703 dbus_pending_call_block (DBusPendingCall *pending) 00704 { 00705 _dbus_return_if_fail (pending != NULL); 00706 00707 _dbus_connection_block_pending_call (pending); 00708 } 00709 00724 dbus_bool_t 00725 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) 00726 { 00727 _dbus_return_val_if_fail (slot_p != NULL, FALSE); 00728 00729 return _dbus_data_slot_allocator_alloc (&slot_allocator, 00730 &_DBUS_LOCK_NAME (pending_call_slots), 00731 slot_p); 00732 } 00733 00745 void 00746 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) 00747 { 00748 _dbus_return_if_fail (slot_p != NULL); 00749 _dbus_return_if_fail (*slot_p >= 0); 00750 00751 _dbus_data_slot_allocator_free (&slot_allocator, slot_p); 00752 } 00753 00767 dbus_bool_t 00768 dbus_pending_call_set_data (DBusPendingCall *pending, 00769 dbus_int32_t slot, 00770 void *data, 00771 DBusFreeFunction free_data_func) 00772 { 00773 dbus_bool_t retval; 00774 00775 _dbus_return_val_if_fail (pending != NULL, FALSE); 00776 _dbus_return_val_if_fail (slot >= 0, FALSE); 00777 00778 00779 CONNECTION_LOCK (pending->connection); 00780 retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func); 00781 CONNECTION_UNLOCK (pending->connection); 00782 return retval; 00783 } 00784 00793 void* 00794 dbus_pending_call_get_data (DBusPendingCall *pending, 00795 dbus_int32_t slot) 00796 { 00797 void *res; 00798 00799 _dbus_return_val_if_fail (pending != NULL, NULL); 00800 00801 CONNECTION_LOCK (pending->connection); 00802 res = _dbus_data_slot_list_get (&slot_allocator, 00803 &pending->slot_list, 00804 slot); 00805 CONNECTION_UNLOCK (pending->connection); 00806 00807 return res; 00808 } 00809
1.7.5.1