From 2c2ff588dfd0facf7c8a22645cc1974660f4e4cc Mon Sep 17 00:00:00 2001 From: Alex Shinn Date: Wed, 30 Dec 2015 14:07:50 +0900 Subject: [PATCH] Smarter polling in blocked output without threads, enable polling in blocked input. Fixes issue #295. --- include/chibi/features.h | 4 ++++ include/chibi/sexp.h | 11 +++++++++++ vm.c | 27 +++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/include/chibi/features.h b/include/chibi/features.h index d867019f..978a9385 100644 --- a/include/chibi/features.h +++ b/include/chibi/features.h @@ -684,6 +684,10 @@ #define SEXP_DEFAULT_EQUAL_BOUND 100000000 #endif +#ifndef SEXP_POLL_SLEEP_TIME +#define SEXP_POLL_SLEEP_TIME 5000 +#endif + #ifndef SEXP_USE_IMAGE_LOADING #define SEXP_USE_IMAGE_LOADING SEXP_USE_DL && !SEXP_USE_GLOBAL_HEAP && !SEXP_USE_BOEHM && !SEXP_USE_NO_FEATURES #endif diff --git a/include/chibi/sexp.h b/include/chibi/sexp.h index d67b3ccd..cbda4c92 100755 --- a/include/chibi/sexp.h +++ b/include/chibi/sexp.h @@ -21,6 +21,9 @@ extern "C" { #define sexp_isdigit(x) ((isdigit)((int)(x))) #define sexp_tolower(x) ((tolower)((int)(x))) #define sexp_toupper(x) ((toupper)((int)(x))) +#define SEXP_USE_POLL_PORT 0 +#define sexp_poll_input(ctx, port) usleep(SEXP_POLL_SLEEP_TIME) +#define sexp_poll_output(ctx, port) usleep(SEXP_POLL_SLEEP_TIME) #else #if SEXP_USE_DL #include @@ -31,6 +34,7 @@ extern "C" { #endif #if SEXP_USE_GREEN_THREADS #include +#include #include #include #endif @@ -39,6 +43,9 @@ extern "C" { #define sexp_isdigit(x) (isdigit(x)) #define sexp_tolower(x) (tolower(x)) #define sexp_toupper(x) (toupper(x)) +#define SEXP_USE_POLL_PORT 1 +#define sexp_poll_input(ctx, port) sexp_poll_port(ctx, port, 1) +#define sexp_poll_output(ctx, port) sexp_poll_port(ctx, port, 0) #endif #if SEXP_USE_GC_FILE_DESCRIPTORS @@ -1586,6 +1593,10 @@ SEXP_API sexp sexp_finalize_c_type (sexp ctx, sexp self, sexp_sint_t n, sexp obj #define sexp_current_error_port(ctx) sexp_parameter_ref(ctx, sexp_env_ref(ctx, sexp_context_env(ctx), sexp_global(ctx,SEXP_G_CUR_ERR_SYMBOL), SEXP_FALSE)) #define sexp_debug(ctx, msg, obj) (sexp_portp(sexp_current_error_port(ctx)) ? (sexp_write_string(ctx, msg, sexp_current_error_port(ctx)), sexp_write(ctx, obj, sexp_current_error_port(ctx)), sexp_write_char(ctx, '\n', sexp_current_error_port(ctx))) : 0) +#if SEXP_USE_POLL_PORT +SEXP_API int sexp_poll_port(sexp ctx, sexp port, int inputp); +#endif + /* simplify primitive API interface */ #define sexp_read(ctx, in) sexp_read_op(ctx, NULL, 1, in) diff --git a/vm.c b/vm.c index 7f61bad6..d6bd1632 100644 --- a/vm.c +++ b/vm.c @@ -979,6 +979,21 @@ static void* sexp_thread_debug_event(sexp ctx) { #define sexp_ensure_stack(n) #endif +/* used only when no thread scheduler has been loaded */ +#if SEXP_USE_POLL_PORT +int sexp_poll_port(sexp ctx, sexp port, int inputp) { + fd_set fds; + int fd = sexp_port_fileno(port); + if (fd < 0) { + usleep(SEXP_POLL_SLEEP_TIME); + return -1; + } + FD_ZERO(&fds); + FD_SET(fd, &fds); + return select(1, (inputp ? &fds : NULL), (inputp ? NULL : &fds), NULL, NULL); +} +#endif + sexp sexp_apply (sexp ctx, sexp proc, sexp args) { unsigned char *ip; sexp bc, cp, *stack = sexp_stack_data(sexp_context_stack(ctx)); @@ -1965,8 +1980,8 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) { if (sexp_port_stream(_ARG2)) clearerr(sexp_port_stream(_ARG2)); if (sexp_applicablep(sexp_global(ctx, SEXP_G_THREADS_BLOCKER))) sexp_apply2(ctx, sexp_global(ctx, SEXP_G_THREADS_BLOCKER), _ARG2, SEXP_FALSE); - else /* no scheduler but output full, wait 5ms */ - usleep(5*1000); + else + sexp_poll_output(ctx, _ARG2); fuel = 0; ip--; /* try again */ goto loop; @@ -2015,8 +2030,8 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) { /* TODO: the wait seems necessary on OS X to stop a print loop to ptys */ if (sexp_applicablep(sexp_global(ctx, SEXP_G_THREADS_BLOCKER))) sexp_apply2(ctx, sexp_global(ctx, SEXP_G_THREADS_BLOCKER), _ARG3, SEXP_FALSE); - else /* no scheduler but output full, wait 5ms */ - usleep(5*1000); + else + sexp_poll_output(ctx, _ARG3); fuel = 0; ip--; /* try again */ goto loop; @@ -2050,6 +2065,8 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) { /* TODO: block and unblock */ if (sexp_applicablep(sexp_global(ctx, SEXP_G_THREADS_BLOCKER))) sexp_apply2(ctx, sexp_global(ctx, SEXP_G_THREADS_BLOCKER), _ARG1, SEXP_FALSE); + else + sexp_poll_input(ctx, _ARG1); fuel = 0; ip--; /* try again */ } else @@ -2079,6 +2096,8 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) { if (sexp_port_stream(_ARG1)) clearerr(sexp_port_stream(_ARG1)); if (sexp_applicablep(sexp_global(ctx, SEXP_G_THREADS_BLOCKER))) sexp_apply2(ctx, sexp_global(ctx, SEXP_G_THREADS_BLOCKER), _ARG1, SEXP_FALSE); + else + sexp_poll_input(ctx, _ARG1); fuel = 0; ip--; /* try again */ } else