A vertical slice of real libuv integration.
This adds a "timer" module to the CLI that provides a Timer class with a static sleep() method. Not the most exciting functionality in the world, but it requires the full hunk of libuv integration: - The CLI sets up libuv and runs the event loop. - Added a new directory src/module for CLI modules. - Updated all the make scripts to handle it. - Reorganized some other CLI code.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#include "timer.h"
|
||||
#include "wren.h"
|
||||
#include "vm.h"
|
||||
|
||||
// This is generated from builtin/module/timer.wren. Do not edit here.
|
||||
static const char* timerLibSource =
|
||||
"class Timer {\n"
|
||||
" static sleep(milliseconds) {\n"
|
||||
" startTimer_(milliseconds, Fiber.current)\n"
|
||||
" Fiber.yield()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static startTimer_(milliseconds, fiber)\n"
|
||||
"\n"
|
||||
" // Called by native code.\n"
|
||||
" static resumeTimer_(fiber) {\n"
|
||||
" fiber.run()\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
// The Wren method to call when a timer has completed.
|
||||
static WrenMethod* resumeTimer;
|
||||
|
||||
// Called by libuv when the timer has completed.
|
||||
static void timerCallback(uv_timer_t* handle)
|
||||
{
|
||||
WrenValue* fiber = (WrenValue*)handle->data;
|
||||
free(handle);
|
||||
|
||||
// Run the fiber that was sleeping.
|
||||
wrenCall(getVM(), resumeTimer, "v", fiber);
|
||||
wrenReleaseValue(getVM(), 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);
|
||||
|
||||
// Store the fiber to resume when the timer completes.
|
||||
uv_timer_t* handle = (uv_timer_t*)malloc(sizeof(uv_timer_t));
|
||||
handle->data = fiber;
|
||||
|
||||
uv_timer_init(getLoop(), handle);
|
||||
uv_timer_start(handle, timerCallback, milliseconds, 0);
|
||||
}
|
||||
|
||||
char* timerGetSource()
|
||||
{
|
||||
size_t length = strlen(timerLibSource);
|
||||
char* copy = malloc(length + 1);
|
||||
strncpy(copy, timerLibSource, length);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
WrenForeignMethodFn timerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature)
|
||||
{
|
||||
if (strcmp(className, "Timer") != 0) return NULL;
|
||||
|
||||
if (isStatic && strcmp(signature, "startTimer_(_,_)") == 0) return startTimer;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void timerReleaseMethods()
|
||||
{
|
||||
if (resumeTimer != NULL) wrenReleaseMethod(getVM(), resumeTimer);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef timer_h
|
||||
#define timer_h
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
// TODO: Coherent naming scheme.
|
||||
char* timerGetSource();
|
||||
|
||||
WrenForeignMethodFn timerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature);
|
||||
|
||||
void timerReleaseMethods();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
class Timer {
|
||||
static sleep(milliseconds) {
|
||||
startTimer_(milliseconds, Fiber.current)
|
||||
Fiber.yield()
|
||||
}
|
||||
|
||||
foreign static startTimer_(milliseconds, fiber)
|
||||
|
||||
// Called by native code.
|
||||
static resumeTimer_(fiber) {
|
||||
fiber.run()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user