mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-19 21:59:17 +02:00
Fixing EAGAIN handling in write_string opcode by using
write(2) directly (considering abandoning FILE* backed ports for standard use-cases). Also fixing write_char return type for native buffered ports.
This commit is contained in:
parent
31db161dcd
commit
acbeeddfa0
3 changed files with 55 additions and 35 deletions
|
@ -1205,10 +1205,10 @@ enum sexp_context_globals {
|
|||
#define sexp_flush(x, p) (sexp_port_buf(p) ? sexp_buffered_flush(x, p) : (fflush(sexp_port_stream(p)), SEXP_VOID))
|
||||
|
||||
SEXP_API int sexp_buffered_read_char (sexp ctx, sexp p);
|
||||
SEXP_API sexp sexp_buffered_write_char (sexp ctx, int c, sexp p);
|
||||
SEXP_API sexp sexp_buffered_write_string_n (sexp ctx, const char *str, sexp_uint_t len, sexp p);
|
||||
SEXP_API sexp sexp_buffered_write_string (sexp ctx, const char *str, sexp p);
|
||||
SEXP_API sexp sexp_buffered_flush (sexp ctx, sexp p);
|
||||
SEXP_API int sexp_buffered_write_char (sexp ctx, int c, sexp p);
|
||||
SEXP_API int sexp_buffered_write_string_n (sexp ctx, const char *str, sexp_uint_t len, sexp p);
|
||||
SEXP_API int sexp_buffered_write_string (sexp ctx, const char *str, sexp p);
|
||||
SEXP_API int sexp_buffered_flush (sexp ctx, sexp p);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
53
sexp.c
53
sexp.c
|
@ -1315,14 +1315,14 @@ int sexp_buffered_read_char (sexp ctx, sexp p) {
|
|||
}
|
||||
}
|
||||
|
||||
sexp sexp_buffered_write_char (sexp ctx, int c, sexp p) {
|
||||
int sexp_buffered_write_char (sexp ctx, int c, sexp p) {
|
||||
if (sexp_port_offset(p)+1 >= sexp_port_size(p))
|
||||
sexp_buffered_flush(ctx, p);
|
||||
sexp_port_buf(p)[sexp_port_offset(p)++] = c;
|
||||
return SEXP_VOID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sexp sexp_buffered_write_string_n (sexp ctx, const char *str,
|
||||
int sexp_buffered_write_string_n (sexp ctx, const char *str,
|
||||
sexp_uint_t len, sexp p) {
|
||||
int diff;
|
||||
while (sexp_port_offset(p)+len >= sexp_port_size(p)) {
|
||||
|
@ -1334,32 +1334,32 @@ sexp sexp_buffered_write_string_n (sexp ctx, const char *str,
|
|||
}
|
||||
memcpy(sexp_port_buf(p)+sexp_port_offset(p), str, len);
|
||||
sexp_port_offset(p) += len;
|
||||
return SEXP_VOID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sexp sexp_buffered_write_string (sexp ctx, const char *str, sexp p) {
|
||||
int sexp_buffered_write_string (sexp ctx, const char *str, sexp p) {
|
||||
return sexp_buffered_write_string_n(ctx, str, strlen(str), p);
|
||||
}
|
||||
|
||||
sexp sexp_buffered_flush (sexp ctx, sexp p) {
|
||||
int sexp_buffered_flush (sexp ctx, sexp p) {
|
||||
int res;
|
||||
sexp_gc_var1(tmp);
|
||||
if (! sexp_oportp(p))
|
||||
return sexp_type_exception(ctx, NULL, SEXP_OPORT, p);
|
||||
if (! sexp_port_openp(p))
|
||||
return sexp_user_exception(ctx, SEXP_FALSE, "port is closed", p);
|
||||
else {
|
||||
if (sexp_port_stream(p)) {
|
||||
fwrite(sexp_port_buf(p), 1, sexp_port_offset(p), sexp_port_stream(p));
|
||||
fflush(sexp_port_stream(p));
|
||||
} else if (sexp_port_offset(p) > 0) {
|
||||
sexp_gc_preserve1(ctx, tmp);
|
||||
tmp = sexp_c_string(ctx, sexp_port_buf(p), sexp_port_offset(p));
|
||||
if (! (sexp_oportp(p) && sexp_port_openp(p)))
|
||||
return -1;
|
||||
if (sexp_port_stream(p)) {
|
||||
fwrite(sexp_port_buf(p), 1, sexp_port_offset(p), sexp_port_stream(p));
|
||||
res = fflush(sexp_port_stream(p));
|
||||
} else if (sexp_port_offset(p) > 0) {
|
||||
sexp_gc_preserve1(ctx, tmp);
|
||||
tmp = sexp_c_string(ctx, sexp_port_buf(p), sexp_port_offset(p));
|
||||
if (tmp && sexp_stringp(tmp))
|
||||
sexp_push(ctx, sexp_port_cookie(p), tmp);
|
||||
sexp_gc_release1(ctx);
|
||||
}
|
||||
sexp_port_offset(p) = 0;
|
||||
return SEXP_VOID;
|
||||
else
|
||||
res = -1;
|
||||
sexp_gc_release1(ctx);
|
||||
}
|
||||
sexp_port_offset(p) = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
sexp sexp_make_input_string_port_op (sexp ctx, sexp self, sexp_sint_t n, sexp str) {
|
||||
|
@ -1845,8 +1845,15 @@ int sexp_write_utf8_char (sexp ctx, int c, sexp out) {
|
|||
#endif
|
||||
|
||||
sexp sexp_flush_output_op (sexp ctx, sexp self, sexp_sint_t n, sexp out) {
|
||||
sexp_flush(ctx, out);
|
||||
return SEXP_VOID;
|
||||
int res;
|
||||
sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out);
|
||||
res = sexp_flush(ctx, out);
|
||||
if (res == EOF) {
|
||||
if (sexp_port_stream(out) && ferror(sexp_port_stream(out)) && (errno == EAGAIN))
|
||||
return sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR);
|
||||
return SEXP_FALSE;
|
||||
}
|
||||
return SEXP_TRUE;
|
||||
}
|
||||
|
||||
#define INIT_STRING_BUFFER_SIZE 128
|
||||
|
|
29
vm.c
29
vm.c
|
@ -409,7 +409,7 @@ static void generate_tail_jump (sexp ctx, sexp name, sexp loc, sexp lam, sexp ap
|
|||
emit_word(ctx, sexp_param_index(lam, sexp_car(ls1)));
|
||||
}
|
||||
|
||||
/* jump */
|
||||
/* drop the current result and jump */
|
||||
emit(ctx, SEXP_OP_JUMP);
|
||||
emit_word(ctx, (sexp_uint_t) (-sexp_context_pos(ctx) +
|
||||
(sexp_pairp(sexp_lambda_locals(lam))
|
||||
|
@ -840,6 +840,8 @@ static sexp sexp_print_vm_profile (sexp ctx, sexp self, sexp_sint_t n) {
|
|||
#define sexp_ensure_stack(n)
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
|
||||
unsigned char *ip;
|
||||
sexp bc, cp, *stack = sexp_stack_data(sexp_context_stack(ctx));
|
||||
|
@ -1804,13 +1806,22 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
|
|||
if (! sexp_oportp(_ARG3))
|
||||
sexp_raise("write-string: not an output-port", sexp_list1(ctx, _ARG3));
|
||||
sexp_context_top(ctx) = top;
|
||||
if (sexp_port_stream(_ARG3)) {
|
||||
i = fwrite(sexp_bytes_data(tmp1), 1, sexp_unbox_fixnum(_ARG2), sexp_port_stream(_ARG3));
|
||||
if (sexp_port_stream(_ARG3) && sexp_port_fileno(_ARG3) >= 0) {
|
||||
/* first flush anything pending */
|
||||
i = fflush(sexp_port_stream(_ARG3));
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if ((i < sexp_unbox_fixnum(_ARG2))
|
||||
&& ferror(sexp_port_stream(_ARG3))
|
||||
&& (errno == EAGAIN)) {
|
||||
if (i) {
|
||||
i = 0;
|
||||
clearerr(sexp_port_stream(_ARG3));
|
||||
if (errno == EAGAIN)
|
||||
goto write_string_yield;
|
||||
}
|
||||
errno = 0;
|
||||
#endif
|
||||
/* fwrite doesn't give reliable counts, use write(2) directly */
|
||||
i = write(sexp_port_fileno(_ARG3), sexp_bytes_data(tmp1), sexp_unbox_fixnum(_ARG2));
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if (i < sexp_unbox_fixnum(_ARG2)) {
|
||||
/* modify stack in-place so we continue where we left off next time */
|
||||
if (i > 0) {
|
||||
if (sexp_stringp(_ARG1))
|
||||
|
@ -1819,7 +1830,8 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
|
|||
_ARG1 = sexp_subbytes(ctx, _ARG1, sexp_make_fixnum(i), SEXP_FALSE);
|
||||
_ARG2 = sexp_make_fixnum(sexp_unbox_fixnum(_ARG2) - i);
|
||||
}
|
||||
/* yield if threads are enabled */
|
||||
/* yield if threads are enabled (otherwise busy loop) */
|
||||
write_string_yield:
|
||||
if (sexp_applicablep(sexp_global(ctx, SEXP_G_THREADS_BLOCKER))) {
|
||||
sexp_apply1(ctx, sexp_global(ctx, SEXP_G_THREADS_BLOCKER), _ARG3);
|
||||
fuel = 0;
|
||||
|
@ -1832,8 +1844,9 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
|
|||
if (sexp_bytes_length(tmp1) != sexp_unbox_fixnum(_ARG2))
|
||||
tmp1 = sexp_subbytes(ctx, tmp1, SEXP_ZERO, _ARG2);
|
||||
sexp_write_string(ctx, sexp_bytes_data(tmp1), _ARG3);
|
||||
i = sexp_unbox_fixnum(_ARG2);
|
||||
}
|
||||
tmp1 = _ARG2; /* return the number of bytes written */
|
||||
tmp1 = sexp_make_fixnum(i); /* return the number of bytes written */
|
||||
top-=2;
|
||||
_ARG1 = tmp1;
|
||||
break;
|
||||
|
|
Loading…
Add table
Reference in a new issue