From be27b9e6d1b7cb590dcda6be6621d707887c87cb Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 12 Jun 2017 17:19:05 +0200 Subject: [PATCH] codegen: Make the task_complete flag for < 2.44 more similar to >= 2.44 According to the g_task_get_completed() docs (which we rely on for glib >= 2.44 targets): "This changes from FALSE to TRUE after the task's callback is invoked, and will return FALSE from inside the callback". So to make the code paths most similar to >= 2.44 (when g_task_get_completed is available), wrap the GAsyncReadyCallback with one of our own, that just invokes the nested callback (if any) and turns on the flag. Also remove the code turning on the flag on finish(), it's superfluous now and there are no guarantees that it will be invoked. https://bugzilla.gnome.org/show_bug.cgi?id=783543 --- codegen/valagasyncmodule.vala | 65 ++++++++++++++++++++++++++++--- tests/Makefile.am | 1 + tests/asynchronous/bug783543.vala | 15 +++++++ 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 tests/asynchronous/bug783543.vala diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala index 002c488ca..dd8e916e2 100644 --- a/codegen/valagasyncmodule.vala +++ b/codegen/valagasyncmodule.vala @@ -33,6 +33,7 @@ public class Vala.GAsyncModule : GtkModule { data.add_field ("GTask*", "_async_result"); if (!context.require_glib_version (2, 44)) { + data.add_field ("GAsyncReadyCallback", "_callback_"); data.add_field ("gboolean", "_task_complete_"); } @@ -160,9 +161,58 @@ public class Vala.GAsyncModule : GtkModule { return freefunc; } + void generate_async_ready_callback_wrapper (Method m, string function_name) { + var function = new CCodeFunction (function_name, "void"); + function.modifiers = CCodeModifiers.STATIC; + + function.add_parameter (new CCodeParameter ("*source_object", "GObject")); + function.add_parameter (new CCodeParameter ("*res", "GAsyncResult")); + function.add_parameter (new CCodeParameter ("*user_data", "void")); + + push_function (function); + + // Set _task_complete_ to false after calling back to the real func + var async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_TASK")); + async_result_cast.add_argument (new CCodeIdentifier ("res")); + + var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data"; + ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_task_data_")); + + var get_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_task_data")); + get_data_call.add_argument (async_result_cast); + + var data_var = new CCodeIdentifier ("_task_data_"); + ccode.add_assignment (data_var, get_data_call); + + var task_inner_callback = new CCodeMemberAccess.pointer (data_var, "_callback_"); + var callback_is_nonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, task_inner_callback, new CCodeConstant ("NULL")); + + ccode.open_if (callback_is_nonnull); + var nested_callback = new CCodeFunctionCall (task_inner_callback); + nested_callback.add_argument (new CCodeIdentifier ("source_object")); + nested_callback.add_argument (new CCodeIdentifier ("res")); + nested_callback.add_argument (new CCodeIdentifier ("user_data")); + ccode.add_expression (nested_callback); + ccode.close (); + + ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_task_complete_"), new CCodeConstant ("TRUE")); + + pop_function (); + + cfile.add_function_declaration (function); + cfile.add_function (function); + } + void generate_async_function (Method m) { push_context (new EmitContext ()); + string? callback_wrapper = null; + + if (!context.require_glib_version (2, 44)) { + callback_wrapper = get_ccode_real_name (m) + "_async_ready_wrapper"; + generate_async_ready_callback_wrapper (m, callback_wrapper); + } + var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data"; var asyncfunc = new CCodeFunction (get_ccode_real_name (m), "void"); var cparam_map = new HashMap (direct_hash, direct_equal); @@ -211,6 +261,10 @@ public class Vala.GAsyncModule : GtkModule { ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_")); ccode.add_assignment (data_var, dataalloc); + if (!context.require_glib_version (2, 44)) { + ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_callback_"), new CCodeConstant ("_callback_")); + } + var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new")); var t = m.parent_symbol as TypeSymbol; @@ -239,7 +293,11 @@ public class Vala.GAsyncModule : GtkModule { create_result.add_argument (new CCodeIdentifier (get_variable_cname (cancellable_param.name))); } - create_result.add_argument (new CCodeIdentifier ("_callback_")); + if (context.require_glib_version (2, 44)) { + create_result.add_argument (new CCodeIdentifier ("_callback_")); + } else { + create_result.add_argument (new CCodeIdentifier (callback_wrapper)); + } create_result.add_argument (new CCodeIdentifier ("_user_data_")); ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_async_result"), create_result); @@ -584,11 +642,6 @@ public class Vala.GAsyncModule : GtkModule { ccode.close (); } - if (!context.require_glib_version (2, 44)) { - var task_completed_var = new CCodeMemberAccess.pointer (data_var, "_task_complete_"); - ccode.add_assignment (task_completed_var, new CCodeConstant ("TRUE")); - } - emit_context.push_symbol (m); foreach (Parameter param in m.get_parameters ()) { if (param.direction != ParameterDirection.IN) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 765d26b13..061184922 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -266,6 +266,7 @@ TESTS = \ asynchronous/bug742621.vala \ asynchronous/bug762819.vala \ asynchronous/bug777242.vala \ + asynchronous/bug783543.vala \ asynchronous/closures.vala \ asynchronous/generator.vala \ asynchronous/yield.vala \ diff --git a/tests/asynchronous/bug783543.vala b/tests/asynchronous/bug783543.vala new file mode 100644 index 000000000..08148f4f5 --- /dev/null +++ b/tests/asynchronous/bug783543.vala @@ -0,0 +1,15 @@ +class Foo : Object { + public async void bar () { + Idle.add (bar.callback); + yield; + } +} + +void main () { + var loop = new MainLoop (); + var foo = new Foo (); + foo.bar.begin (() => { + loop.quit (); + }); + loop.run (); +} -- 2.47.2