X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbind%2Fdbind.c;h=e154f8571a3a8c79f646c1b497cd841a52e79130;hb=3785cfb93aa4a29b70ffdd39686f14d2c8e26b0b;hp=5c49d66591de6a65c71096c7f4950f0a247d1f4e;hpb=11d647c36278e2430df5df0c56546e267971e74a;p=platform%2Fupstream%2Fat-spi2-core.git diff --git a/dbind/dbind.c b/dbind/dbind.c index 5c49d66..e154f85 100644 --- a/dbind/dbind.c +++ b/dbind/dbind.c @@ -1,11 +1,33 @@ - +/* + * Copyright 2008-2011 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include #include +#include +#include #include #include "config.h" #include "dbind/dbind.h" +#include "atspi/atspi-gmain.h" + +static int dbind_timeout = -1; /* * FIXME: compare types - to ensure they match & @@ -14,30 +36,90 @@ /*---------------------------------------------------------------------------*/ +typedef struct _SpiReentrantCallClosure +{ + DBusMessage *reply; +} SpiReentrantCallClosure; + static void -set_reply (DBusPendingCall *pending, void *user_data) +set_reply (DBusPendingCall * pending, void *user_data) { - void **replyptr = (void **)user_data; + SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data; - *replyptr = dbus_pending_call_steal_reply (pending); + closure->reply = dbus_pending_call_steal_reply (pending); + dbus_pending_call_unref (pending); +} + +static gint +time_elapsed (struct timeval *origin) +{ + struct timeval tv; + + gettimeofday (&tv, NULL); + return (tv.tv_sec - origin->tv_sec) * 1000 + (tv.tv_usec - origin->tv_usec) / 1000; } DBusMessage * -dbind_send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, DBusError *error) +dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusError *error) { - DBusPendingCall *pending; - DBusMessage *reply = NULL; + DBusPendingCall *pending; + SpiReentrantCallClosure *closure; + const char *unique_name = dbus_bus_get_unique_name (bus); + const char *destination = dbus_message_get_destination (message); + struct timeval tv; + DBusMessage *ret; + static gboolean in_dispatch = FALSE; + + if (unique_name && destination && + strcmp (destination, unique_name) != 0) + { + ret = dbus_connection_send_with_reply_and_block (bus, message, + dbind_timeout, error); + if (g_main_depth () == 0 && !in_dispatch) + { + in_dispatch = TRUE; + while (dbus_connection_dispatch (bus) == DBUS_DISPATCH_DATA_REMAINS); + in_dispatch = FALSE; + } + return ret; + } - if (!dbus_connection_send_with_reply (bus, message, &pending, -1)) + closure = g_new0 (SpiReentrantCallClosure, 1); + closure->reply = NULL; + if (!dbus_connection_send_with_reply (bus, message, &pending, dbind_timeout) + || !pending) { - return NULL; + g_free (closure); + return NULL; } - dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL); - while (!reply) + dbus_pending_call_set_notify (pending, set_reply, (void *) closure, g_free); + + closure->reply = NULL; + gettimeofday (&tv, NULL); + dbus_pending_call_ref (pending); + while (!closure->reply) { - if (!dbus_connection_read_write_dispatch (bus, -1)) return NULL; + if (!dbus_connection_read_write_dispatch (bus, dbind_timeout)) + { + //dbus_pending_call_set_notify (pending, NULL, NULL, NULL); + dbus_pending_call_cancel (pending); + dbus_pending_call_unref (pending); + return NULL; + } + if (time_elapsed (&tv) > dbind_timeout) + { + //dbus_pending_call_set_notify (pending, NULL, NULL, NULL); + dbus_pending_call_cancel (pending); + dbus_pending_call_unref (pending); + dbus_set_error_const (error, "org.freedesktop.DBus.Error.NoReply", + "timeout from dbind"); + return NULL; + } } - return reply; + + ret = closure->reply; + dbus_pending_call_unref (pending); + return ret; } dbus_bool_t @@ -55,11 +137,14 @@ dbind_method_call_reentrant_va (DBusConnection *cnx, DBusMessageIter iter; DBusError *err, real_err; const char *p; + va_list args_demarshal; + dbus_error_init (&real_err); + + va_copy (args_demarshal, args); if (opt_error) err = opt_error; else { - dbus_error_init (&real_err); err = &real_err; } @@ -77,17 +162,26 @@ dbind_method_call_reentrant_va (DBusConnection *cnx, if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { - const char *name = dbus_message_get_error_name (reply); - dbus_set_error (err, name, g_strdup ("")); goto out; } /* demarshal */ if (p[0] == '=' && p[1] == '>') { DBusMessageIter iter; - p += 2; dbus_message_iter_init (reply, &iter); - dbind_any_demarshal_va (&iter, &p, args); + if (strcmp (p + 2, dbus_message_get_signature (reply)) != 0) + { + g_warning ("dbind: Call to \"%s\" returned signature %s; expected %s", + method, dbus_message_get_signature (reply), p + 2); + if (opt_error) + dbus_set_error (opt_error, DBUS_ERROR_INVALID_ARGS, + "Call to \"%s\" returned signature %s; expected %s", + method, dbus_message_get_signature (reply), + p + 2); + goto out; + } + p = arg_types; + dbind_any_demarshal_va (&iter, &p, args_demarshal); } success = TRUE; @@ -98,9 +192,10 @@ out: if (reply) dbus_message_unref (reply); - if (err == &real_err) - dbus_error_free (err); + if (dbus_error_is_set (&real_err)) + dbus_error_free (&real_err); + va_end (args_demarshal); return success; } @@ -150,6 +245,7 @@ dbind_method_call_reentrant (DBusConnection *cnx, /*---------------------------------------------------------------------------*/ +/* TODO: opt_error is unused; should be removed */ dbus_bool_t dbind_emit_signal_va (DBusConnection *cnx, const char *path, @@ -162,16 +258,8 @@ dbind_emit_signal_va (DBusConnection *cnx, dbus_bool_t success = FALSE; DBusMessage *msg = NULL; DBusMessageIter iter; - DBusError *err, real_err; const char *p; - if (opt_error) - err = opt_error; - else { - dbus_error_init (&real_err); - err = &real_err; - } - msg = dbus_message_new_signal (path, interface, signal); if (!msg) goto out; @@ -189,9 +277,6 @@ out: if (msg) dbus_message_unref (msg); - if (err == &real_err) - dbus_error_free (err); - return success; } @@ -226,5 +311,11 @@ dbind_emit_signal (DBusConnection *cnx, return success; } +void +dbind_set_timeout (int timeout) +{ + dbind_timeout = timeout; +} + /*END------------------------------------------------------------------------*/