mirror of
https://github.com/janet-lang/janet
synced 2025-06-03 15:14:13 +00:00
Merge branch 'master' into ev
This commit is contained in:
commit
30522bbf7d
@ -3,7 +3,13 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
## Unreleased - ???
|
## Unreleased - ???
|
||||||
- Silence warnings in some compilers.
|
- Silence warnings in some compilers.
|
||||||
|
- Change `net/read`, `net/chunk`, and `net/write` to raise errors in the case of failures.
|
||||||
|
- Add `janet_continue_signal` to C API. This indirectly enables C functions that yield to the event loop
|
||||||
|
to raise errors or other signals.
|
||||||
- Update meson build script to fix bug on Debian's version of meson
|
- Update meson build script to fix bug on Debian's version of meson
|
||||||
|
- Add `xprint`, `xprin`, `xprintf`, and `xprinf`.
|
||||||
|
- `net/write` now raises an error message if write fails.
|
||||||
|
- Fix issue with SIGPIPE on macOS and BSDs.
|
||||||
|
|
||||||
## 1.11.3 - 2020-08-03
|
## 1.11.3 - 2020-08-03
|
||||||
- Add `JANET_HASHSEED` environment variable when `JANET_PRF` is enabled.
|
- Add `JANET_HASHSEED` environment variable when `JANET_PRF` is enabled.
|
||||||
|
@ -15,6 +15,6 @@
|
|||||||
(let [server (net/server "127.0.0.1" "8000")]
|
(let [server (net/server "127.0.0.1" "8000")]
|
||||||
(print "Starting echo server on 127.0.0.1:8000")
|
(print "Starting echo server on 127.0.0.1:8000")
|
||||||
(forever
|
(forever
|
||||||
(if-let [conn (:accept server 2.8)]
|
(if-let [conn (:accept server)]
|
||||||
(ev/call handler conn)
|
(ev/call handler conn)
|
||||||
(print "no new connections"))))
|
(print "no new connections"))))
|
||||||
|
@ -1804,14 +1804,16 @@
|
|||||||
(defn expandqq [t]
|
(defn expandqq [t]
|
||||||
(defn qq [x]
|
(defn qq [x]
|
||||||
(case (type x)
|
(case (type x)
|
||||||
:tuple (do
|
:tuple (if (= :brackets (tuple/type x))
|
||||||
(def x0 (in x 0))
|
~[,;(map qq x)]
|
||||||
(if (or (= 'unquote x0) (= 'unquote-splicing x0))
|
(do
|
||||||
(tuple x0 (recur (in x 1)))
|
(def x0 (get x 0))
|
||||||
(tuple/slice (map qq x))))
|
(if (= 'unquote x0)
|
||||||
|
(tuple x0 (recur (get x 1)))
|
||||||
|
(tuple/slice (map qq x)))))
|
||||||
:array (map qq x)
|
:array (map qq x)
|
||||||
:table (table (map qq (kvs x)))
|
:table (table ;(map qq (kvs x)))
|
||||||
:struct (struct (map qq (kvs x)))
|
:struct (struct ;(map qq (kvs x)))
|
||||||
x))
|
x))
|
||||||
(tuple (in t 0) (qq (in t 1))))
|
(tuple (in t 0) (qq (in t 1))))
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ typedef struct JanetTask JanetTask;
|
|||||||
struct JanetTask {
|
struct JanetTask {
|
||||||
JanetFiber *fiber;
|
JanetFiber *fiber;
|
||||||
Janet value;
|
Janet value;
|
||||||
|
JanetSignal sig;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Min priority queue of timestamps for timeouts. */
|
/* Min priority queue of timestamps for timeouts. */
|
||||||
@ -121,6 +122,7 @@ typedef struct JanetTimeout JanetTimeout;
|
|||||||
struct JanetTimeout {
|
struct JanetTimeout {
|
||||||
JanetTimestamp when;
|
JanetTimestamp when;
|
||||||
JanetFiber *fiber;
|
JanetFiber *fiber;
|
||||||
|
int is_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
@ -300,8 +302,25 @@ void janet_pollable_deinit(JanetPollable *pollable) {
|
|||||||
pollable->state = NULL;
|
pollable->state = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cancel any state machines waiting on this fiber. */
|
/* Register a fiber to resume with value */
|
||||||
void janet_cancel(JanetFiber *fiber) {
|
void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig) {
|
||||||
|
if (fiber->flags & JANET_FIBER_FLAG_SCHEDULED) return;
|
||||||
|
fiber->flags |= JANET_FIBER_FLAG_SCHEDULED;
|
||||||
|
fiber->sched_id++;
|
||||||
|
JanetTask t = { fiber, value, sig };
|
||||||
|
janet_q_push(&janet_vm_spawn, &t, sizeof(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_cancel(JanetFiber *fiber, Janet value) {
|
||||||
|
janet_schedule_signal(fiber, value, JANET_SIGNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_schedule(JanetFiber *fiber, Janet value) {
|
||||||
|
janet_schedule_signal(fiber, value, JANET_SIGNAL_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_fiber_did_resume(JanetFiber *fiber) {
|
||||||
|
/* Cancel any pending fibers */
|
||||||
if (fiber->waiting) janet_unlisten(fiber->waiting);
|
if (fiber->waiting) janet_unlisten(fiber->waiting);
|
||||||
if (fiber->timeout_index >= 0) {
|
if (fiber->timeout_index >= 0) {
|
||||||
pop_timeout(fiber->timeout_index);
|
pop_timeout(fiber->timeout_index);
|
||||||
@ -309,15 +328,6 @@ void janet_cancel(JanetFiber *fiber) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register a fiber to resume with value */
|
|
||||||
void janet_schedule(JanetFiber *fiber, Janet value) {
|
|
||||||
if (fiber->flags & JANET_FIBER_FLAG_SCHEDULED) return;
|
|
||||||
fiber->flags |= JANET_FIBER_FLAG_SCHEDULED;
|
|
||||||
fiber->sched_id++;
|
|
||||||
JanetTask t = { fiber, value };
|
|
||||||
janet_q_push(&janet_vm_spawn, &t, sizeof(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark all pending tasks */
|
/* Mark all pending tasks */
|
||||||
void janet_ev_mark(void) {
|
void janet_ev_mark(void) {
|
||||||
JanetTask *tasks = janet_vm_spawn.data;
|
JanetTask *tasks = janet_vm_spawn.data;
|
||||||
@ -342,10 +352,10 @@ void janet_ev_mark(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Run a top level task */
|
/* Run a top level task */
|
||||||
static void run_one(JanetFiber *fiber, Janet value) {
|
static void run_one(JanetFiber *fiber, Janet value, JanetSignal sigin) {
|
||||||
fiber->flags &= ~JANET_FIBER_FLAG_SCHEDULED;
|
fiber->flags &= ~JANET_FIBER_FLAG_SCHEDULED;
|
||||||
Janet res;
|
Janet res;
|
||||||
JanetSignal sig = janet_continue(fiber, value, &res);
|
JanetSignal sig = janet_continue_signal(fiber, value, &res, sigin);
|
||||||
if (sig != JANET_SIGNAL_OK && sig != JANET_SIGNAL_EVENT) {
|
if (sig != JANET_SIGNAL_OK && sig != JANET_SIGNAL_EVENT) {
|
||||||
janet_stacktrace(fiber, res);
|
janet_stacktrace(fiber, res);
|
||||||
}
|
}
|
||||||
@ -377,6 +387,7 @@ void janet_addtimeout(double sec) {
|
|||||||
JanetTimeout to;
|
JanetTimeout to;
|
||||||
to.when = ts_delta(ts_now(), sec);
|
to.when = ts_delta(ts_now(), sec);
|
||||||
to.fiber = fiber;
|
to.fiber = fiber;
|
||||||
|
to.is_error = 1;
|
||||||
add_timeout(to);
|
add_timeout(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,9 +606,9 @@ void janet_loop(void) {
|
|||||||
}
|
}
|
||||||
/* Run scheduled fibers */
|
/* Run scheduled fibers */
|
||||||
while (janet_vm_spawn.head != janet_vm_spawn.tail) {
|
while (janet_vm_spawn.head != janet_vm_spawn.tail) {
|
||||||
JanetTask task = {NULL, janet_wrap_nil()};
|
JanetTask task = {NULL, janet_wrap_nil(), JANET_SIGNAL_OK};
|
||||||
janet_q_pop(&janet_vm_spawn, &task, sizeof(task));
|
janet_q_pop(&janet_vm_spawn, &task, sizeof(task));
|
||||||
run_one(task.fiber, task.value);
|
run_one(task.fiber, task.value, task.sig);
|
||||||
}
|
}
|
||||||
/* Poll for events */
|
/* Poll for events */
|
||||||
if (janet_vm_active_listeners || janet_vm_tq_count) {
|
if (janet_vm_active_listeners || janet_vm_tq_count) {
|
||||||
@ -707,7 +718,11 @@ void janet_loop1_impl(void) {
|
|||||||
/* Timer event */
|
/* Timer event */
|
||||||
pop_timeout(0);
|
pop_timeout(0);
|
||||||
/* Cancel waiters for this fiber */
|
/* Cancel waiters for this fiber */
|
||||||
janet_schedule(to.fiber, janet_wrap_nil());
|
if (to.is_error) {
|
||||||
|
janet_cancel(to.fiber, janet_cstringv("timeout"));
|
||||||
|
} else {
|
||||||
|
janet_schedule(to.fiber, janet_wrap_nil());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Normal event */
|
/* Normal event */
|
||||||
int mask = events[i].events;
|
int mask = events[i].events;
|
||||||
@ -784,6 +799,7 @@ static Janet cfun_ev_sleep(int32_t argc, Janet *argv) {
|
|||||||
JanetTimeout to;
|
JanetTimeout to;
|
||||||
to.when = ts_delta(ts_now(), sec);
|
to.when = ts_delta(ts_now(), sec);
|
||||||
to.fiber = janet_vm_root_fiber;
|
to.fiber = janet_vm_root_fiber;
|
||||||
|
to.is_error = 0;
|
||||||
add_timeout(to);
|
add_timeout(to);
|
||||||
janet_await();
|
janet_await();
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,15 @@
|
|||||||
#ifndef JANET_FEATURES_H_defined
|
#ifndef JANET_FEATURES_H_defined
|
||||||
#define JANET_FEATURES_H_defined
|
#define JANET_FEATURES_H_defined
|
||||||
|
|
||||||
#ifndef _POSIX_C_SOURCE
|
#if defined(__NetBSD__) || defined(__APPLE__) || defined(__OpenBSD__) \
|
||||||
#define _POSIX_C_SOURCE 200809L
|
|| defined(__bsdi__) || defined(__DragonFly__)
|
||||||
|
/* Use BSD soucre on any BSD systems, include OSX */
|
||||||
|
# define _BSD_SOURCE
|
||||||
|
#else
|
||||||
|
/* Use POSIX feature flags */
|
||||||
|
# ifndef _POSIX_C_SOURCE
|
||||||
|
# define _POSIX_C_SOURCE 200809L
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(WIN32) || defined(_WIN32)
|
#if defined(WIN32) || defined(_WIN32)
|
||||||
|
@ -46,8 +46,9 @@
|
|||||||
#define JANET_FIBER_MASK_USERN(N) (16 << (N))
|
#define JANET_FIBER_MASK_USERN(N) (16 << (N))
|
||||||
#define JANET_FIBER_MASK_USER 0x3FF0
|
#define JANET_FIBER_MASK_USER 0x3FF0
|
||||||
|
|
||||||
#define JANET_FIBER_STATUS_MASK 0x7F0000
|
#define JANET_FIBER_STATUS_MASK 0x3F0000
|
||||||
#define JANET_FIBER_FLAG_SCHEDULED 0x800000
|
#define JANET_FIBER_FLAG_SCHEDULED 0x800000
|
||||||
|
#define JANET_FIBER_RESUME_SIGNAL 0x400000
|
||||||
#define JANET_FIBER_STATUS_OFFSET 16
|
#define JANET_FIBER_STATUS_OFFSET 16
|
||||||
|
|
||||||
#define JANET_FIBER_BREAKPOINT 0x1000000
|
#define JANET_FIBER_BREAKPOINT 0x1000000
|
||||||
@ -77,4 +78,8 @@ void janet_fiber_popframe(JanetFiber *fiber);
|
|||||||
void janet_env_maybe_detach(JanetFuncEnv *env);
|
void janet_env_maybe_detach(JanetFuncEnv *env);
|
||||||
int janet_env_valid(JanetFuncEnv *env);
|
int janet_env_valid(JanetFuncEnv *env);
|
||||||
|
|
||||||
|
#ifdef JANET_EV
|
||||||
|
void janet_fiber_did_resume(JanetFiber *fiber);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -391,18 +391,16 @@ FILE *janet_dynfile(const char *name, FILE *def) {
|
|||||||
return iofile->file;
|
return iofile->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
static Janet cfun_io_print_impl_x(int32_t argc, Janet *argv, int newline,
|
||||||
int newline, const char *name, FILE *dflt_file) {
|
FILE *dflt_file, int32_t offset, Janet x) {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
Janet x = janet_dyn(name);
|
|
||||||
switch (janet_type(x)) {
|
switch (janet_type(x)) {
|
||||||
default:
|
default:
|
||||||
/* Other values simply do nothing */
|
janet_panicf("cannot print to %v", x);
|
||||||
return janet_wrap_nil();
|
|
||||||
case JANET_BUFFER: {
|
case JANET_BUFFER: {
|
||||||
/* Special case buffer */
|
/* Special case buffer */
|
||||||
JanetBuffer *buf = janet_unwrap_buffer(x);
|
JanetBuffer *buf = janet_unwrap_buffer(x);
|
||||||
for (int32_t i = 0; i < argc; ++i) {
|
for (int32_t i = offset; i < argc; ++i) {
|
||||||
janet_to_string_b(buf, argv[i]);
|
janet_to_string_b(buf, argv[i]);
|
||||||
}
|
}
|
||||||
if (newline)
|
if (newline)
|
||||||
@ -411,6 +409,7 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
|||||||
}
|
}
|
||||||
case JANET_NIL:
|
case JANET_NIL:
|
||||||
f = dflt_file;
|
f = dflt_file;
|
||||||
|
if (f == NULL) janet_panic("cannot print to nil");
|
||||||
break;
|
break;
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
@ -421,7 +420,7 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int32_t i = 0; i < argc; ++i) {
|
for (int32_t i = offset; i < argc; ++i) {
|
||||||
int32_t len;
|
int32_t len;
|
||||||
const uint8_t *vstr;
|
const uint8_t *vstr;
|
||||||
if (janet_checktype(argv[i], JANET_BUFFER)) {
|
if (janet_checktype(argv[i], JANET_BUFFER)) {
|
||||||
@ -434,7 +433,11 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
|||||||
}
|
}
|
||||||
if (len) {
|
if (len) {
|
||||||
if (1 != fwrite(vstr, len, 1, f)) {
|
if (1 != fwrite(vstr, len, 1, f)) {
|
||||||
janet_panicf("could not print %d bytes to (dyn :%s)", len, name);
|
if (f == dflt_file) {
|
||||||
|
janet_panicf("cannot print %d bytes", len);
|
||||||
|
} else {
|
||||||
|
janet_panicf("cannot print %d bytes to %v", len, x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,6 +446,13 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
|||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
|
||||||
|
int newline, const char *name, FILE *dflt_file) {
|
||||||
|
Janet x = janet_dyn(name);
|
||||||
|
return cfun_io_print_impl_x(argc, argv, newline, dflt_file, 0, x);
|
||||||
|
}
|
||||||
|
|
||||||
static Janet cfun_io_print(int32_t argc, Janet *argv) {
|
static Janet cfun_io_print(int32_t argc, Janet *argv) {
|
||||||
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
|
return cfun_io_print_impl(argc, argv, 1, "out", stdout);
|
||||||
}
|
}
|
||||||
@ -459,25 +469,33 @@ static Janet cfun_io_eprin(int32_t argc, Janet *argv) {
|
|||||||
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
|
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
static Janet cfun_io_xprint(int32_t argc, Janet *argv) {
|
||||||
const char *name, FILE *dflt_file) {
|
|
||||||
FILE *f;
|
|
||||||
janet_arity(argc, 1, -1);
|
janet_arity(argc, 1, -1);
|
||||||
const char *fmt = janet_getcstring(argv, 0);
|
return cfun_io_print_impl_x(argc, argv, 1, NULL, 1, argv[0]);
|
||||||
Janet x = janet_dyn(name);
|
}
|
||||||
|
|
||||||
|
static Janet cfun_io_xprin(int32_t argc, Janet *argv) {
|
||||||
|
janet_arity(argc, 1, -1);
|
||||||
|
return cfun_io_print_impl_x(argc, argv, 0, NULL, 1, argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
|
||||||
|
FILE *dflt_file, int32_t offset, Janet x) {
|
||||||
|
FILE *f;
|
||||||
|
const char *fmt = janet_getcstring(argv, offset);
|
||||||
switch (janet_type(x)) {
|
switch (janet_type(x)) {
|
||||||
default:
|
default:
|
||||||
/* Other values simply do nothing */
|
janet_panicf("cannot print to %v", x);
|
||||||
return janet_wrap_nil();
|
|
||||||
case JANET_BUFFER: {
|
case JANET_BUFFER: {
|
||||||
/* Special case buffer */
|
/* Special case buffer */
|
||||||
JanetBuffer *buf = janet_unwrap_buffer(x);
|
JanetBuffer *buf = janet_unwrap_buffer(x);
|
||||||
janet_buffer_format(buf, fmt, 0, argc, argv);
|
janet_buffer_format(buf, fmt, offset, argc, argv);
|
||||||
if (newline) janet_buffer_push_u8(buf, '\n');
|
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
case JANET_NIL:
|
case JANET_NIL:
|
||||||
f = dflt_file;
|
f = dflt_file;
|
||||||
|
if (f == NULL) janet_panic("cannot print to nil");
|
||||||
break;
|
break;
|
||||||
case JANET_ABSTRACT: {
|
case JANET_ABSTRACT: {
|
||||||
void *abstract = janet_unwrap_abstract(x);
|
void *abstract = janet_unwrap_abstract(x);
|
||||||
@ -489,11 +507,11 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
JanetBuffer *buf = janet_buffer(10);
|
JanetBuffer *buf = janet_buffer(10);
|
||||||
janet_buffer_format(buf, fmt, 0, argc, argv);
|
janet_buffer_format(buf, fmt, offset, argc, argv);
|
||||||
if (newline) janet_buffer_push_u8(buf, '\n');
|
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||||
if (buf->count) {
|
if (buf->count) {
|
||||||
if (1 != fwrite(buf->data, buf->count, 1, f)) {
|
if (1 != fwrite(buf->data, buf->count, 1, f)) {
|
||||||
janet_panicf("could not print %d bytes to file", buf->count, name);
|
janet_panicf("could not print %d bytes to file", buf->count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Clear buffer to make things easier for GC */
|
/* Clear buffer to make things easier for GC */
|
||||||
@ -504,6 +522,14 @@ static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
|||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet cfun_io_printf_impl(int32_t argc, Janet *argv, int newline,
|
||||||
|
const char *name, FILE *dflt_file) {
|
||||||
|
janet_arity(argc, 1, -1);
|
||||||
|
Janet x = janet_dyn(name);
|
||||||
|
return cfun_io_printf_impl_x(argc, argv, newline, dflt_file, 0, x);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static Janet cfun_io_printf(int32_t argc, Janet *argv) {
|
static Janet cfun_io_printf(int32_t argc, Janet *argv) {
|
||||||
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
|
return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
|
||||||
}
|
}
|
||||||
@ -520,6 +546,16 @@ static Janet cfun_io_eprinf(int32_t argc, Janet *argv) {
|
|||||||
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
|
return cfun_io_printf_impl(argc, argv, 0, "err", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet cfun_io_xprintf(int32_t argc, Janet *argv) {
|
||||||
|
janet_arity(argc, 2, -1);
|
||||||
|
return cfun_io_printf_impl_x(argc, argv, 1, NULL, 1, argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_io_xprinf(int32_t argc, Janet *argv) {
|
||||||
|
janet_arity(argc, 2, -1);
|
||||||
|
return cfun_io_printf_impl_x(argc, argv, 0, NULL, 1, argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
static void janet_flusher(const char *name, FILE *dflt_file) {
|
static void janet_flusher(const char *name, FILE *dflt_file) {
|
||||||
Janet x = janet_dyn(name);
|
Janet x = janet_dyn(name);
|
||||||
switch (janet_type(x)) {
|
switch (janet_type(x)) {
|
||||||
@ -633,6 +669,29 @@ static const JanetReg io_cfuns[] = {
|
|||||||
JDOC("(eprinf fmt & xs)\n\n"
|
JDOC("(eprinf fmt & xs)\n\n"
|
||||||
"Like eprintf but with no trailing newline.")
|
"Like eprintf but with no trailing newline.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"xprint", cfun_io_xprint,
|
||||||
|
JDOC("(xprint to & xs)\n\n"
|
||||||
|
"Print to a file or other value explicitly (no dynamic bindings) with a trailing "
|
||||||
|
"newline character. The value to print "
|
||||||
|
"to is the first argument, and is otherwise the same as print. Returns nil.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"xprin", cfun_io_xprin,
|
||||||
|
JDOC("(xprin to & xs)\n\n"
|
||||||
|
"Print to a file or other value explicitly (no dynamic bindings). The value to print "
|
||||||
|
"to is the first argument, and is otherwise the same as prin. Returns nil.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"xprintf", cfun_io_xprintf,
|
||||||
|
JDOC("(xprint to fmt & xs)\n\n"
|
||||||
|
"Like printf but prints to an explicit file or value to. Returns nil.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"xprinf", cfun_io_xprinf,
|
||||||
|
JDOC("(xprin to fmt & xs)\n\n"
|
||||||
|
"Like prinf but prints to an explicit file or value to. Returns nil.")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"flush", cfun_io_flush,
|
"flush", cfun_io_flush,
|
||||||
JDOC("(flush)\n\n"
|
JDOC("(flush)\n\n"
|
||||||
|
@ -139,6 +139,18 @@ static int janet_stream_close(void *p, size_t s) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nosigpipe(JSock s) {
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
int enable = 1;
|
||||||
|
if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) < 0) {
|
||||||
|
JSOCKCLOSE(s);
|
||||||
|
janet_panic("setsockopt(SO_NOSIGPIPE) failed");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void) s;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int janet_stream_mark(void *p, size_t s) {
|
static int janet_stream_mark(void *p, size_t s) {
|
||||||
(void) s;
|
(void) s;
|
||||||
janet_pollable_mark((JanetPollable *) p);
|
janet_pollable_mark((JanetPollable *) p);
|
||||||
@ -166,8 +178,7 @@ JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event)
|
|||||||
janet_mark(janet_wrap_buffer(state->buf));
|
janet_mark(janet_wrap_buffer(state->buf));
|
||||||
break;
|
break;
|
||||||
case JANET_ASYNC_EVENT_CLOSE:
|
case JANET_ASYNC_EVENT_CLOSE:
|
||||||
/* Read is finished, even if chunk is incomplete */
|
janet_cancel(s->fiber, janet_cstringv("stream closed"));
|
||||||
janet_schedule(s->fiber, janet_wrap_nil());
|
|
||||||
return JANET_ASYNC_STATUS_DONE;
|
return JANET_ASYNC_STATUS_DONE;
|
||||||
case JANET_ASYNC_EVENT_READ:
|
case JANET_ASYNC_EVENT_READ:
|
||||||
/* Read in bytes */
|
/* Read in bytes */
|
||||||
@ -201,15 +212,23 @@ JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event)
|
|||||||
|
|
||||||
/* Resume if done */
|
/* Resume if done */
|
||||||
if (!state->is_chunk || bytes_left == 0) {
|
if (!state->is_chunk || bytes_left == 0) {
|
||||||
|
JanetSignal sig = JANET_SIGNAL_OK;
|
||||||
Janet resume_val;
|
Janet resume_val;
|
||||||
if (state->is_recv_from) {
|
if (state->is_recv_from) {
|
||||||
void *abst = janet_abstract(&AddressAT, socklen);
|
void *abst = janet_abstract(&AddressAT, socklen);
|
||||||
memcpy(abst, &saddr, socklen);
|
memcpy(abst, &saddr, socklen);
|
||||||
resume_val = janet_wrap_abstract(abst);
|
resume_val = janet_wrap_abstract(abst);
|
||||||
} else {
|
} else {
|
||||||
resume_val = nread > 0 ? janet_wrap_buffer(buffer) : janet_wrap_nil();
|
if (nread > 0) {
|
||||||
|
resume_val = janet_wrap_buffer(buffer);
|
||||||
|
} else {
|
||||||
|
sig = JANET_SIGNAL_ERROR;
|
||||||
|
resume_val = (nread == -1)
|
||||||
|
? janet_cstringv(strerror(JLASTERR))
|
||||||
|
: janet_cstringv("could not read");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
janet_schedule(s->fiber, resume_val);
|
janet_schedule_signal(s->fiber, resume_val, sig);
|
||||||
return JANET_ASYNC_STATUS_DONE;
|
return JANET_ASYNC_STATUS_DONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +296,7 @@ JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JANET_ASYNC_EVENT_CLOSE:
|
case JANET_ASYNC_EVENT_CLOSE:
|
||||||
janet_schedule(s->fiber, janet_wrap_nil());
|
janet_cancel(s->fiber, janet_cstringv("stream closed"));
|
||||||
return JANET_ASYNC_STATUS_DONE;
|
return JANET_ASYNC_STATUS_DONE;
|
||||||
case JANET_ASYNC_EVENT_WRITE: {
|
case JANET_ASYNC_EVENT_WRITE: {
|
||||||
int32_t start, len;
|
int32_t start, len;
|
||||||
@ -291,9 +310,9 @@ JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event)
|
|||||||
bytes = state->src.str;
|
bytes = state->src.str;
|
||||||
len = janet_string_length(bytes);
|
len = janet_string_length(bytes);
|
||||||
}
|
}
|
||||||
|
JReadInt nwrote = 0;
|
||||||
if (start < len) {
|
if (start < len) {
|
||||||
int32_t nbytes = len - start;
|
int32_t nbytes = len - start;
|
||||||
JReadInt nwrote;
|
|
||||||
do {
|
do {
|
||||||
void *dest_abst = state->dest_abst;
|
void *dest_abst = state->dest_abst;
|
||||||
if (dest_abst) {
|
if (dest_abst) {
|
||||||
@ -311,7 +330,13 @@ JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event)
|
|||||||
}
|
}
|
||||||
state->start = start;
|
state->start = start;
|
||||||
if (start >= len) {
|
if (start >= len) {
|
||||||
janet_schedule(s->fiber, janet_wrap_nil());
|
if (nwrote > 0) {
|
||||||
|
janet_schedule(s->fiber, janet_wrap_nil());
|
||||||
|
} else if (nwrote == 0) {
|
||||||
|
janet_cancel(s->fiber, janet_cstringv("could not write"));
|
||||||
|
} else {
|
||||||
|
janet_cancel(s->fiber, janet_cstringv(strerror(JLASTERR)));
|
||||||
|
}
|
||||||
return JANET_ASYNC_STATUS_DONE;
|
return JANET_ASYNC_STATUS_DONE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -370,6 +395,7 @@ JanetAsyncStatus net_machine_simple_server(JanetListenerState *s, JanetAsyncEven
|
|||||||
JSock connfd = accept(s->pollable->handle, NULL, NULL);
|
JSock connfd = accept(s->pollable->handle, NULL, NULL);
|
||||||
if (JSOCKVALID(connfd)) {
|
if (JSOCKVALID(connfd)) {
|
||||||
/* Made a new connection socket */
|
/* Made a new connection socket */
|
||||||
|
nosigpipe(connfd);
|
||||||
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||||
Janet streamv = janet_wrap_abstract(stream);
|
Janet streamv = janet_wrap_abstract(stream);
|
||||||
JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
|
JanetFiber *fiber = janet_fiber(state->function, 64, 1, &streamv);
|
||||||
@ -392,11 +418,12 @@ JanetAsyncStatus net_machine_accept(JanetListenerState *s, JanetAsyncEvent event
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case JANET_ASYNC_EVENT_CLOSE:
|
case JANET_ASYNC_EVENT_CLOSE:
|
||||||
janet_schedule(s->fiber, janet_wrap_nil());
|
janet_cancel(s->fiber, janet_cstringv("stream closed"));
|
||||||
return JANET_ASYNC_STATUS_DONE;
|
return JANET_ASYNC_STATUS_DONE;
|
||||||
case JANET_ASYNC_EVENT_READ: {
|
case JANET_ASYNC_EVENT_READ: {
|
||||||
JSock connfd = accept(s->pollable->handle, NULL, NULL);
|
JSock connfd = accept(s->pollable->handle, NULL, NULL);
|
||||||
if (JSOCKVALID(connfd)) {
|
if (JSOCKVALID(connfd)) {
|
||||||
|
nosigpipe(connfd);
|
||||||
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||||
Janet streamv = janet_wrap_abstract(stream);
|
Janet streamv = janet_wrap_abstract(stream);
|
||||||
janet_schedule(s->fiber, streamv);
|
janet_schedule(s->fiber, streamv);
|
||||||
@ -551,6 +578,8 @@ static Janet cfun_net_connect(int32_t argc, Janet *argv) {
|
|||||||
janet_panic("could not connect to socket");
|
janet_panic("could not connect to socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nosigpipe(sock);
|
||||||
|
|
||||||
/* Wrap socket in abstract type JanetStream */
|
/* Wrap socket in abstract type JanetStream */
|
||||||
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||||
return janet_wrap_abstract(stream);
|
return janet_wrap_abstract(stream);
|
||||||
@ -562,11 +591,6 @@ static const char *serverify_socket(JSock sfd) {
|
|||||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(int)) < 0) {
|
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(int)) < 0) {
|
||||||
return "setsockopt(SO_REUSEADDR) failed";
|
return "setsockopt(SO_REUSEADDR) failed";
|
||||||
}
|
}
|
||||||
#ifdef SO_NOSIGPIPE
|
|
||||||
if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) < 0) {
|
|
||||||
return "setsockopt(SO_NOSIGPIPE) failed";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
|
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
|
||||||
return "setsockopt(SO_REUSEPORT) failed";
|
return "setsockopt(SO_REUSEPORT) failed";
|
||||||
@ -620,6 +644,8 @@ static Janet cfun_net_server(int32_t argc, Janet *argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nosigpipe(sfd);
|
||||||
|
|
||||||
if (socktype == SOCK_DGRAM) {
|
if (socktype == SOCK_DGRAM) {
|
||||||
/* Datagram server (UDP) */
|
/* Datagram server (UDP) */
|
||||||
|
|
||||||
@ -807,7 +833,7 @@ static const JanetReg net_cfuns[] = {
|
|||||||
"Read up to n bytes from a stream, suspending the current fiber until the bytes are available. "
|
"Read up to n bytes from a stream, suspending the current fiber until the bytes are available. "
|
||||||
"If less than n bytes are available (and more than 0), will push those bytes and return early. "
|
"If less than n bytes are available (and more than 0), will push those bytes and return early. "
|
||||||
"Takes an optional timeout in seconds, after which will return nil. "
|
"Takes an optional timeout in seconds, after which will return nil. "
|
||||||
"Returns a buffer with up to n more bytes in it.")
|
"Returns a buffer with up to n more bytes in it, or raises an error if the read failed.")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"net/chunk", cfun_stream_chunk,
|
"net/chunk", cfun_stream_chunk,
|
||||||
@ -820,7 +846,7 @@ static const JanetReg net_cfuns[] = {
|
|||||||
JDOC("(net/write stream data &opt timeout)\n\n"
|
JDOC("(net/write stream data &opt timeout)\n\n"
|
||||||
"Write data to a stream, suspending the current fiber until the write "
|
"Write data to a stream, suspending the current fiber until the write "
|
||||||
"completes. Takes an optional timeout in seconds, after which will return nil. "
|
"completes. Takes an optional timeout in seconds, after which will return nil. "
|
||||||
"Returns stream.")
|
"Returns nil, or raises an error if the write failed.")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"net/send-to", cfun_stream_send_to,
|
"net/send-to", cfun_stream_send_to,
|
||||||
|
@ -564,6 +564,15 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
register Janet *stack;
|
register Janet *stack;
|
||||||
register uint32_t *pc;
|
register uint32_t *pc;
|
||||||
register JanetFunction *func;
|
register JanetFunction *func;
|
||||||
|
|
||||||
|
if (fiber->flags & JANET_FIBER_RESUME_SIGNAL) {
|
||||||
|
JanetSignal sig = (fiber->gc.flags & JANET_FIBER_STATUS_MASK) >> JANET_FIBER_STATUS_OFFSET;
|
||||||
|
fiber->gc.flags &= ~JANET_FIBER_STATUS_MASK;
|
||||||
|
fiber->flags &= ~(JANET_FIBER_RESUME_SIGNAL | JANET_FIBER_FLAG_MASK);
|
||||||
|
janet_vm_return_reg[0] = in;
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
vm_restore();
|
vm_restore();
|
||||||
|
|
||||||
if (fiber->flags & JANET_FIBER_DID_LONGJUMP) {
|
if (fiber->flags & JANET_FIBER_DID_LONGJUMP) {
|
||||||
@ -801,6 +810,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
|||||||
vm_pcnext();
|
vm_pcnext();
|
||||||
|
|
||||||
VM_OP(JOP_NEXT)
|
VM_OP(JOP_NEXT)
|
||||||
|
vm_commit();
|
||||||
stack[A] = janet_next(stack[B], stack[C]);
|
stack[A] = janet_next(stack[B], stack[C]);
|
||||||
vm_pcnext();
|
vm_pcnext();
|
||||||
|
|
||||||
@ -1287,7 +1297,7 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
|||||||
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
JanetFiberStatus old_status = janet_fiber_status(fiber);
|
||||||
|
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
janet_cancel(fiber);
|
janet_fiber_did_resume(fiber);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Continue child fiber if it exists */
|
/* Continue child fiber if it exists */
|
||||||
@ -1370,6 +1380,20 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
|||||||
return janet_continue_no_check(fiber, in, out);
|
return janet_continue_no_check(fiber, in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enter the main vm loop but immediately raise a signal */
|
||||||
|
JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig) {
|
||||||
|
JanetSignal tmp_signal = janet_check_can_resume(fiber, out);
|
||||||
|
if (tmp_signal) return tmp_signal;
|
||||||
|
if (sig != JANET_SIGNAL_OK) {
|
||||||
|
JanetFiber *child = fiber;
|
||||||
|
while (child->child) child = child->child;
|
||||||
|
child->gc.flags &= ~JANET_FIBER_STATUS_MASK;
|
||||||
|
child->gc.flags |= sig << JANET_FIBER_STATUS_OFFSET;
|
||||||
|
child->flags |= JANET_FIBER_RESUME_SIGNAL;
|
||||||
|
}
|
||||||
|
return janet_continue_no_check(fiber, in, out);
|
||||||
|
}
|
||||||
|
|
||||||
JanetSignal janet_pcall(
|
JanetSignal janet_pcall(
|
||||||
JanetFunction *fun,
|
JanetFunction *fun,
|
||||||
int32_t argc,
|
int32_t argc,
|
||||||
|
@ -1217,6 +1217,8 @@ JANET_API void janet_pollable_deinit(JanetPollable *pollable);
|
|||||||
|
|
||||||
/* Queue a fiber to run on the event loop */
|
/* Queue a fiber to run on the event loop */
|
||||||
JANET_API void janet_schedule(JanetFiber *fiber, Janet value);
|
JANET_API void janet_schedule(JanetFiber *fiber, Janet value);
|
||||||
|
JANET_API void janet_cancel(JanetFiber *fiber, Janet value);
|
||||||
|
JANET_API void janet_schedule_signal(JanetFiber *fiber, Janet value, JanetSignal sig);
|
||||||
|
|
||||||
/* Start a state machine listening for events from a pollable */
|
/* Start a state machine listening for events from a pollable */
|
||||||
JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior, int mask, size_t size);
|
JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior, int mask, size_t size);
|
||||||
@ -1224,10 +1226,6 @@ JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListene
|
|||||||
/* Shorthand for yielding to event loop in C */
|
/* Shorthand for yielding to event loop in C */
|
||||||
JANET_NO_RETURN JANET_API void janet_await(void);
|
JANET_NO_RETURN JANET_API void janet_await(void);
|
||||||
|
|
||||||
/* Cancel a waiting fiber. Will notify the canceled state machines, but will not
|
|
||||||
* unwind the fiber. */
|
|
||||||
void janet_cancel(JanetFiber *fiber);
|
|
||||||
|
|
||||||
/* For use inside listeners - adds a timeout to the current fiber, such that
|
/* For use inside listeners - adds a timeout to the current fiber, such that
|
||||||
* it will be resumed after sec seconds if no other event schedules the current fiber. */
|
* it will be resumed after sec seconds if no other event schedules the current fiber. */
|
||||||
void janet_addtimeout(double sec);
|
void janet_addtimeout(double sec);
|
||||||
@ -1500,6 +1498,7 @@ JANET_API int janet_symeq(Janet x, const char *cstring);
|
|||||||
JANET_API int janet_init(void);
|
JANET_API int janet_init(void);
|
||||||
JANET_API void janet_deinit(void);
|
JANET_API void janet_deinit(void);
|
||||||
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
|
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
|
||||||
|
JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig);
|
||||||
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
|
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
|
||||||
JANET_API JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out);
|
JANET_API JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out);
|
||||||
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);
|
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);
|
||||||
|
@ -34,4 +34,14 @@
|
|||||||
(assert (= nil (index-of 10 @[])) "index-of 10")
|
(assert (= nil (index-of 10 @[])) "index-of 10")
|
||||||
(assert (= nil (index-of 10 @[1 2 3])) "index-of 11")
|
(assert (= nil (index-of 10 @[1 2 3])) "index-of 11")
|
||||||
|
|
||||||
|
# Regression
|
||||||
|
(assert (= {:x 10} (|(let [x $] ~{:x ,x}) 10)) "issue 463")
|
||||||
|
|
||||||
|
# macex testing
|
||||||
|
(assert (deep= (macex1 '~{1 2 3 4}) '~{1 2 3 4}) "macex1 qq struct")
|
||||||
|
(assert (deep= (macex1 '~@{1 2 3 4}) '~@{1 2 3 4}) "macex1 qq table")
|
||||||
|
(assert (deep= (macex1 '~(1 2 3 4)) '~[1 2 3 4]) "macex1 qq tuple")
|
||||||
|
(assert (= :brackets (tuple/type (1 (macex1 '~[1 2 3 4])))) "macex1 qq bracket tuple")
|
||||||
|
(assert (deep= (macex1 '~@[1 2 3 4 ,blah]) '~@[1 2 3 4 ,blah]) "macex1 qq array")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user