feat: add scheduler module and refactor built-in module loading into shared modules.c
Introduce a new scheduler module with fiber-based cooperative multitasking, including native bindings for resume operations and a Wren class for scheduling callables. Refactor the existing timer module and CLI code to use a centralized built-in module registry in modules.c, replacing direct includes of timer.h and timer.wren.inc. Update Xcode project and Makefile to compile the new scheduler.c, modules.c, and their generated .wren.inc sources.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#include "scheduler.h"
|
||||
#include "wren.h"
|
||||
#include "vm.h"
|
||||
|
||||
// This method resumes a fiber that is suspended waiting on an asynchronous
|
||||
// operation. The first resumes it with zero arguments, and the second passes
|
||||
// one.
|
||||
static WrenValue* resume;
|
||||
static WrenValue* resumeWithArg;
|
||||
|
||||
static void captureMethods(WrenVM* vm)
|
||||
{
|
||||
resume = wrenGetMethod(vm, "scheduler", "Scheduler", "resume_(_)");
|
||||
resumeWithArg = wrenGetMethod(vm, "scheduler", "Scheduler", "resume_(_,_)");
|
||||
}
|
||||
|
||||
WrenForeignMethodFn schedulerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature)
|
||||
{
|
||||
if (strcmp(className, "Scheduler") != 0) return NULL;
|
||||
|
||||
if (isStatic && strcmp(signature, "captureMethods_()") == 0) return captureMethods;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void schedulerResume(WrenValue* fiber)
|
||||
{
|
||||
wrenCall(getVM(), resume, NULL, "v", fiber);
|
||||
wrenReleaseValue(getVM(), fiber);
|
||||
}
|
||||
|
||||
void schedulerReleaseMethods()
|
||||
{
|
||||
if (resume != NULL) wrenReleaseValue(getVM(), resume);
|
||||
if (resumeWithArg != NULL) wrenReleaseValue(getVM(), resumeWithArg);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef scheduler_h
|
||||
#define scheduler_h
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn schedulerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature);
|
||||
|
||||
void schedulerResume(WrenValue* fiber);
|
||||
|
||||
void schedulerReleaseMethods();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
class Scheduler {
|
||||
static add(callable) {
|
||||
if (__scheduled == null) __scheduled = []
|
||||
|
||||
__scheduled.add(Fiber.new {
|
||||
callable.call()
|
||||
runNextScheduled_()
|
||||
})
|
||||
}
|
||||
|
||||
// Called by native code.
|
||||
static resume_(fiber) { fiber.transfer() }
|
||||
static resume_(fiber, arg) { fiber.transfer(arg) }
|
||||
|
||||
static runNextScheduled_() {
|
||||
if (__scheduled == null || __scheduled.isEmpty) {
|
||||
return Fiber.suspend()
|
||||
} else {
|
||||
return __scheduled.removeAt(0).transfer()
|
||||
}
|
||||
}
|
||||
|
||||
foreign static captureMethods_()
|
||||
}
|
||||
|
||||
Scheduler.captureMethods_()
|
||||
@@ -0,0 +1,28 @@
|
||||
// Generated automatically from src/module/scheduler.wren. Do not edit.
|
||||
static const char* schedulerModuleSource =
|
||||
"class Scheduler {\n"
|
||||
" static add(callable) {\n"
|
||||
" if (__scheduled == null) __scheduled = []\n"
|
||||
"\n"
|
||||
" __scheduled.add(Fiber.new {\n"
|
||||
" callable.call()\n"
|
||||
" runNextScheduled_()\n"
|
||||
" })\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // Called by native code.\n"
|
||||
" static resume_(fiber) { fiber.transfer() }\n"
|
||||
" static resume_(fiber, arg) { fiber.transfer(arg) }\n"
|
||||
"\n"
|
||||
" static runNextScheduled_() {\n"
|
||||
" if (__scheduled == null || __scheduled.isEmpty) {\n"
|
||||
" return Fiber.suspend()\n"
|
||||
" } else {\n"
|
||||
" return __scheduled.removeAt(0).transfer()\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static captureMethods_()\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"Scheduler.captureMethods_()\n";
|
||||
+3
-28
@@ -3,14 +3,10 @@
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#include "scheduler.h"
|
||||
#include "timer.h"
|
||||
#include "wren.h"
|
||||
#include "vm.h"
|
||||
|
||||
#include "timer.wren.inc"
|
||||
|
||||
// The Wren method to call when a timer has completed.
|
||||
static WrenValue* resumeTimer;
|
||||
#include "wren.h"
|
||||
|
||||
// Called by libuv when the timer finished closing.
|
||||
static void timerCloseCallback(uv_handle_t* handle)
|
||||
@@ -27,18 +23,11 @@ static void timerCallback(uv_timer_t* handle)
|
||||
uv_close((uv_handle_t*)handle, timerCloseCallback);
|
||||
|
||||
// Run the fiber that was sleeping.
|
||||
wrenCall(getVM(), resumeTimer, NULL, "v", fiber);
|
||||
wrenReleaseValue(getVM(), fiber);
|
||||
schedulerResume(fiber);
|
||||
}
|
||||
|
||||
static void startTimer(WrenVM* vm)
|
||||
{
|
||||
// If we haven't looked up the resume method yet, grab it now.
|
||||
if (resumeTimer == NULL)
|
||||
{
|
||||
resumeTimer = wrenGetMethod(vm, "timer", "Timer", "resumeTimer_(_)");
|
||||
}
|
||||
|
||||
int milliseconds = (int)wrenGetArgumentDouble(vm, 1);
|
||||
WrenValue* fiber = wrenGetArgumentValue(vm, 2);
|
||||
|
||||
@@ -50,15 +39,6 @@ static void startTimer(WrenVM* vm)
|
||||
uv_timer_start(handle, timerCallback, milliseconds, 0);
|
||||
}
|
||||
|
||||
char* timerGetSource()
|
||||
{
|
||||
size_t length = strlen(timerModuleSource);
|
||||
char* copy = (char*)malloc(length + 1);
|
||||
strncpy(copy, timerModuleSource, length + 1);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
WrenForeignMethodFn timerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature)
|
||||
{
|
||||
@@ -68,8 +48,3 @@ WrenForeignMethodFn timerBindForeign(
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void timerReleaseMethods()
|
||||
{
|
||||
if (resumeTimer != NULL) wrenReleaseValue(getVM(), resumeTimer);
|
||||
}
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
char* timerGetSource();
|
||||
|
||||
WrenForeignMethodFn timerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature);
|
||||
|
||||
void timerReleaseMethods();
|
||||
|
||||
#endif
|
||||
|
||||
+4
-25
@@ -1,34 +1,13 @@
|
||||
import "scheduler" for Scheduler
|
||||
|
||||
class Timer {
|
||||
static sleep(milliseconds) {
|
||||
if (!(milliseconds is Num)) Fiber.abort("Milliseconds must be a number.")
|
||||
if (milliseconds < 0) Fiber.abort("Milliseconds cannot be negative.")
|
||||
|
||||
startTimer_(milliseconds, Fiber.current)
|
||||
|
||||
runNextScheduled_()
|
||||
}
|
||||
|
||||
// TODO: Once the CLI modules are more fleshed out, find a better place to
|
||||
// put this.
|
||||
static schedule(callable) {
|
||||
if (__scheduled == null) __scheduled = []
|
||||
__scheduled.add(Fiber.new {
|
||||
callable.call()
|
||||
runNextScheduled_()
|
||||
})
|
||||
Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
foreign static startTimer_(milliseconds, fiber)
|
||||
|
||||
// Called by native code.
|
||||
static resumeTimer_(fiber) {
|
||||
fiber.transfer()
|
||||
}
|
||||
|
||||
static runNextScheduled_() {
|
||||
if (__scheduled == null || __scheduled.isEmpty) {
|
||||
Fiber.suspend()
|
||||
} else {
|
||||
__scheduled.removeAt(0).transfer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,15 @@
|
||||
// Generated automatically from src/module/timer.wren. Do not edit.
|
||||
static const char* timerModuleSource =
|
||||
"import \"scheduler\" for Scheduler\n"
|
||||
"\n"
|
||||
"class Timer {\n"
|
||||
" static sleep(milliseconds) {\n"
|
||||
" if (!(milliseconds is Num)) Fiber.abort(\"Milliseconds must be a number.\")\n"
|
||||
" if (milliseconds < 0) Fiber.abort(\"Milliseconds cannot be negative.\")\n"
|
||||
"\n"
|
||||
" startTimer_(milliseconds, Fiber.current)\n"
|
||||
"\n"
|
||||
" runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // TODO: Once the CLI modules are more fleshed out, find a better place to\n"
|
||||
" // put this.\n"
|
||||
" static schedule(callable) {\n"
|
||||
" if (__scheduled == null) __scheduled = []\n"
|
||||
" __scheduled.add(Fiber.new {\n"
|
||||
" callable.call()\n"
|
||||
" runNextScheduled_()\n"
|
||||
" })\n"
|
||||
" Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static startTimer_(milliseconds, fiber)\n"
|
||||
"\n"
|
||||
" // Called by native code.\n"
|
||||
" static resumeTimer_(fiber) {\n"
|
||||
" fiber.transfer()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static runNextScheduled_() {\n"
|
||||
" if (__scheduled == null || __scheduled.isEmpty) {\n"
|
||||
" Fiber.suspend()\n"
|
||||
" } else {\n"
|
||||
" __scheduled.removeAt(0).transfer()\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
Reference in New Issue
Block a user