From a686b55be31cc26c11d57c54a6439f3c97eb4602 Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Thu, 16 Jul 2009 10:39:36 -0400 Subject: [PATCH] Bug 18972 - Support threaded asynchronous calls Introduce support for a new org.freedesktop.DBus.GLib.Thread annotation which means that the server handler will be run in a new thread. Inside the core invoke_object_method function, move output argument handling to add_output_arguments. Signed-off-by: Colin Walters --- dbus/Makefile.am | 4 +- dbus/dbus-binding-tool-glib.c | 16 ++- dbus/dbus-binding-tool-glib.h | 1 + dbus/dbus-gobject.c | 452 ++++++++++++++++++++++++++++++--------- test/core/my-object.c | 19 ++ test/core/my-object.h | 4 + test/core/test-dbus-glib.c | 57 +++++- test/core/test-service-glib.xml | 18 ++ 8 files changed, 466 insertions(+), 105 deletions(-) diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 02ef3a3..473219f 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -32,7 +32,9 @@ DBUS_GLIB_INTERNALS = \ dbus-gsignature.h \ dbus-gvalue.h \ dbus-gvalue-utils.c \ - dbus-gvalue-utils.h + dbus-gvalue-utils.h \ + dbus-gasync.c \ + dbus-gasync.h libdbus_glib_1_la_SOURCES = \ dbus-glib-error-switch.h \ diff --git a/dbus/dbus-binding-tool-glib.c b/dbus/dbus-binding-tool-glib.c index e7c4a46..e224e14 100644 --- a/dbus/dbus-binding-tool-glib.c +++ b/dbus/dbus-binding-tool-glib.c @@ -140,10 +140,20 @@ compute_gsignature (MethodInfo *method, GType *rettype, GArray **params, GError GType retval_type; GArray *ret; gboolean is_async; + gboolean is_thread; const char *arg_type; gboolean retval_signals_error; is_async = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL; + is_thread = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_THREAD) != NULL; + if (is_async && is_thread) + { + g_set_error (error, + DBUS_BINDING_TOOL_ERROR, + DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION, + "Asynchronous methods can not be threaded"); + return FALSE; + } retval_signals_error = FALSE; ret = g_array_new (TRUE, TRUE, sizeof (GType)); @@ -562,6 +572,7 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) char *marshaller_name; char *method_c_name; gboolean async = FALSE; + gboolean thread = FALSE; GSList *args; gboolean found_retval = FALSE; @@ -596,6 +607,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) async = TRUE; + if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_THREAD) != NULL) + thread = TRUE; + /* Object method data blob format: * \0\0(\0\0\0)*\0 */ @@ -606,7 +620,7 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) g_string_append (object_introspection_data_blob, method_info_get_name (method)); g_string_append_c (object_introspection_data_blob, '\0'); - g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S'); + g_string_append_c (object_introspection_data_blob, async ? 'A' : (thread ? 'T' : 'S')); g_string_append_c (object_introspection_data_blob, '\0'); for (args = method_info_get_args (method); args; args = args->next) diff --git a/dbus/dbus-binding-tool-glib.h b/dbus/dbus-binding-tool-glib.h index 7a2f0e9..71c823d 100644 --- a/dbus/dbus-binding-tool-glib.h +++ b/dbus/dbus-binding-tool-glib.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS #define DBUS_GLIB_ANNOTATION_C_SYMBOL "org.freedesktop.DBus.GLib.CSymbol" #define DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL "org.freedesktop.DBus.GLib.ClientCSymbol" +#define DBUS_GLIB_ANNOTATION_THREAD "org.freedesktop.DBus.GLib.Thread" #define DBUS_GLIB_ANNOTATION_ASYNC "org.freedesktop.DBus.GLib.Async" #define DBUS_GLIB_ANNOTATION_CONST "org.freedesktop.DBus.GLib.Const" #define DBUS_GLIB_ANNOTATION_RETURNVAL "org.freedesktop.DBus.GLib.ReturnVal" diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c index 2c56a8f..7bec6a7 100644 --- a/dbus/dbus-gobject.c +++ b/dbus/dbus-gobject.c @@ -33,14 +33,23 @@ #include "dbus-gvalue.h" #include "dbus-gmarshal.h" #include "dbus-gvalue-utils.h" +#include "dbus-gasync.h" #include +typedef enum { + SYNCHRONOUS, + SYNCHRONOUS_THREADED, + ASYNCHRONOUS +} GMethodCallType; + typedef struct { char *default_iface; GType code_enum; } DBusGErrorInfo; +typedef struct _DBusGSyncThreadedData DBusGSyncThreadedData; + static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT; static GHashTable *marshal_table = NULL; static GData *error_metadata = NULL; @@ -1210,6 +1219,160 @@ struct _DBusGMethodInvocation { gboolean send_reply; }; +/** + * The data provided to the callback function which calls synchronous + * threaded dbus methods + */ +struct _DBusGSyncThreadedData { + const DBusGMethodInfo *method; + GClosure *closure; + GValueArray *value_array; + GArray *out_param_values; + GValueArray *out_param_gvalues; +}; + +static gboolean +add_output_arguments (DBusMessageIter *iter, + const DBusGObjectInfo *object_info, + const DBusGMethodInfo *method, + GArray *out_param_values, + GValueArray *out_param_gvalues); + +/** + * Creates a return message for a given method invocation, with arguments. + * The arguments are the elements in the value array. + */ +static DBusMessage* +method_create_response (DBusGMethodInvocation *context, + GArray *out_param_values, + GValueArray *out_param_gvalues) +{ + DBusMessage *reply; + DBusMessageIter iter; + + reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message)); + if (!reply) + { + g_error ("Out of memory"); + return NULL; + } + + dbus_message_iter_init_append (reply, &iter); + + if (!add_output_arguments (&iter, + context->object, + context->method, + out_param_values, + out_param_gvalues)) + { + g_error ("Out of memory"); + dbus_message_unref (reply); + return NULL; + } + + return reply; +} + +/** + * This function is called in a thread and invokes regular synchronous + * dbus method. + * + * The context which is supposed to be the last element in the value_array + * is used for sending dbus messages. Messages are sent using the + * dbus_g_method_send_reply() function which also unrefs the context. + * + * This function will free all the three arrays used for sending/getting + * arguments: value_array, out_param_values and out_param_gvalues. + * + * Note that the dbus method called by the marshaller is a regular syncronous + * method so the context is hidden from it! + */ +static void +invoke_marshaller_threaded (gpointer data) +{ + GError *error = NULL; + guint last_element; + DBusGMethodInvocation *context; + GValue return_value = {0,}; + DBusMessage *reply = NULL; + DBusGSyncThreadedData *method_data; + gboolean send_reply; + + method_data = (DBusGSyncThreadedData *)data; + + g_assert (method_data != NULL); + + const DBusGMethodInfo *method = method_data->method; + GClosure *closure = method_data->closure; + GValueArray *value_array = method_data->value_array; + GArray *out_param_values = method_data->out_param_values; + GValueArray *out_param_gvalues = method_data->out_param_gvalues; + + g_assert (method != NULL); + g_assert (closure != NULL); + g_assert (value_array != NULL); + g_assert (out_param_values != NULL); + g_assert (out_param_gvalues != NULL); + + /* + * Init return_value, it is needed by the marshaller function + * if the dbus function(the one described in the xml file) is not void + * Actually its value is never considered, perhaps that should + * be fixed? + */ + g_value_init (&return_value, G_TYPE_BOOLEAN); + + /* Get the index of the last element in the value_array */ + last_element = value_array->n_values - 1; + + /* Get the context */ + context = g_value_get_pointer (value_array->values + last_element); + g_assert (context != NULL); + + /* + * This field was initialized inside invoke_object_method; we + * carry it over through the sync threaded invocation to here. + */ + send_reply = context->send_reply; + + /* Remove the context and add the error instead */ + g_value_unset (g_value_array_get_nth (value_array, last_element)); + g_value_init (g_value_array_get_nth (value_array, last_element), G_TYPE_POINTER); + g_value_set_pointer (g_value_array_get_nth (value_array, last_element), &error); + + /* Invoke marshaller */ + method->marshaller (closure, + &return_value, + value_array->n_values, + value_array->values, + NULL, + method->function); + + /* Return a message with arguments or error */ + if (error) + { + if (send_reply) + reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error); + g_error_free (error); + } + else + { + if (send_reply) + reply = method_create_response (context, out_param_values, out_param_gvalues); + } + + g_array_free (out_param_values, TRUE); + g_value_array_free (out_param_gvalues); + g_value_array_free (value_array); + + g_slice_free (DBusGSyncThreadedData, method_data); + + if (reply) + { + dbus_g_method_send_reply (context, reply); + } +} + static DBusHandlerResult invoke_object_method (GObject *object, const DBusGObjectInfo *object_info, @@ -1217,11 +1380,12 @@ invoke_object_method (GObject *object, DBusConnection *connection, DBusMessage *message) { - gboolean had_error, is_async, send_reply; + gboolean send_reply; + GMethodCallType call_type; + gboolean had_error; GError *gerror; GValueArray *value_array; GValue return_value = {0,}; - GClosure closure; char *in_signature; GArray *out_param_values = NULL; GValueArray *out_param_gvalues = NULL; @@ -1234,35 +1398,52 @@ invoke_object_method (GObject *object, gboolean retval_is_synthetic; gboolean retval_is_constant; const char *arg_metadata; + const char *call_type_str; + DBusGSyncThreadedData *method_data; + + /* This is evil. We do this to work around the fact that + * the generated glib marshallers check a flag in the closure object + * which we don't care about. We don't need/want to create + * a new closure for each invocation. + */ + static GClosure closure = {0}; gerror = NULL; - /* This flag says whether invokee is handed a special DBusGMethodInvocation structure, - * instead of being required to fill out all return values in the context of the function. - * Some additional data is also exposed, such as the message sender. + /* Determine how the method is to be called. 3 possible ways: + * + * synchronously - method_call_type 'S' + * synchronously in a thread - method_call_type 'T' + * asynchronously - method_call_type 'A' */ - is_async = strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0; - + call_type_str = string_table_lookup (get_method_data (object_info, method), 2); + switch (*call_type_str) + { + case 'A': /* call method asynchronously */ + call_type = ASYNCHRONOUS; + break; + case 'T': /* call synchronous method in a thread */ + call_type = SYNCHRONOUS_THREADED; + break; + case 'S': /* call fully synchronous method */ + default: + call_type = SYNCHRONOUS; + break; + } + /* Messages can be sent with a flag that says "I don't need a reply". This is an optimization * normally, but in the context of the system bus it's important to not send a reply * to these kinds of messages, because they will be unrequested replies, and thus subject * to denial and logging. We don't want to fill up logs. * http://bugs.freedesktop.org/show_bug.cgi?id=19441 */ - send_reply = !dbus_message_get_no_reply (message); + send_reply = !dbus_message_get_no_reply (message); have_retval = FALSE; retval_signals_error = FALSE; retval_is_synthetic = FALSE; retval_is_constant = FALSE; - /* This is evil. We do this to work around the fact that - * the generated glib marshallers check a flag in the closure object - * which we don't care about. We don't need/want to create - * a new closure for each invocation. - */ - memset (&closure, 0, sizeof (closure)); - in_signature = method_input_signature_from_object_info (object_info, method); /* Convert method IN parameters to GValueArray */ @@ -1299,22 +1480,8 @@ invoke_object_method (GObject *object, g_value_array_prepend (value_array, NULL); g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT); g_value_set_object (g_value_array_get_nth (value_array, 0), object); - - if (is_async) - { - GValue context_value = {0,}; - DBusGMethodInvocation *context; - context = g_new (DBusGMethodInvocation, 1); - context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection)); - context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message)); - context->object = object_info; - context->method = method; - context->send_reply = send_reply; - g_value_init (&context_value, G_TYPE_POINTER); - g_value_set_pointer (&context_value, context); - g_value_array_append (value_array, &context_value); - } - else + + if (ASYNCHRONOUS!=call_type) { RetvalType retval; gboolean arg_in; @@ -1370,7 +1537,7 @@ invoke_object_method (GObject *object, * is a "synthetic" return value; i.e. we aren't going to be * sending it over the bus, it's just to signal an error. */ - if (!have_retval) + if (!have_retval && SYNCHRONOUS_THREADED!=call_type) { have_retval = TRUE; retval_is_synthetic = TRUE; @@ -1433,21 +1600,69 @@ invoke_object_method (GObject *object, } } - /* Append GError as final argument if necessary */ + /* + * Append GError as final argument if necessary + * Note: we never do this for asynchronous and synchronous threaded calls! + */ if (retval_signals_error) { g_assert (have_retval); + g_assert (SYNCHRONOUS==call_type); g_value_array_append (value_array, NULL); g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER); g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror); } - + + /* + * Append DBusGMethodInvocation as final argument in case of + * asynchronous or synchronous threaded calls + */ + if (ASYNCHRONOUS==call_type || SYNCHRONOUS_THREADED==call_type) + { + GValue context_value = {0,}; + DBusGMethodInvocation *context; + context = g_new (DBusGMethodInvocation, 1); + context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection)); + context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message)); + context->object = object_info; + context->method = method; + context->send_reply = send_reply; + g_value_init (&context_value, G_TYPE_POINTER); + g_value_set_pointer (&context_value, context); + g_value_array_append (value_array, &context_value); + } + /* Actually invoke method */ - method->marshaller (&closure, have_retval ? &return_value : NULL, - value_array->n_values, - value_array->values, - NULL, method->function); - if (is_async) + switch (call_type) + { + case SYNCHRONOUS_THREADED: + method_data = g_slice_new (DBusGSyncThreadedData); + if (!method_data) + goto nomem; + + method_data->method = method; + method_data->closure = &closure; + method_data->value_array = value_array; + method_data->out_param_values = out_param_values; + method_data->out_param_gvalues = out_param_gvalues; + + if (!_dbus_gasync_thread_pool_start (invoke_marshaller_threaded, + method_data)) + { + g_slice_free (DBusGSyncThreadedData, method_data); + goto nomem; + } + break; + case ASYNCHRONOUS: + case SYNCHRONOUS: + method->marshaller (&closure, have_retval ? &return_value : NULL, + value_array->n_values, + value_array->values, + NULL, method->function); + break; + } + + if (ASYNCHRONOUS==call_type || SYNCHRONOUS_THREADED==call_type) { result = DBUS_HANDLER_RESULT_HANDLED; goto done; @@ -1478,68 +1693,21 @@ invoke_object_method (GObject *object, /* First, append the return value, unless it's synthetic */ if (have_retval && !retval_is_synthetic) - { + { if (send_reply && !_dbus_gvalue_marshal (&iter, &return_value)) goto nomem; if (!retval_is_constant) g_value_unset (&return_value); } - /* Grab the argument metadata and iterate over it */ - arg_metadata = method_arg_info_from_object_info (object_info, method); - /* Now append any remaining return values */ - out_param_pos = 0; - out_param_gvalue_pos = 0; - while (*arg_metadata) - { - GValue gvalue = {0, }; - const char *arg_name; - gboolean arg_in; - gboolean constval; - RetvalType retval; - const char *arg_signature; - DBusSignatureIter argsigiter; - - do - { - /* Iterate over only output values; skip over input - arguments and the return value */ - arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature); - } - while ((arg_in || retval != RETVAL_NONE) && *arg_metadata); - - /* If the last argument we saw was input or the return - * value, we must be done iterating over output arguments. - */ - if (arg_in || retval != RETVAL_NONE) - break; - - dbus_signature_iter_init (&argsigiter, arg_signature); - - g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE)); - if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE) - { - if (!_dbus_gvalue_take (&gvalue, - &(g_array_index (out_param_values, GTypeCValue, out_param_pos)))) - g_assert_not_reached (); - out_param_pos++; - } - else - { - g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos); - out_param_gvalue_pos++; - } - - if (send_reply && !_dbus_gvalue_marshal (&iter, &gvalue)) - goto nomem; - /* Here we actually free the allocated value; we - * took ownership of it with _dbus_gvalue_take, unless - * an annotation has specified this value as constant. - */ - if (!constval) - g_value_unset (&gvalue); - } + if (send_reply && + !add_output_arguments (&iter, + object_info, + method, + out_param_values, + out_param_gvalues)) + goto nomem; } else if (send_reply) reply = gerror_to_dbus_error_message (object_info, message, gerror); @@ -1553,18 +1721,98 @@ invoke_object_method (GObject *object, result = DBUS_HANDLER_RESULT_HANDLED; done: g_free (in_signature); - if (!is_async) + if (SYNCHRONOUS_THREADED!=call_type) { - g_array_free (out_param_values, TRUE); - g_value_array_free (out_param_gvalues); + /* + * if call_type is synchronous threaded the arrays will be freed + * within the thread_pool by invoke_marshaller_method() + */ + if (out_param_values) + g_array_free (out_param_values, TRUE); + if (out_param_gvalues) + g_value_array_free (out_param_gvalues); + g_value_array_free (value_array); } - g_value_array_free (value_array); return result; nomem: result = DBUS_HANDLER_RESULT_NEED_MEMORY; goto done; } +static gboolean +add_output_arguments (DBusMessageIter *iter, + const DBusGObjectInfo *object_info, + const DBusGMethodInfo *method, + GArray *out_param_values, + GValueArray *out_param_gvalues) +{ + const char *arg_metadata; + int out_param_pos, out_param_gvalue_pos; + gboolean res = TRUE; + + /* Grab the argument metadata and iterate over it */ + arg_metadata = method_arg_info_from_object_info (object_info, method); + + /* Append the remaining return values */ + out_param_pos = 0; + out_param_gvalue_pos = 0; + while (*arg_metadata) + { + GValue gvalue = {0, }; + const char *arg_name; + gboolean arg_in; + gboolean constval; + RetvalType retval; + const char *arg_signature; + DBusSignatureIter argsigiter; + + do + { + /* Iterate over only output values; skip over input + arguments and the return value */ + arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature); + } + while ((arg_in || retval != RETVAL_NONE) && *arg_metadata); + + /* If the last argument we saw was input or the return + * value, we must be done iterating over output arguments. + */ + if (arg_in || retval != RETVAL_NONE) + break; + + dbus_signature_iter_init (&argsigiter, arg_signature); + + g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE)); + if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE) + { + if (!_dbus_gvalue_take (&gvalue, + &(g_array_index (out_param_values, GTypeCValue, out_param_pos)))) + g_assert_not_reached (); + out_param_pos++; + } + else + { + g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos); + out_param_gvalue_pos++; + } + + if (!_dbus_gvalue_marshal (iter, &gvalue)) + { + res = FALSE; + break; + } + + /* Here we actually free the allocated value; we + * took ownership of it with _dbus_gvalue_take, unless + * an annotation has specified this value as constant. + */ + if (!constval) + g_value_unset (&gvalue); + } + + return res; +} + static DBusHandlerResult object_registration_message (DBusConnection *connection, DBusMessage *message, @@ -2473,7 +2721,7 @@ dbus_g_method_return (DBusGMethodInvocation *context, ...) char *out_sig; GArray *argsig; guint i; - + /* This field was initialized inside invoke_object_method; we * carry it over through the async invocation to here. */ @@ -2525,11 +2773,11 @@ void dbus_g_method_return_error (DBusGMethodInvocation *context, const GError *error) { DBusMessage *reply; - + /* See comment in dbus_g_method_return */ if (!context->send_reply) - return; - + return; + reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error); dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL); dbus_message_unref (reply); diff --git a/test/core/my-object.c b/test/core/my-object.c index 6059724..d4478bc 100644 --- a/test/core/my-object.c +++ b/test/core/my-object.c @@ -241,6 +241,12 @@ my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error) return TRUE; } +void +my_object_uppercase_thread (MyObject *obj, const char *str, char **ret, DBusGMethodInvocation *invocation) +{ + *ret = g_ascii_strup (str, -1); +} + gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error) { @@ -585,6 +591,13 @@ my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **er return TRUE; } +void +my_object_echo_variant_thread (MyObject *obj, GValue *variant, GValue *out, DBusGMethodInvocation *invocation) +{ + g_value_init (out, G_VALUE_TYPE(variant)); + g_value_copy (variant, out); +} + gboolean my_object_echo_signature (MyObject *obj, const gchar *in, gchar **out, GError **error) { @@ -739,6 +752,12 @@ my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *conte g_idle_add ((GSourceFunc)do_async_increment, data); } +void +my_object_thread_increment (MyObject *obj, gint32 x, gint32 *out, DBusGMethodInvocation *context) +{ + *out = x + 1; +} + static gboolean do_async_error (IncrementData *data) { diff --git a/test/core/my-object.h b/test/core/my-object.h index 7fe449d..66255f7 100644 --- a/test/core/my-object.h +++ b/test/core/my-object.h @@ -44,6 +44,8 @@ gboolean my_object_do_nothing (MyObject *obj, GError **error); gboolean my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); +void my_object_thread_increment (MyObject *obj, gint32 x, gint32 *out, DBusGMethodInvocation *context); + gint32 my_object_increment_retval (MyObject *obj, gint32 x); gint32 my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error); @@ -52,6 +54,7 @@ gboolean my_object_throw_error (MyObject *obj, GError **error); gboolean my_object_throw_not_supported (MyObject *obj, GError **error); gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error); +void my_object_uppercase_thread (MyObject *obj, const char *str, char **rete, DBusGMethodInvocation *invocation); gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error); @@ -91,6 +94,7 @@ gboolean my_object_emit_signal2 (MyObject *obj, GError **error); gboolean my_object_emit_frobnicate (MyObject *obj, GError **error); gboolean my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error); +void my_object_echo_variant_thread (MyObject *obj, GValue *variant, GValue *ret, DBusGMethodInvocation *invocation); gboolean my_object_echo_signature (MyObject *obj, const gchar *in, gchar **out, GError **error); gboolean my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error); diff --git a/test/core/test-dbus-glib.c b/test/core/test-dbus-glib.c index c6071a7..ce9a46f 100644 --- a/test/core/test-dbus-glib.c +++ b/test/core/test-dbus-glib.c @@ -721,6 +721,18 @@ main (int argc, char **argv) lose_gerror ("Failed to complete Increment call", error); if (v_UINT32_2 != 43) lose ("Increment call returned %d, should be 43", v_UINT32_2); + + v_UINT32_2 = 0; + g_print ("Calling ThreadIncrement\n"); + error = NULL; + if (!dbus_g_proxy_call (proxy, "ThreadIncrement", &error, + G_TYPE_UINT, 42, + G_TYPE_INVALID, + G_TYPE_UINT, &v_UINT32_2, + G_TYPE_INVALID)) + lose_gerror ("Failed to complete ThreadIncrement call", error); + if (v_UINT32_2 != 43) + lose ("ThreadIncrement call returned %d, should be 43", v_UINT32_2); v_UINT32_2 = 0; g_print ("Calling Increment (async)\n"); @@ -805,7 +817,50 @@ main (int argc, char **argv) if (strcmp ("FOOBAR", v_STRING_2) != 0) lose ("Uppercase call returned unexpected string %s", v_STRING_2); g_free (v_STRING_2); + + g_print ("Calling UppercaseThread\n"); + if (!dbus_g_proxy_call (proxy, "UppercaseThread", &error, + G_TYPE_STRING, "foobar", + G_TYPE_INVALID, + G_TYPE_STRING, &v_STRING_2, + G_TYPE_INVALID)) + lose_gerror ("Failed to complete Uppercase call", error); + if (strcmp ("FOOBAR", v_STRING_2) != 0) + lose ("Uppercase call returned unexpected string %s", v_STRING_2); + g_free (v_STRING_2); + { + GValue val = {0, }; + GValue retval = {0, }; + + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, 41); + + g_print ("Calling EchoVariant\n"); + + if (!dbus_g_proxy_call (proxy, "EchoVariant", &error, + G_TYPE_VALUE, &val, G_TYPE_INVALID, + G_TYPE_VALUE, &retval, G_TYPE_INVALID)) + lose_gerror ("Failed to complete EchoVariant call", error); + if (G_VALUE_TYPE(&retval) != G_TYPE_INT) + lose ("EchoVariant returned invalid type %d", G_VALUE_TYPE(&retval)); + if (g_value_get_int (&retval) != 41) + lose ("EchoVariant returned incorrect value %d", g_value_get_int (&retval)); + + g_print ("Calling EchoVariantThread\n"); + + g_value_unset (&retval); + + if (!dbus_g_proxy_call (proxy, "EchoVariantThread", &error, + G_TYPE_VALUE, &val, G_TYPE_INVALID, + G_TYPE_VALUE, &retval, G_TYPE_INVALID)) + lose_gerror ("Failed to complete EchoVariantThread call", error); + if (G_VALUE_TYPE(&retval) != G_TYPE_INT) + lose ("EchoVariant returned invalid type %d", G_VALUE_TYPE(&retval)); + if (g_value_get_int (&retval) != 41) + lose ("EchoVariant returned incorrect value %d", g_value_get_int (&retval)); + } + run_mainloop (); g_print ("Calling ManyArgs\n"); @@ -1184,7 +1239,7 @@ main (int argc, char **argv) g_free (out_sig); } - + { GValue *val; GHashTable *table; diff --git a/test/core/test-service-glib.xml b/test/core/test-service-glib.xml index 86152c7..5db7daa 100644 --- a/test/core/test-service-glib.xml +++ b/test/core/test-service-glib.xml @@ -36,6 +36,12 @@ + + + + + + @@ -119,6 +125,12 @@ + + + + + + @@ -137,6 +149,12 @@ + + + + + + -- 1.6.2.5