Working 'sleep' command and 'timer' queue example.

parent 6785e65c
......@@ -22,10 +22,10 @@ main: $(MAKEHEADERS) $(HEADERS) $(DEPOBJS) $(OBJS)
$(MAKEHEADERS): makeheaders.c
gcc makeheaders.c -o makeheaders
%.h: $(SRC)
%.h: %.c
./makeheaders src/*.c
%.o: %.c
%.o: %.c %.h
$(CC) $< -c -o $@ $(CFLAGS)
clean:
......
function (compareFunction, arr, element) {
// Lol. Efficiency could be improved, but this is most obviously correct.
arr.push(item);
arr.sort(compareFunction);
}
function () {
return function (compareFunction, arr, element) {
// Lol. Efficiency could be improved, but this is most obviously correct.
arr.push(element);
arr.sort(compareFunction);
}
}
function (print) {
return function () {
print((new Date()).toString());
}
}
function (args) {
var env = args.environ;
var argv = args.argv;
var modules = args.modules;
var Queues = args.Queues;
var timers = Queues.timers;
var compile = modules.compile;
var printTime = compile('printTime.js')(modules.print);
var orderedInsert = compile('orderedInsert.js')();
var byMstimestampAscending = function (a, b) {
return a.t - b.t;
}
var scheduleCallback = function (mstimestamp, callback) {
orderedInsert(byMstimestampAscending, timers, {t: mstimestamp, cb: callback});
}
printTime();
var now = Math.trunc(Date.now() / 1000) * 1000;
// Queue some events
scheduleCallback(now + 4000, printTime);
scheduleCallback(now + 2000, printTime);
scheduleCallback(now + 8000, printTime);
// It is a **very** basic event loop.
while (1) {
if (timers.length === 0) break;
// Dequeue
var event = timers.shift();
// Schedule next event (TODO: allow/handle waking up prematurely via an interupt)
modules.sleep(event.t - Date.now());
// Run synchronously (for now)
event.cb();
}
return
}
function (timers) {
/**
* Inserts a callback into the timers queue s.t. the timers queue is
* chronologically ordered.
* @param {Number} mstimestamp [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
var scheduleCallback = function (mstimestamp, callback) {
orderedInsert(byMstimestampAscending, timers, [mstimestamp, callback]);
}
// Example polyfills for the browser/node functions with their lame argument order
var setTimeout = function (callback, ms) {
scheduleCallback(Date.now() + ms, callback);
}
var callThenReschedule = function (callback, ms) {
return function () {
callback();
setTimeout(callback, ms); // Is this really what ECMAScript does or does it account for drift?
}
}
var setInterval = function (callback, ms) {
scheduleCallback(Date.now() + ms, callThenReschedule(callback));
}
return {
setTimeout: setTimeout,
setInterval: setInterval,
scheduleCallback: scheduleCallback
}
}
......@@ -3,6 +3,7 @@ extern char **environ;
// Include dependencies
#include <string.h>
#include <stdio.h>
#ifdef _WIN32
// @see [1]
#include <io.h>
......@@ -21,6 +22,11 @@ int main(int argc, char *argv[] /* char *environ[] */) {
_setmode(0, _O_BINARY);
_setmode(1, _O_BINARY);
#endif
// In my experience, output buffering by default is surprising to most
// beginners. It's premature optimization. If users need buffering they
// are smart enough to implement that in their app.
setbuf(stdin, NULL);
setbuf(stdout, NULL);
if (argc < 2) {
printf("Usage: dukboot file-to-eval.js\n");
......@@ -70,6 +76,8 @@ int main(int argc, char *argv[] /* char *environ[] */) {
duk_put_prop_string(ctx, -2, "compile");
duk_push_c_function(ctx, app_assert_safe_path, 1);
duk_put_prop_string(ctx, -2, "assert_safe_path");
duk_push_c_function(ctx, native_sleep, 1);
duk_put_prop_string(ctx, -2, "sleep");
duk_put_prop_string(ctx, -2, "modules");
// Provide direct access to the event loop
duk_push_object(ctx);
......
#include <time.h>
#include <math.h>
#include <errno.h>
#include "duktape/duktape.h"
#include "native_sleep.h"
// Takes its parameter in milliseconds, but
// supports sub-millisecond accuracy by accepting a float.
duk_int_t native_sleep (duk_context *ctx) {
duk_double_t ms = duk_get_number(ctx, -1);
duk_double_t sec = 0;
struct timespec t;
t.tv_nsec = (long) 1000000000 * modf(ms / 1000.0, &sec);
t.tv_sec = (time_t) sec;
int ret = nanosleep(&t, NULL);
if (ret) {
switch (errno) {
case EFAULT: return duk_generic_error(ctx, "System EFAULT");
break;
case EINVAL: return duk_range_error(ctx, "System EINVAL (hint: negative arguments to sleep() are invalid)");
break;
case EINTR: // TODO: Handle a signal interupt case
break;
}
}
return 0;
}
......@@ -8,7 +8,7 @@ for n in $(seq 2 $((NUM_CORES * 1))); do
EXPECT="$EXPECT
$EXPECT_ONE"
done
RESULT="$($DUKBOOT example/example.js)"
RESULT="$($DUKBOOT examples/tests/parent.js)"
echo "$EXPECT"
echo "---"
echo "$RESULT"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment