Finalizing stream/fd backed ports will properly flush them.

However, don't try to flush string/custom ports which could result in alloc during gc.
This commit is contained in:
Alex Shinn 2012-09-23 23:28:09 +09:00
parent 90ff32e3bd
commit 9da98bd68d
2 changed files with 26 additions and 23 deletions

View file

@ -1254,6 +1254,7 @@ SEXP_API sexp sexp_push_op(sexp ctx, sexp* loc, sexp x);
#define sexp_write_string(x, s, p) (fputs(s, sexp_port_stream(p))) #define sexp_write_string(x, s, p) (fputs(s, sexp_port_stream(p)))
#define sexp_write_string_n(x, s, n, p) (fwrite(s, 1, n, sexp_port_stream(p))) #define sexp_write_string_n(x, s, n, p) (fwrite(s, 1, n, sexp_port_stream(p)))
#define sexp_flush(x, p) (fflush(sexp_port_stream(p))) #define sexp_flush(x, p) (fflush(sexp_port_stream(p)))
#define sexp_flush_forced sexp_flush
#else #else
@ -1262,13 +1263,14 @@ SEXP_API sexp sexp_push_op(sexp ctx, sexp* loc, sexp x);
#define sexp_write_char(x, c, p) (sexp_port_buf(p) ? ((sexp_port_offset(p) < sexp_port_size(p)) ? ((((sexp_port_buf(p))[sexp_port_offset(p)++]) = (char)(c)), 0) : sexp_buffered_write_char(x, c, p)) : putc(c, sexp_port_stream(p))) #define sexp_write_char(x, c, p) (sexp_port_buf(p) ? ((sexp_port_offset(p) < sexp_port_size(p)) ? ((((sexp_port_buf(p))[sexp_port_offset(p)++]) = (char)(c)), 0) : sexp_buffered_write_char(x, c, p)) : putc(c, sexp_port_stream(p)))
#define sexp_write_string(x, s, p) (sexp_port_buf(p) ? sexp_buffered_write_string(x, s, p) : fputs(s, sexp_port_stream(p))) #define sexp_write_string(x, s, p) (sexp_port_buf(p) ? sexp_buffered_write_string(x, s, p) : fputs(s, sexp_port_stream(p)))
#define sexp_write_string_n(x, s, n, p) (sexp_port_buf(p) ? sexp_buffered_write_string_n(x, s, n, p) : fwrite(s, 1, n, sexp_port_stream(p))) #define sexp_write_string_n(x, s, n, p) (sexp_port_buf(p) ? sexp_buffered_write_string_n(x, s, n, p) : fwrite(s, 1, n, sexp_port_stream(p)))
#define sexp_flush(x, p) (sexp_port_buf(p) ? sexp_buffered_flush(x, p) : fflush(sexp_port_stream(p))) #define sexp_flush(x, p) (sexp_port_buf(p) ? sexp_buffered_flush(x, p, 0) : fflush(sexp_port_stream(p)))
#define sexp_flush_forced(x, p) (sexp_port_buf(p) ? sexp_buffered_flush(x, p, 1) : fflush(sexp_port_stream(p)))
SEXP_API int sexp_buffered_read_char (sexp ctx, sexp p); SEXP_API int sexp_buffered_read_char (sexp ctx, sexp p);
SEXP_API int sexp_buffered_write_char (sexp ctx, int c, 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_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_write_string (sexp ctx, const char *str, sexp p);
SEXP_API int sexp_buffered_flush (sexp ctx, sexp p); SEXP_API int sexp_buffered_flush (sexp ctx, sexp p, int forcep);
#endif #endif

39
sexp.c
View file

@ -127,6 +127,19 @@ sexp sexp_finalize_port (sexp ctx, sexp self, sexp_sint_t n, sexp port) {
sexp res = SEXP_VOID; sexp res = SEXP_VOID;
if (sexp_port_openp(port)) { if (sexp_port_openp(port)) {
sexp_port_openp(port) = 0; sexp_port_openp(port) = 0;
if (sexp_oportp(port)) sexp_flush_forced(ctx, port);
#ifndef PLAN9
if (sexp_filenop(sexp_port_fd(port))
&& sexp_fileno_openp(sexp_port_fd(port))) {
if (sexp_port_shutdownp(port)) {
/* shutdown the socket if requested */
if (sexp_iportp(port))
shutdown(sexp_port_fileno(port), sexp_oportp(port) ? SHUT_RDWR : SHUT_RD);
if (sexp_oportp(port))
shutdown(sexp_port_fileno(port), SHUT_WR);
}
}
#endif
if (sexp_port_stream(port) && ! sexp_port_no_closep(port)) { if (sexp_port_stream(port) && ! sexp_port_no_closep(port)) {
/* close the stream */ /* close the stream */
fclose(sexp_port_stream(port)); fclose(sexp_port_stream(port));
@ -143,20 +156,6 @@ sexp sexp_finalize_port (sexp ctx, sexp self, sexp_sint_t n, sexp port) {
) )
free(sexp_port_buf(port)); free(sexp_port_buf(port));
} }
#ifndef PLAN9
if (sexp_filenop(sexp_port_fd(port))
&& sexp_fileno_openp(sexp_port_fd(port))) {
if (sexp_oportp(port)) res = sexp_flush_output(ctx, port);
if (sexp_exceptionp(res)) return res;
if (sexp_port_shutdownp(port)) {
/* shutdown the socket if requested */
if (sexp_iportp(port))
shutdown(sexp_port_fileno(port), sexp_oportp(port) ? SHUT_RDWR : SHUT_RD);
if (sexp_oportp(port))
shutdown(sexp_port_fileno(port), SHUT_WR);
}
}
#endif
} }
return res; return res;
} }
@ -1429,7 +1428,7 @@ int sexp_buffered_read_char (sexp ctx, sexp p) {
int sexp_buffered_write_char (sexp ctx, int c, sexp p) { int sexp_buffered_write_char (sexp ctx, int c, sexp p) {
int res; int res;
if (sexp_port_offset(p)+1 >= sexp_port_size(p)) if (sexp_port_offset(p)+1 >= sexp_port_size(p))
if ((res = sexp_buffered_flush(ctx, p))) if ((res = sexp_buffered_flush(ctx, p, 0)))
return res; return res;
sexp_port_buf(p)[sexp_port_offset(p)++] = c; sexp_port_buf(p)[sexp_port_offset(p)++] = c;
return 0; return 0;
@ -1442,7 +1441,7 @@ int sexp_buffered_write_string_n (sexp ctx, const char *str,
diff = sexp_port_size(p) - sexp_port_offset(p); diff = sexp_port_size(p) - sexp_port_offset(p);
memcpy(sexp_port_buf(p)+sexp_port_offset(p), str, diff); memcpy(sexp_port_buf(p)+sexp_port_offset(p), str, diff);
sexp_port_offset(p) = sexp_port_size(p); sexp_port_offset(p) = sexp_port_size(p);
if ((res = sexp_buffered_flush(ctx, p))) if ((res = sexp_buffered_flush(ctx, p, 0)))
return written + diff; return written + diff;
written += sexp_port_size(p); written += sexp_port_size(p);
str += diff; str += diff;
@ -1457,10 +1456,10 @@ int sexp_buffered_write_string (sexp ctx, const char *str, sexp p) {
return sexp_buffered_write_string_n(ctx, str, strlen(str), p); return sexp_buffered_write_string_n(ctx, str, strlen(str), p);
} }
int sexp_buffered_flush (sexp ctx, sexp p) { int sexp_buffered_flush (sexp ctx, sexp p, int forcep) {
long res = 0, off; long res = 0, off;
sexp_gc_var1(tmp); sexp_gc_var1(tmp);
if (! (sexp_oportp(p) && sexp_port_openp(p))) if (!sexp_oportp(p) || (!forcep && !sexp_port_openp(p)))
return -1; return -1;
off = sexp_port_offset(p); off = sexp_port_offset(p);
if (sexp_port_stream(p)) { if (sexp_port_stream(p)) {
@ -1478,6 +1477,8 @@ int sexp_buffered_flush (sexp ctx, sexp p) {
sexp_port_offset(p) = 0; sexp_port_offset(p) = 0;
res = 0; res = 0;
} }
} else if (!sexp_port_openp(p)) {
return -1;
} else if (sexp_port_offset(p) > 0) { } else if (sexp_port_offset(p) > 0) {
sexp_gc_preserve1(ctx, tmp); sexp_gc_preserve1(ctx, tmp);
if (sexp_port_customp(p)) { /* custom port */ if (sexp_port_customp(p)) { /* custom port */
@ -2051,7 +2052,7 @@ int sexp_write_utf8_char (sexp ctx, int c, sexp out) {
sexp sexp_flush_output_op (sexp ctx, sexp self, sexp_sint_t n, sexp out) { sexp sexp_flush_output_op (sexp ctx, sexp self, sexp_sint_t n, sexp out) {
int res; int res;
sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out); sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out);
res = sexp_flush(ctx, out); res = sexp_flush_forced(ctx, out);
if (res == EOF) { if (res == EOF) {
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_GREEN_THREADS
if (sexp_port_stream(out) && ferror(sexp_port_stream(out)) && (errno == EAGAIN)) if (sexp_port_stream(out) && ferror(sexp_port_stream(out)) && (errno == EAGAIN))