From 0c6d2191efac1342a0306d7182e32f0aaf1a402c Mon Sep 17 00:00:00 2001 From: Gary Houston Date: Tue, 2 Jan 2001 00:38:41 +0000 Subject: [PATCH] * fports.c (fport_write): bugfix: handle short writes for unbuffered ports too. optimize the buffered case by minimizing the number of write/flush calls. (write_all): new helper procedure. --- libguile/ChangeLog | 7 ++++ libguile/fports.c | 90 +++++++++++++++++++++++++++++++++------------- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/libguile/ChangeLog b/libguile/ChangeLog index cb8d92eca..7aa776caf 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,10 @@ +2001-01-01 Gary Houston + + * fports.c (fport_write): bugfix: handle short writes for + unbuffered ports too. optimize the buffered case by minimizing + the number of write/flush calls. + (write_all): new helper procedure. + 2000-12-30 Michael Livshin * guardians.c (guardian_print): for sharing guardians, print that diff --git a/libguile/fports.c b/libguile/fports.c index f8a717001..9d0f96d51 100644 --- a/libguile/fports.c +++ b/libguile/fports.c @@ -573,41 +573,83 @@ fport_truncate (SCM port, off_t length) scm_syserror ("ftruncate"); } +/* helper for fport_write: try to write data, using multiple system + calls if required. */ +#define FUNC_NAME "write_all" +static void write_all (SCM port, const void *data, size_t remaining) +{ + int fdes = SCM_FSTREAM (port)->fdes; + + while (remaining > 0) + { + ssize_t done; + + SCM_SYSCALL (done = write (fdes, data, remaining)); + + if (done == -1) + SCM_SYSERROR; + remaining -= done; + data = ((const char *) data) + done; + } +} +#undef FUNC_NAME + static void fport_write (SCM port, const void *data, size_t size) { + /* this procedure tries to minimize the number of writes/flushes. */ scm_port *pt = SCM_PTAB_ENTRY (port); - if (pt->write_buf == &pt->shortbuf) + if (pt->write_buf == &pt->shortbuf + || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size)) { - /* "unbuffered" port. */ - int fdes = SCM_FSTREAM (port)->fdes; - - if (write (fdes, data, size) == -1) - scm_syserror ("fport_write"); + /* "unbuffered" port, or + port with empty buffer and data won't fit in buffer. */ + write_all (port, data, size); + return; } - else - { - const char *input = (char *) data; - size_t remaining = size; - while (remaining > 0) - { - int space = pt->write_end - pt->write_pos; - int write_len = (remaining > space) ? space : remaining; + { + off_t space = pt->write_end - pt->write_pos; - memcpy (pt->write_pos, input, write_len); - pt->write_pos += write_len; - remaining -= write_len; - input += write_len; - if (write_len == space) + if (size <= space) + { + /* data fits in buffer. */ + memcpy (pt->write_pos, data, size); + pt->write_pos += size; + if (pt->write_pos == pt->write_end) + { fport_flush (port); - } - - /* handle line buffering. */ - if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size)) + /* we can skip the line-buffering check if nothing's buffered. */ + return; + } + } + else + { + memcpy (pt->write_pos, data, space); + pt->write_pos = pt->write_end; fport_flush (port); - } + { + const void *ptr = ((const char *) data) + space; + size_t remaining = size - space; + + if (size >= pt->write_buf_size) + { + write_all (port, ptr, remaining); + return; + } + else + { + memcpy (pt->write_pos, ptr, remaining); + pt->write_pos += remaining; + } + } + } + + /* handle line buffering. */ + if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size)) + fport_flush (port); + } } /* becomes 1 when process is exiting: normal exception handling won't