Skip to content

Commit

Permalink
Allow iterating over fibers with each and similar.
Browse files Browse the repository at this point in the history
  • Loading branch information
bakpakin committed Jan 3, 2021
1 parent ecc6eb7 commit c357af0
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 7 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020 Calvin Rose
# Copyright (c) 2021 Calvin Rose
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
Expand Down Expand Up @@ -27,7 +27,7 @@ PREFIX?=/usr/local
INCLUDEDIR?=$(PREFIX)/include
BINDIR?=$(PREFIX)/bin
LIBDIR?=$(PREFIX)/lib
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n &>2 /dev/null || echo local)\""
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 2> /dev/null || echo local)\""
CLIBS=-lm -lpthread
JANET_TARGET=build/janet
JANET_LIBRARY=build/libjanet.so
Expand Down
28 changes: 28 additions & 0 deletions examples/iterate-fiber.janet
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
(def f
(coro
(for i 0 10
(yield (string "yield " i))
(os/sleep 0))))

(print "simple yielding")
(each item f (print "got: " item ", now " (fiber/status f)))

(def f
(coro
(for i 0 10
(yield (string "yield " i))
(ev/sleep 0))))

(print "old style fiber iteration")
(eachy item f (print "got: " item ", now " (fiber/status f)))

(def f
(coro
(for i 0 10
(yield (string "yield " i))
(ev/sleep 0))))

(print "complex yielding")
(each item f (print "got: " item ", now " (fiber/status f)))

(print (fiber/status f))
2 changes: 1 addition & 1 deletion src/core/ev.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2021 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
Expand Down
14 changes: 13 additions & 1 deletion src/core/fiber.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2021 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
Expand Down Expand Up @@ -37,6 +37,7 @@ static void fiber_reset(JanetFiber *fiber) {
fiber->child = NULL;
fiber->flags = JANET_FIBER_MASK_YIELD | JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP;
fiber->env = NULL;
fiber->last_value = janet_wrap_nil();
#ifdef JANET_EV
fiber->waiting = NULL;
fiber->sched_id = 0;
Expand Down Expand Up @@ -586,6 +587,12 @@ static Janet cfun_fiber_can_resume(int32_t argc, Janet *argv) {
return janet_wrap_boolean(!isFinished);
}

static Janet cfun_fiber_last_value(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1);
JanetFiber *fiber = janet_getfiber(argv, 0);
return fiber->last_value;
}

static const JanetReg fiber_cfuns[] = {
{
"fiber/new", cfun_fiber_new,
Expand Down Expand Up @@ -663,6 +670,11 @@ static const JanetReg fiber_cfuns[] = {
JDOC("(fiber/can-resume? fiber)\n\n"
"Check if a fiber is finished and cannot be resumed.")
},
{
"fiber/last-value", cfun_fiber_last_value,
JDOC("(fiber/last-value\n\n"
"Get the last value returned or signaled from the fiber.")
},
{NULL, NULL, NULL}
};

Expand Down
2 changes: 2 additions & 0 deletions src/core/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ static void janet_mark_fiber(JanetFiber *fiber) {
return;
janet_gc_mark(fiber);

janet_mark(fiber->last_value);

/* Mark values on the argument stack */
janet_mark_many(fiber->data + fiber->stackstart,
fiber->stacktop - fiber->stackstart);
Expand Down
1 change: 1 addition & 0 deletions src/core/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ void janet_buffer_format(
int32_t argstart,
int32_t argc,
Janet *argv);
Janet janet_next_impl(Janet ds, Janet key, int is_interpreter);

/* Inside the janet core, defining globals is different
* at bootstrap time and normal runtime */
Expand Down
69 changes: 68 additions & 1 deletion src/core/value.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2021 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
Expand All @@ -25,6 +25,7 @@
#include "util.h"
#include "state.h"
#include "gc.h"
#include "fiber.h"
#include <janet.h>
#endif

Expand Down Expand Up @@ -115,6 +116,10 @@ static int traversal_next(Janet *x, Janet *y) {
*/

Janet janet_next(Janet ds, Janet key) {
return janet_next_impl(ds, key, 0);
}

Janet janet_next_impl(Janet ds, Janet key, int is_interpreter) {
JanetType t = janet_type(ds);
switch (t) {
default:
Expand Down Expand Up @@ -177,6 +182,44 @@ Janet janet_next(Janet ds, Janet key) {
if (NULL == at->next) break;
return at->next(abst, key);
}
case JANET_FIBER: {
JanetFiber *child = janet_unwrap_fiber(ds);
Janet retreg;
JanetFiberStatus status = janet_fiber_status(child);
if (status == JANET_STATUS_ALIVE ||
status == JANET_STATUS_DEAD ||
status == JANET_STATUS_ERROR ||
status == JANET_STATUS_USER0 ||
status == JANET_STATUS_USER1 ||
status == JANET_STATUS_USER2 ||
status == JANET_STATUS_USER3 ||
status == JANET_STATUS_USER4) {
return janet_wrap_nil();
}
janet_vm_fiber->child = child;
JanetSignal sig = janet_continue(child, janet_wrap_nil(), &retreg);
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
if (is_interpreter) {
janet_signalv(sig, retreg);
} else {
janet_vm_fiber->child = NULL;
janet_panicv(retreg);
}
}
janet_vm_fiber->child = NULL;
if (sig == JANET_SIGNAL_OK ||
sig == JANET_SIGNAL_ERROR ||
sig == JANET_SIGNAL_USER0 ||
sig == JANET_SIGNAL_USER1 ||
sig == JANET_SIGNAL_USER2 ||
sig == JANET_SIGNAL_USER3 ||
sig == JANET_SIGNAL_USER4) {
/* Fiber cannot be resumed, so discard last value. */
return janet_wrap_nil();
} else {
return janet_wrap_integer(0);
}
}
}
return janet_wrap_nil();
}
Expand Down Expand Up @@ -434,6 +477,14 @@ Janet janet_in(Janet ds, Janet key) {
}
break;
}
case JANET_FIBER: {
/* Bit of a hack to allow iterating over fibers. */
if (janet_equals(key, janet_wrap_integer(0))) {
return janet_unwrap_fiber(ds)->last_value;
} else {
janet_panicf("expected key 0, got %v", key);
}
}
}
return value;
}
Expand Down Expand Up @@ -489,6 +540,14 @@ Janet janet_get(Janet ds, Janet key) {
const JanetKV *st = janet_unwrap_struct(ds);
return janet_struct_get(st, key);
}
case JANET_FIBER: {
/* Bit of a hack to allow iterating over fibers. */
if (janet_equals(key, janet_wrap_integer(0))) {
return janet_unwrap_fiber(ds)->last_value;
} else {
return janet_wrap_nil();
}
}
}
}

Expand Down Expand Up @@ -545,6 +604,14 @@ Janet janet_getindex(Janet ds, int32_t index) {
}
break;
}
case JANET_FIBER: {
if (index == 0) {
value = janet_unwrap_fiber(ds)->last_value;
} else {
value = janet_wrap_nil();
}
break;
}
}
return value;
}
Expand Down
32 changes: 30 additions & 2 deletions src/core/vm.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Calvin Rose
* Copyright (c) 2021 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
Expand Down Expand Up @@ -815,7 +815,11 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {

VM_OP(JOP_NEXT)
vm_commit();
stack[A] = janet_next(stack[B], stack[C]);
{
Janet temp = janet_next_impl(stack[B], stack[C], 1);
vm_restore();
stack[A] = temp;
}
vm_pcnext();

VM_OP(JOP_LOAD_NIL)
Expand Down Expand Up @@ -1341,10 +1345,14 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
janet_fiber_did_resume(fiber);
#endif

/* Clear last value */
fiber->last_value = janet_wrap_nil();

/* Continue child fiber if it exists */
if (fiber->child) {
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
JanetFiber *child = fiber->child;
uint32_t instr = (janet_stack_frame(fiber->data + fiber->frame)->pc)[0];
janet_vm_stackn++;
JanetSignal sig = janet_continue(child, in, &in);
janet_vm_stackn--;
Expand All @@ -1353,6 +1361,25 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
*out = in;
return sig;
}
/* Check if we need any special handling for certain opcodes */
switch (instr & 0x7F) {
default:
break;
case JOP_NEXT: {
if (sig == JANET_SIGNAL_OK ||
sig == JANET_SIGNAL_ERROR ||
sig == JANET_SIGNAL_USER0 ||
sig == JANET_SIGNAL_USER1 ||
sig == JANET_SIGNAL_USER2 ||
sig == JANET_SIGNAL_USER3 ||
sig == JANET_SIGNAL_USER4) {
in = janet_wrap_nil();
} else {
in = janet_wrap_integer(0);
}
break;
}
}
fiber->child = NULL;
}

Expand Down Expand Up @@ -1384,6 +1411,7 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
janet_fiber_set_status(fiber, signal);
janet_restore(&tstate);
fiber->last_value = tstate.payload;
*out = tstate.payload;

return signal;
Expand Down
1 change: 1 addition & 0 deletions src/include/janet.h
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,7 @@ struct JanetFiber {
JanetTable *env; /* Dynamic bindings table (usually current environment). */
Janet *data; /* Dynamically resized stack memory */
JanetFiber *child; /* Keep linked list of fibers for restarting pending fibers */
Janet last_value; /* Last returned value from a fiber */
#ifdef JANET_EV
JanetListenerState *waiting;
uint32_t sched_id; /* Increment everytime fiber is scheduled by event loop */
Expand Down

0 comments on commit c357af0

Please sign in to comment.