diff options
Diffstat (limited to 'libguile')
-rw-r--r-- | libguile/fports.c | 46 | ||||
-rw-r--r-- | libguile/ports-internal.h | 3 | ||||
-rw-r--r-- | libguile/ports.c | 179 | ||||
-rw-r--r-- | libguile/ports.h | 4 |
4 files changed, 211 insertions, 21 deletions
diff --git a/libguile/fports.c b/libguile/fports.c index 046a844e9..271f3a0a1 100644 --- a/libguile/fports.c +++ b/libguile/fports.c @@ -573,14 +573,24 @@ fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED) static size_t fport_read (SCM port, SCM dst, size_t start, size_t count) { - long res; scm_t_fport *fp = SCM_FSTREAM (port); signed char *ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start; + ssize_t ret; - SCM_SYSCALL (res = read (fp->fdes, ptr, count)); - if (res == -1) - scm_syserror ("fport_read"); - return res; + retry: + ret = read (fp->fdes, ptr, count); + if (ret < 0) + { + if (errno == EINTR) + { + SCM_ASYNC_TICK; + goto retry; + } + if (errno == EWOULDBLOCK || errno == EAGAIN) + return -1; + scm_syserror ("fport_read"); + } + return ret; } static size_t @@ -588,11 +598,23 @@ fport_write (SCM port, SCM src, size_t start, size_t count) { int fd = SCM_FPORT_FDES (port); signed char *ptr = SCM_BYTEVECTOR_CONTENTS (src) + start; + ssize_t ret; - if (full_write (fd, ptr, count) < count) - scm_syserror ("fport_write"); + retry: + ret = write (fd, ptr, count); + if (ret < 0) + { + if (errno == EINTR) + { + SCM_ASYNC_TICK; + goto retry; + } + if (errno == EWOULDBLOCK || errno == EAGAIN) + return -1; + scm_syserror ("fport_write"); + } - return count; + return ret; } static scm_t_off @@ -637,6 +659,12 @@ fport_random_access_p (SCM port) return SCM_FDES_RANDOM_P (SCM_FSTREAM (port)->fdes); } +static int +fport_wait_fd (SCM port) +{ + return SCM_FSTREAM (port)->fdes; +} + /* Query the OS to get the natural buffering for FPORT, if available. */ static void fport_get_natural_buffer_sizes (SCM port, size_t *read_size, size_t *write_size) @@ -660,6 +688,8 @@ scm_make_fptob () scm_set_port_close (ptob, fport_close); scm_set_port_seek (ptob, fport_seek); scm_set_port_truncate (ptob, fport_truncate); + scm_set_port_read_wait_fd (ptob, fport_wait_fd); + scm_set_port_write_wait_fd (ptob, fport_wait_fd); scm_set_port_input_waiting (ptob, fport_input_waiting); scm_set_port_random_access_p (ptob, fport_random_access_p); scm_set_port_get_natural_buffer_sizes (ptob, fport_get_natural_buffer_sizes); diff --git a/libguile/ports-internal.h b/libguile/ports-internal.h index 54ce3e4b0..38da49eb7 100644 --- a/libguile/ports-internal.h +++ b/libguile/ports-internal.h @@ -44,6 +44,9 @@ struct scm_t_port_type SCM scm_read; SCM scm_write; + int (*read_wait_fd) (SCM port); + int (*write_wait_fd) (SCM port); + scm_t_off (*seek) (SCM port, scm_t_off OFFSET, int WHENCE); void (*close) (SCM port); diff --git a/libguile/ports.c b/libguile/ports.c index c67bdf53b..ba3755507 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -33,6 +33,7 @@ #include <fcntl.h> /* for chsize on mingw */ #include <assert.h> #include <iconv.h> +#include <poll.h> #include <uniconv.h> #include <unistr.h> #include <striconveh.h> @@ -126,6 +127,18 @@ default_random_access_p (SCM port) return SCM_PORT_TYPE (port)->seek != NULL; } +static int +default_read_wait_fd (SCM port) +{ + scm_misc_error ("read_wait_fd", "unimplemented", SCM_EOL); +} + +static int +default_write_wait_fd (SCM port) +{ + scm_misc_error ("write_wait_fd", "unimplemented", SCM_EOL); +} + scm_t_port_type * scm_make_port_type (char *name, size_t (*read) (SCM port, SCM dst, size_t start, @@ -144,6 +157,8 @@ scm_make_port_type (char *name, desc->c_write = write; desc->scm_read = read ? trampoline_to_c_read_subr : SCM_BOOL_F; desc->scm_write = write ? trampoline_to_c_write_subr : SCM_BOOL_F; + desc->read_wait_fd = default_read_wait_fd; + desc->write_wait_fd = default_write_wait_fd; desc->random_access_p = default_random_access_p; scm_make_port_classes (desc); @@ -154,7 +169,7 @@ static SCM trampoline_to_c_read (SCM port, SCM dst, SCM start, SCM count) #define FUNC_NAME "port-read" { - size_t c_start, c_count; + size_t c_start, c_count, ret; SCM_VALIDATE_OPPORT (1, port); c_start = scm_to_size_t (start); @@ -162,24 +177,25 @@ trampoline_to_c_read (SCM port, SCM dst, SCM start, SCM count) SCM_ASSERT_RANGE (2, start, c_start <= c_count); SCM_ASSERT_RANGE (3, count, c_start+c_count <= scm_c_bytevector_length (dst)); - return scm_from_size_t - (SCM_PORT_TYPE (port)->c_read (port, dst, c_start, c_count)); + ret = SCM_PORT_TYPE (port)->c_read (port, dst, c_start, c_count); + + return ret == (size_t) -1 ? SCM_BOOL_F : scm_from_size_t (ret); } #undef FUNC_NAME static size_t trampoline_to_scm_read (SCM port, SCM dst, size_t start, size_t count) { - return scm_to_size_t - (scm_call_4 (SCM_PORT_TYPE (port)->scm_read, port, dst, - scm_from_size_t (start), scm_from_size_t (count))); + SCM ret = scm_call_4 (SCM_PORT_TYPE (port)->scm_read, port, dst, + scm_from_size_t (start), scm_from_size_t (count)); + return scm_is_true (ret) ? scm_to_size_t (ret) : (size_t) -1; } static SCM trampoline_to_c_write (SCM port, SCM src, SCM start, SCM count) #define FUNC_NAME "port-write" { - size_t c_start, c_count; + size_t c_start, c_count, ret; SCM_VALIDATE_OPPORT (1, port); c_start = scm_to_size_t (start); @@ -187,17 +203,18 @@ trampoline_to_c_write (SCM port, SCM src, SCM start, SCM count) SCM_ASSERT_RANGE (2, start, c_start <= c_count); SCM_ASSERT_RANGE (3, count, c_start+c_count <= scm_c_bytevector_length (src)); - return scm_from_size_t - (SCM_PORT_TYPE (port)->c_write (port, src, c_start, c_count)); + ret = SCM_PORT_TYPE (port)->c_write (port, src, c_start, c_count); + + return ret == (size_t) -1 ? SCM_BOOL_F : scm_from_size_t (ret); } #undef FUNC_NAME static size_t trampoline_to_scm_write (SCM port, SCM src, size_t start, size_t count) { - return scm_to_size_t - (scm_call_4 (SCM_PORT_TYPE (port)->scm_write, port, src, - scm_from_size_t (start), scm_from_size_t (count))); + SCM ret = scm_call_4 (SCM_PORT_TYPE (port)->scm_write, port, src, + scm_from_size_t (start), scm_from_size_t (count)); + return scm_is_true (ret) ? scm_to_size_t (ret) : (size_t) -1; } void @@ -215,6 +232,18 @@ scm_set_port_scm_write (scm_t_port_type *ptob, SCM write) } void +scm_set_port_read_wait_fd (scm_t_port_type *ptob, int (*get_fd) (SCM)) +{ + ptob->read_wait_fd = get_fd; +} + +void +scm_set_port_write_wait_fd (scm_t_port_type *ptob, int (*get_fd) (SCM)) +{ + ptob->write_wait_fd = get_fd; +} + +void scm_set_port_print (scm_t_port_type *ptob, int (*print) (SCM exp, SCM port, scm_print_state *pstate)) { @@ -1232,6 +1261,116 @@ SCM_DEFINE (scm_set_port_conversion_strategy_x, "set-port-conversion-strategy!", +/* Non-blocking I/O. */ + +static int +port_read_wait_fd (SCM port) +{ + scm_t_port_type *ptob = SCM_PORT_TYPE (port); + return ptob->read_wait_fd (port); +} + +static int +port_write_wait_fd (SCM port) +{ + scm_t_port_type *ptob = SCM_PORT_TYPE (port); + return ptob->write_wait_fd (port); +} + +SCM_INTERNAL SCM scm_port_read_wait_fd (SCM); +SCM_DEFINE (scm_port_read_wait_fd, "port-read-wait-fd", 1, 0, 0, + (SCM port), "") +#define FUNC_NAME s_scm_port_read_wait_fd +{ + int fd; + + port = SCM_COERCE_OUTPORT (port); + SCM_VALIDATE_OPINPORT (1, port); + + fd = port_read_wait_fd (port); + return fd < 0 ? SCM_BOOL_F : scm_from_int (fd); +} +#undef FUNC_NAME + +SCM_INTERNAL SCM scm_port_write_wait_fd (SCM); +SCM_DEFINE (scm_port_write_wait_fd, "port-write-wait-fd", 1, 0, 0, + (SCM port), "") +#define FUNC_NAME s_scm_port_write_wait_fd +{ + int fd; + + port = SCM_COERCE_OUTPORT (port); + SCM_VALIDATE_OPOUTPORT (1, port); + + fd = port_write_wait_fd (port); + return fd < 0 ? SCM_BOOL_F : scm_from_int (fd); +} +#undef FUNC_NAME + +static int +port_poll (SCM port, short events, int timeout) +#define FUNC_NAME "port-poll" +{ + struct pollfd pollfd[2]; + int nfds = 0, rv = 0; + + if (events & POLLIN) + { + pollfd[nfds].fd = port_read_wait_fd (port); + pollfd[nfds].events = events & (POLLIN | POLLPRI); + pollfd[nfds].revents = 0; + nfds++; + } + if (events & POLLOUT) + { + pollfd[nfds].fd = port_write_wait_fd (port); + pollfd[nfds].events = events & (POLLOUT | POLLPRI); + pollfd[nfds].revents = 0; + nfds++; + } + + if (nfds == 2 && pollfd[0].fd == pollfd[1].fd) + { + pollfd[0].events |= pollfd[1].events; + nfds--; + } + + SCM_SYSCALL (rv = poll (pollfd, nfds, timeout)); + if (rv < 0) + SCM_SYSERROR; + + return rv; +} +#undef FUNC_NAME + +SCM_INTERNAL SCM scm_port_poll (SCM, SCM, SCM); +SCM_DEFINE (scm_port_poll, "port-poll", 2, 1, 0, + (SCM port, SCM events, SCM timeout), + "") +#define FUNC_NAME s_scm_port_poll +{ + short c_events = 0; + int c_timeout; + + port = SCM_COERCE_OUTPORT (port); + SCM_VALIDATE_PORT (1, port); + SCM_VALIDATE_STRING (2, events); + c_timeout = SCM_UNBNDP (timeout) ? -1 : SCM_NUM2INT (3, timeout); + + if (scm_i_string_contains_char (events, 'r')) + c_events |= POLLIN; + if (scm_i_string_contains_char (events, '!')) + c_events |= POLLPRI; + if (scm_i_string_contains_char (events, 'w')) + c_events |= POLLIN; + + return scm_from_int (port_poll (port, c_events, c_timeout)); +} +#undef FUNC_NAME + + + + /* Input. */ static int @@ -1330,8 +1469,15 @@ scm_i_read_bytes (SCM port, SCM dst, size_t start, size_t count) assert (count <= SCM_BYTEVECTOR_LENGTH (dst)); assert (start + count <= SCM_BYTEVECTOR_LENGTH (dst)); + retry: filled = ptob->c_read (port, dst, start, count); + if (filled == (size_t) -1) + { + port_poll (port, POLLIN, -1); + goto retry; + } + assert (filled <= count); return filled; @@ -2508,7 +2654,14 @@ scm_i_write_bytes (SCM port, SCM src, size_t start, size_t count) assert (start + count <= SCM_BYTEVECTOR_LENGTH (src)); do - written += ptob->c_write (port, src, start + written, count - written); + { + size_t ret = ptob->c_write (port, src, start + written, count - written); + + if (ret == (size_t) -1) + port_poll (port, POLLOUT, -1); + else + written += ret; + } while (written < count); assert (written == count); diff --git a/libguile/ports.h b/libguile/ports.h index 43cd7458d..2905f68db 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -90,6 +90,10 @@ SCM_API scm_t_port_type *scm_make_port_type size_t (*write) (SCM port, SCM src, size_t start, size_t count)); SCM_API void scm_set_port_scm_read (scm_t_port_type *ptob, SCM read); SCM_API void scm_set_port_scm_write (scm_t_port_type *ptob, SCM write); +SCM_API void scm_set_port_read_wait_fd (scm_t_port_type *ptob, + int (*wait_fd) (SCM port)); +SCM_API void scm_set_port_write_wait_fd (scm_t_port_type *ptob, + int (*wait_fd) (SCM port)); SCM_API void scm_set_port_print (scm_t_port_type *ptob, int (*print) (SCM exp, SCM port, |