diff --git a/codegen/valaccodeattribute.vala b/codegen/valaccodeattribute.vala
index 0383fe3..1c2856a 100644
--- a/codegen/valaccodeattribute.vala
+++ b/codegen/valaccodeattribute.vala
@@ -502,6 +502,19 @@ public class Vala.CCodeAttribute : AttributeCache {
 		}
 	}
 
+	public bool fast_async {
+		get {
+			if (_fast_async == null) {
+				if (ccode != null && ccode.has_argument ("fast_async")) {
+					_fast_async = ccode.get_bool ("fast_async");
+				} else {
+					_fast_async = false;
+				}
+			}
+			return _fast_async;
+		}
+	}	
+
 	public string? array_length_type { get; private set; }
 	public string? array_length_name { get; private set; }
 	public string? array_length_expr { get; private set; }
@@ -546,6 +559,7 @@ public class Vala.CCodeAttribute : AttributeCache {
 	private bool ctype_set = false;
 	private bool? _array_length;
 	private bool? _array_null_terminated;
+	private bool? _fast_async;
 
 	private static int dynamic_method_id;
 
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 8e923ea..7f0268f 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -692,6 +692,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 			int state = next_coroutine_state++;
 
 			ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
+			ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_yeld_expression_progress_"), new CCodeConstant ("1"));
 			ccode.add_expression (async_call);
 			ccode.add_return (new CCodeConstant ("FALSE"));
 			ccode.add_label ("_state_%d".printf (state));
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index d147eb1..efef696 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -124,24 +124,33 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 	}
 
 	public void complete_async () {
-		var state = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_");
-		var zero = new CCodeConstant ("0");
-		var state_is_zero = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, state, zero);
-		ccode.open_if (state_is_zero);
 
 		var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
 
-		var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
-		idle_call.add_argument (async_result_expr);
-		ccode.add_expression (idle_call);
+		if (current_method == null || (!get_ccode_attribute(current_method).fast_async)) {
 
-		ccode.add_else ();
+			var state = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_");
+			var zero = new CCodeConstant ("0");
+			var state_is_zero = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, state, zero);
 
-		var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
-		direct_call.add_argument (async_result_expr);
-		ccode.add_expression (direct_call);
+			ccode.open_if (state_is_zero);
 
-		ccode.close ();
+			var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
+			idle_call.add_argument (async_result_expr);
+			ccode.add_expression (idle_call);
+
+			ccode.add_else ();
+
+			var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
+			direct_call.add_argument (async_result_expr);
+			ccode.add_expression (direct_call);
+
+			ccode.close ();
+		} else {
+			var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
+			direct_call.add_argument (async_result_expr);
+			ccode.add_expression (direct_call);
+		}
 
 		var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
 		unref.add_argument (async_result_expr);
@@ -456,6 +465,20 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 		if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
 			if (m.body != null) {
 				if (m.coroutine) {
+					ccode.open_if(
+						new CCodeBinaryExpression(CCodeBinaryOperator.OR, 
+							new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, 
+								new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_in_progress_"), 
+								new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_") ),
+							new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, 
+								new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_in_progress_"), new CCodeConstant ("1")) ));
+
+					ccode.add_statement (new CCodeComment ("callback is called too early before that yield stantment is really reached"));
+					CCodeExpression codenode = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_wakeup_requested_"), new CCodeConstant ("1"), CCodeAssignmentOperator.ADD);
+					ccode.add_expression (codenode);
+					ccode.add_return (new CCodeConstant ("FALSE"));
+					ccode.close();
+
 					ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"));
 
 					// initial coroutine state
@@ -471,11 +494,13 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 					// let gcc know that this can't happen
 					ccode.add_default ();
 					ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
+					ccode.add_return (new CCodeConstant ("FALSE"));
 
 					ccode.close ();
 
 					// coroutine body
-					ccode.add_label ("_state_0");
+					ccode.add_label ("_state_0");					
+					ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_in_progress_"), new CCodeConstant ("0"));
 				}
 
 				if (m.closure) {
diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala
index 928e67b..234f6b4 100644
--- a/codegen/valagasyncmodule.vala
+++ b/codegen/valagasyncmodule.vala
@@ -28,6 +28,9 @@ public class Vala.GAsyncModule : GtkModule {
 		var data = new CCodeStruct ("_" + dataname);
 
 		data.add_field ("int", "_state_");
+		data.add_field ("int", "_state_in_progress_");
+		data.add_field ("int", "_wakeup_requested_");
+		data.add_field ("int", "_yeld_expression_progress_");
 		data.add_field ("GObject*", "_source_object_");
 		data.add_field ("GAsyncResult*", "_res_");
 		data.add_field ("GSimpleAsyncResult*", "_async_result");
@@ -200,6 +203,7 @@ public class Vala.GAsyncModule : GtkModule {
 
 		ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
 		ccode.add_assignment (data_var, dataalloc);
+		ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_in_progress_"), new CCodeConstant ("-1"));
 
 		var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
 
@@ -604,6 +608,7 @@ public class Vala.GAsyncModule : GtkModule {
 		ccode.add_assignment (new CCodeIdentifier ("_data_"), new CCodeIdentifier ("_user_data_"));
 		ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_"), new CCodeIdentifier ("source_object"));
 		ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"), new CCodeIdentifier ("_res_"));
+		ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_yeld_expression_progress_"), new CCodeConstant ("0"));
 
 		var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
 		ccall.add_argument (new CCodeIdentifier ("_data_"));
@@ -663,10 +668,21 @@ public class Vala.GAsyncModule : GtkModule {
 
 		if (stmt.yield_expression == null) {
 			int state = next_coroutine_state++;
-
+			ccode.open_if(
+				new CCodeBinaryExpression(CCodeBinaryOperator.GREATER_THAN,
+				new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_wakeup_requested_"), 
+				new CCodeConstant ("0") ) );
+			ccode.add_statement (new CCodeComment ("callback to wakeup yield is already called, so no wait and go to next state"));
+			ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
+			CCodeExpression codenode = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_wakeup_requested_"), new CCodeConstant ("-1"), CCodeAssignmentOperator.ADD);
+			ccode.add_expression (codenode);
+			ccode.add_else();
 			ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
 			ccode.add_return (new CCodeConstant ("FALSE"));
+			ccode.close();
+			
 			ccode.add_label ("_state_%d".printf (state));
+			ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_in_progress_"), new CCodeConstant (state.to_string ()));
 			ccode.add_statement (new CCodeEmptyStatement ());
 
 			return;
