aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2013-07-02 12:20:56 -0400
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2013-07-02 12:20:56 -0400
commit1f647aac9fa3e412c63a966535de8ee4fec855f2 (patch)
tree1d6fb3994907a16df69ad694dcef0d539211078d
parent27e1e910147465ad240a3e4393bbd4312937fed5 (diff)
downloadegawk-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--ChangeLog17
-rw-r--r--eval.c1
-rw-r--r--extension/ChangeLog6
-rw-r--r--extension/select.c28
-rw-r--r--io.c41
5 files changed, 79 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 78027810..9719effc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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"].
diff --git a/eval.c b/eval.c
index c1253f57..4ad5afe0 100644
--- a/eval.c
+++ b/eval.c
@@ -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"));
diff --git a/io.c b/io.c
index 14b8df91..0ba36451 100644
--- a/io.c
+++ b/io.c
@@ -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) {