From: Carlos Garnacho Date: Mon, 12 Jun 2017 15:19:05 +0000 (+0200) Subject: codegen: Make the task_complete flag for < 2.44 more similar to >= 2.44 X-Git-Tag: 0.37.1~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fkeep-around%2Fbe27b9e6d1b7cb590dcda6be6621d707887c87cb;p=thirdparty%2Fvala.git 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 --- 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 (); +}