diff options
author | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2013-07-02 12:20:56 -0400 |
---|---|---|
committer | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2013-07-02 12:20:56 -0400 |
commit | 1f647aac9fa3e412c63a966535de8ee4fec855f2 (patch) | |
tree | 1d6fb3994907a16df69ad694dcef0d539211078d | |
parent | 27e1e910147465ad240a3e4393bbd4312937fed5 (diff) | |
download | egawk-1f647aac9fa3e412c63a966535de8ee4fec855f2.tar.gz egawk-1f647aac9fa3e412c63a966535de8ee4fec855f2.tar.bz2 egawk-1f647aac9fa3e412c63a966535de8ee4fec855f2.zip |
Enhance getline to return -2 when an I/O operation should be retried.
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | extension/ChangeLog | 6 | ||||
-rw-r--r-- | extension/select.c | 28 | ||||
-rw-r--r-- | io.c | 41 |
5 files changed, 79 insertions, 14 deletions
@@ -1,3 +1,20 @@ +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * eval.c (update_ERRNO_string): Set PROCINFO["errno"] to 0. + * io.c (inrec): Since get_a_record may now return -2, be sure + to throw an error in that case as well. + (wait_any): Fix what appears to be a bug. The old logic repeatedly + called wait until it failed. When a process has multiple children, + this causes it to stall until all of them have exited. Instead, + we now exit the function after the first successful wait call. + (do_getline_redir, do_getline): Handle case where get_a_record + returns -2. + (errno_io_retry): New function to decide whether an I/O operation should + be retried. + (get_a_record): When read returns an error, call errno_io_retry to + decide whether the operation should be retried. If so, return -2 + instead of setting the IOP_AT_EOF flag. + 2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com> * eval.c (update_ERRNO_int, unset_ERRNO): Update PROCINFO["errno"]. @@ -1012,6 +1012,7 @@ update_ERRNO_int(int errcode) void update_ERRNO_string(const char *string) { + update_PROCINFO_num("errno", 0); unref(ERRNO_node->var_value); ERRNO_node->var_value = make_string(string, strlen(string)); } diff --git a/extension/ChangeLog b/extension/ChangeLog index 9218c744..d1ef7b4a 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,9 @@ +2013-07-02 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * select.c (set_non_blocking): New helper function to call fcntl. + (do_set_non_blocking): Add support for the case where there's a single + integer fd argument. + 2013-07-01 Andrew J. Schorr <aschorr@telemetry-investments.com> * select.c (do_set_non_blocking): Implement new set_non_blocking diff --git a/extension/select.c b/extension/select.c index 91898a20..c1b706fc 100644 --- a/extension/select.c +++ b/extension/select.c @@ -364,26 +364,36 @@ do_select(int nargs, awk_value_t *result) return make_number(rc, result); } +static int +set_non_blocking(int fd) +{ + int flags = fcntl(fd, F_GETFL); + int rc = fcntl(fd, F_SETFL, (flags|O_NONBLOCK)); + if (rc < 0) + update_ERRNO_int(errno); + return rc; +} + /* do_set_non_blocking --- Set a file to be non-blocking */ static awk_value_t * do_set_non_blocking(int nargs, awk_value_t *result) { awk_value_t cmd, cmdtype; + int fd; if (do_lint && nargs > 2) lintwarn(ext_id, _("set_non_blocking: called with too many arguments")); - if (get_argument(0, AWK_STRING, & cmd) && + if (get_argument(0, AWK_NUMBER, & cmd) && + (cmd.num_value == (fd = cmd.num_value)) && + ! get_argument(1, AWK_STRING, & cmdtype)) + return make_number(set_non_blocking(fd), result); + else if (get_argument(0, AWK_STRING, & cmd) && get_argument(1, AWK_STRING, & cmdtype)) { const awk_input_buf_t *buf; - if ((buf = get_file(cmd.str_value.str, cmd.str_value.len, cmdtype.str_value.str, cmdtype.str_value.len)) != NULL) { - int flags = fcntl(buf->fd, F_GETFL); - int rc = fcntl(buf->fd, F_SETFL, (flags|O_NONBLOCK)); - if (rc < 0) - update_ERRNO_int(errno); - return make_number(rc, result); - } else - warning(ext_id, _("set_non_blocking: get_file(`%s', `%s') failed"), cmd.str_value.str, cmdtype.str_value.str); + if ((buf = get_file(cmd.str_value.str, cmd.str_value.len, cmdtype.str_value.str, cmdtype.str_value.len)) != NULL) + return make_number(set_non_blocking(buf->fd), result); + warning(ext_id, _("set_non_blocking: get_file(`%s', `%s') failed"), cmd.str_value.str, cmdtype.str_value.str); } else if (do_lint) { if (nargs < 2) lintwarn(ext_id, _("set_non_blocking: called with too few arguments")); @@ -555,7 +555,7 @@ inrec(IOBUF *iop, int *errcode) else cnt = get_a_record(& begin, iop, errcode); - if (cnt == EOF) { + if (cnt < 0) { retval = 1; if (*errcode > 0) update_ERRNO_int(*errcode); @@ -2210,12 +2210,13 @@ wait_any(int interesting) /* pid of interest, if any */ if (pid == redp->pid) { redp->pid = -1; redp->status = status; - break; + goto finished; } } if (pid == -1 && errno == ECHILD) break; } +finished: signal(SIGHUP, hstat); signal(SIGQUIT, qstat); #endif @@ -2439,7 +2440,7 @@ do_getline_redir(int into_variable, enum redirval redirtype) if (errcode != 0) { if (! do_traditional && (errcode != -1)) update_ERRNO_int(errcode); - return make_number((AWKNUM) -1.0); + return make_number((AWKNUM) cnt); } if (cnt == EOF) { @@ -2489,7 +2490,7 @@ do_getline(int into_variable, IOBUF *iop) update_ERRNO_int(errcode); if (into_variable) (void) POP_ADDRESS(); - return make_number((AWKNUM) -1.0); + return make_number((AWKNUM) cnt); } if (cnt == EOF) @@ -3427,6 +3428,32 @@ find_longest_terminator: return REC_OK; } +/* Does the I/O error indicate that the operation should be retried later? */ + +static inline int +errno_io_retry(void) +{ + switch (errno) { +#ifdef EAGAIN + case EAGAIN: +#endif +#ifdef EWOULDBLOCK +#if !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif +#endif +#ifdef EINTR + case EINTR: +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: +#endif + return 1; + default: + return 0; + } +} + /* * get_a_record --- read a record from IOP into out, * return length of EOF, set RT. @@ -3474,8 +3501,10 @@ get_a_record(char **out, /* pointer to pointer to data */ iop->flag |= IOP_AT_EOF; return EOF; } else if (iop->count == -1) { - iop->flag |= IOP_AT_EOF; *errcode = errno; + if (errno_io_retry()) + return -2; + iop->flag |= IOP_AT_EOF; return EOF; } else { iop->dataend = iop->buf + iop->count; @@ -3540,6 +3569,8 @@ get_a_record(char **out, /* pointer to pointer to data */ iop->count = iop->public.read_func(iop->public.fd, iop->dataend, amt_to_read); if (iop->count == -1) { *errcode = errno; + if (errno_io_retry()) + return -2; iop->flag |= IOP_AT_EOF; break; } else if (iop->count == 0) { |