Browse Source

Several Fiber related fixes. Unit test added.

Marco Bambini 7 years ago
parent
commit
c7da14bb29

+ 10 - 0
src/runtime/gravity_core.c

@@ -410,6 +410,13 @@ inline gravity_value_t convert_value2string (gravity_vm *vm, gravity_value_t v)
 		return convert_map2string(vm, map);
 	}
 
+    if (VALUE_ISA_RANGE(v)) {
+        gravity_range_t *r = VALUE_AS_RANGE(v);
+        char buffer[512];
+        snprintf(buffer, sizeof(buffer), "%" PRId64 "...%" PRId64, r->from, r->to);
+        return VALUE_FROM_CSTRING(vm, buffer);
+    }
+	
 	// check if class implements the String method (avoiding infinte loop by checking for convert_object_string)
 	gravity_closure_t *closure = gravity_vm_fastlookup(vm, gravity_value_getclass(v), GRAVITY_STRING_INDEX);
 
@@ -2392,6 +2399,9 @@ static bool fiber_create (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 static bool fiber_run (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex, bool is_trying) {
 	#pragma unused(nargs, rindex)
 
+    // set rindex slot to NULL in order to falsify the if closure check performed by the VM
+    gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex);
+	
 	gravity_fiber_t *fiber = VALUE_AS_FIBER(GET_VALUE(0));
 	if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
 

+ 21 - 4
src/runtime/gravity_vm.c

@@ -388,11 +388,16 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 				// prepare function call for binary operation
 				PREPARE_FUNC_CALL2(closure, v2, v3, (op == LOAD) ? GRAVITY_LOAD_INDEX : ((op == LOADAT) ? GRAVITY_LOADAT_INDEX : GRAVITY_LOADS_INDEX), rwin);
 
+                // save currently executing fiber (that can change!)
+                gravity_fiber_t *current_fiber = fiber;
+                
 				// call closure (do not use a macro here because we want to handle both the bridged and special cases)
 				STORE_FRAME();
 				execute_load_function:
 				switch(closure->f->tag) {
 					case EXEC_TYPE_NATIVE: {
+                        // invalidate current_fiber because it does not need to be synced in this case
+                        current_fiber = NULL;
 						PUSH_FRAME(closure, &stackstart[rwin], r1, 2);
 					} break;
 
@@ -430,7 +435,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					} break;
 				}
 				LOAD_FRAME();
-				SYNC_STACKTOP(closure, MAXNUM(_rneed, rwin));
+                SYNC_STACKTOP(current_fiber, MAXNUM(_rneed, rwin));
 
 				// continue execution
 				DISPATCH();
@@ -516,11 +521,16 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 				// prepare function call
 				PREPARE_FUNC_CALL3(closure, v2, v3, v1, (op == STORE) ? GRAVITY_STORE_INDEX : GRAVITY_STOREAT_INDEX, rwin);
 
+                // save currently executing fiber (that can change!)
+                gravity_fiber_t *current_fiber = fiber;
+                
 				// call function f (do not use a macro here because we want to handle both the bridged and special cases)
 				STORE_FRAME();
 				execute_store_function:
 				switch(closure->f->tag) {
 					case EXEC_TYPE_NATIVE: {
+                        // invalidate current_fiber because it does not need to be synced in this case
+                        current_fiber = NULL;
 						SETVALUE(rwin+1, v1);
 						PUSH_FRAME(closure, &stackstart[rwin], r1, 2);
 					} break;
@@ -559,7 +569,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					} break;
 				}
 				LOAD_FRAME();
-				SYNC_STACKTOP(closure, MAXNUM(_rneed, rwin));
+				SYNC_STACKTOP(current_fiber, MAXNUM(_rneed, rwin));
 
 				// continue execution
 				DISPATCH();
@@ -1077,11 +1087,16 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 
 				DEBUG_STACK();
 
+                // save currently executing fiber (that can change!)
+                gravity_fiber_t *current_fiber = fiber;
+                
 				// execute function
 				STORE_FRAME();
 				execute_call_function:
 				switch(closure->f->tag) {
 					case EXEC_TYPE_NATIVE: {
+                        // invalidate current_fiber because it does not need to be synced in this case
+                        current_fiber = NULL;
                         // support for default arg values
                         if (marray_size(closure->f->pvalue)) {
                             uint32_t n = 1; // from 1 in order to skip self implicit argument
@@ -1106,8 +1121,10 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 								goto execute_call_function;
 							}
 
-							// check for special fiber error
+                            // reset current fiber that could be changed during the call
 							fiber = vm->fiber;
+                            
+							// check for special fiber error
 							if (fiber == NULL) return true;
 							if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error);
 						}
@@ -1133,7 +1150,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 						break;
 				}
 				LOAD_FRAME();
-				SYNC_STACKTOP(closure, MAXNUM(_rneed, rwin));
+				SYNC_STACKTOP(current_fiber, MAXNUM(_rneed, rwin));
 
 				DISPATCH();
 			}

+ 5 - 3
src/runtime/gravity_vmmacros.h

@@ -157,7 +157,7 @@
 									cframe->outloop = false;																			\
 									cframe->args = (USE_ARGS(_c)) ? gravity_list_from_array(vm, _n-1, _s+1) : NULL;						\
 
-#define SYNC_STACKTOP(_c,_n)		if (_c->f->tag != EXEC_TYPE_NATIVE) fiber->stacktop -= _n
+#define SYNC_STACKTOP(_fiber,_n)	if (_fiber) _fiber->stacktop -= _n
 #define SETFRAME_OUTLOOP(cframe)	(cframe)->outloop = true
 
 #define COMPUTE_JUMP(value)			(func->bytecode + (value))
@@ -238,10 +238,12 @@
 													SETVALUE(_w+2, _v3)
 
 
-#define CALL_FUNC(_name,_c,r1,nargs,rwin)			STORE_FRAME();																			\
+#define CALL_FUNC(_name,_c,r1,nargs,rwin)           gravity_fiber_t *current_fiber = fiber;                                                 \
+                                                    STORE_FRAME();																			\
 													execute_op_##_name:																		\
 													switch(_c->f->tag) {																	\
 													case EXEC_TYPE_NATIVE: {																\
+                                                        current_fiber = NULL;                                                               \
 														PUSH_FRAME(_c, &stackstart[rwin], r1, nargs);										\
 													} break;																				\
 													case EXEC_TYPE_INTERNAL: {																\
@@ -268,7 +270,7 @@
 														break;																				\
 													}																						\
 													LOAD_FRAME();																			\
-													SYNC_STACKTOP(_c, MAXNUM(_rneed, rwin))
+													SYNC_STACKTOP(current_fiber, MAXNUM(_rneed, rwin))
 
 // MACROS used in core and optionals
 #define SETMETA_INITED(c)                           gravity_class_get_meta(c)->is_inited = true

+ 2 - 2
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 #endif
 
-#define GRAVITY_VERSION						"0.4.6"     // git tag 0.4.6
-#define GRAVITY_VERSION_NUMBER				0x000406    // git push --tags
+#define GRAVITY_VERSION						"0.4.7"     // git tag 0.4.7
+#define GRAVITY_VERSION_NUMBER				0x000407    // git push --tags
 #define GRAVITY_BUILD_DATE					__DATE__
 
 #ifndef GRAVITY_ENABLE_DOUBLE

+ 22 - 0
test/unittest/fibers_scheduling.gravity

@@ -0,0 +1,22 @@
+#unittest {
+	name: "Fibers scheduling.";
+	result: "abcbcbcbcbcbcbcbcd";
+};
+
+func main() {
+    var g = "a";
+    var n = 8;
+    
+    var task1 = Fiber.create({
+        for (var i in 1...n) {g += "b"; Fiber.yield();}
+    });
+    
+    var task2 = Fiber.create({
+        for (var i in 1...n) {g += "c"; Fiber.yield();}
+    });
+    
+    for (var i in 1...n) {task1();task2();}
+    
+    g += "d";
+    return g;
+}