diff options
author | Amit Shah <amit.shah@redhat.com> | 2010-04-01 19:39:52 +0530 |
---|---|---|
committer | Amit Shah <amit.shah@redhat.com> | 2010-04-06 20:00:37 +0530 |
commit | 7798bff7fa23ea2218a1480fecbcdd981fed4039 (patch) | |
tree | cfe65e0d09a5275697bfd45a65dafee54146a973 | |
parent | 873d4e83413cbd1be336c7157d28f763f8e7208e (diff) | |
download | test-virtserial-7798bff7fa23ea2218a1480fecbcdd981fed4039.tar.gz test-virtserial-7798bff7fa23ea2218a1480fecbcdd981fed4039.tar.xz test-virtserial-7798bff7fa23ea2218a1480fecbcdd981fed4039.zip |
auto-test: guest: Cope with EINTR and EAGAIN for read/write/poll
Introduce wrappers for read(), write() and poll() that handle EINTR and
EAGAIN properly. For EINTR, just re-do the operation. For EAGAIN, if
it's a non-blocking port, let the host know about it.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
-rw-r--r-- | auto-virtserial-guest.c | 149 |
1 files changed, 111 insertions, 38 deletions
diff --git a/auto-virtserial-guest.c b/auto-virtserial-guest.c index 6776874..eebf1f0 100644 --- a/auto-virtserial-guest.c +++ b/auto-virtserial-guest.c @@ -45,6 +45,93 @@ static int g_length; /* The 'name' field in the sysfs port info */ static char g_sysfs_name[1024]; + +static ssize_t safewrite(int fd, const void *buf, size_t count) +{ + size_t ret, len; + int flags; + bool nonblock; + + nonblock = false; + flags = fcntl(fd, F_GETFL); + if (flags > 0 && flags & O_NONBLOCK) + nonblock = true; + + len = count; + while (len > 0) { + ret = write(fd, buf, len); + if (ret == -1) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN) { + if (nonblock) { + return -EAGAIN; + } else { + continue; + } + } + return -errno; + } else if (ret == 0) { + break; + } else { + buf += ret; + len -= ret; + } + } + return count - len; +} + +static ssize_t saferead(int fd, void *buf, size_t count) +{ + size_t ret, len; + int flags; + bool nonblock; + + nonblock = false; + flags = fcntl(fd, F_GETFL); + if (flags > 0 && flags & O_NONBLOCK) + nonblock = true; + + len = count; + while (len > 0) { + ret = read(fd, buf, len); + if (ret == -1) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN) { + if (nonblock) { + return -EAGAIN; + } else { + continue; + } + } + return -errno; + } else if (ret == 0) { + break; + } else { + buf += ret; + len -= ret; + } + } + return count - len; +} + +static int safepoll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + int ret; + + do { + ret = poll(fds, nfds, timeout); + } while (ret == -1 && errno == EINTR); + + if (ret == -1) + ret = -errno; + + return ret; +} + static char *get_port_dev(unsigned int nr) { char *buf; @@ -77,11 +164,10 @@ static int poll_port(int timeout) pollfds[0].fd = g_fd; pollfds[0].events = POLLIN | POLLOUT; - ret = poll(pollfds, 1, timeout); - if (ret == -1) - return -errno; - if (ret == 0) + ret = safepoll(pollfds, 1, timeout); + if (ret <= 0) return ret; + return pollfds[0].revents; } @@ -100,11 +186,8 @@ static int read_port(int nr) buf = malloc(g_length); if (!buf) return -ENOMEM; - ret = read(g_fd, buf, g_length); + ret = saferead(g_fd, buf, g_length); free(buf); - if (ret == -1) - ret = -errno; - return ret; } @@ -119,11 +202,8 @@ static int write_port(int nr) buf = malloc(g_length); if (!buf) return -ENOMEM; - ret = write(g_fd, buf, g_length); + ret = safewrite(g_fd, buf, g_length); free(buf); - if (ret == -1) - ret = -errno; - return ret; } @@ -191,8 +271,8 @@ static int recv_bytestream(int val) if (!buf) return -ENOMEM; - while((ret = read(g_fd, buf, g_length))) { - ret = write(g_bigfile_fd, buf, ret); + while((ret = saferead(g_fd, buf, g_length)) > 0) { + ret = safewrite(g_bigfile_fd, buf, ret); if (ret < 0) break; } @@ -220,12 +300,11 @@ static int send_host_csum(int nr) if (!csum_fd) { return -errno; } - ret = read(csum_fd, buf, g_length); + ret = saferead(csum_fd, buf, g_length); close(csum_fd); - ret = write(g_fd, buf, ret); - if (ret < 0) - ret = -errno; + if (ret > 0) + ret = safewrite(g_fd, buf, ret); free(buf); return ret; } @@ -247,17 +326,14 @@ static int send_bytestream(int val) if (!buf) return -ENOMEM; - while((ret = read(g_bigfile_fd, buf, g_length)) > 0) { - - ret = write(g_fd, buf, ret); + while((ret = saferead(g_bigfile_fd, buf, g_length)) > 0) { + ret = safewrite(g_fd, buf, ret); if (ret < 0) break; } free(buf); close(g_bigfile_fd); close(g_fd); - if (ret < 0) - ret = -errno; return ret; } @@ -280,12 +356,11 @@ static int send_guest_csum(int nr) if (!csum_fd) { return -errno; } - ret = read(csum_fd, buf, g_length); + ret = saferead(csum_fd, buf, g_length); close(csum_fd); - ret = write(g_fd, buf, ret); - if (ret < 0) - ret = -errno; + if (ret > 0) + ret = safewrite(g_fd, buf, ret); free(buf); return ret; } @@ -300,11 +375,9 @@ static int check_sysfs(int nr) if (fd < 0) return -errno; - ret = read(fd, g_sysfs_name, 1024); - if (ret < 0) { - ret = -errno; + ret = saferead(fd, g_sysfs_name, 1024); + if (ret < 0) goto out_close; - } ret = 0; out_close: @@ -346,7 +419,7 @@ static void send_report(int cfd, int ret) gpkt.key = KEY_RESULT; gpkt.value = ret; - write(cfd, &gpkt, sizeof(gpkt)); + safewrite(cfd, &gpkt, sizeof(gpkt)); } int main(int argc, char *argv[]) @@ -375,22 +448,22 @@ back_to_open: gpkt.key = KEY_STATUS_OK; gpkt.value = 1; - ret = write(cfd, &gpkt, sizeof(gpkt)); - if (ret == -1) - error(errno, errno, "write control port"); + ret = safewrite(cfd, &gpkt, sizeof(gpkt)); + if (ret < 0) + error(-ret, -ret, "write control port"); pollfd[0].fd = cfd; pollfd[0].events = POLLIN; while (1) { - ret = poll(pollfd, 1, -1); - if (ret == -1) + ret = safepoll(pollfd, 1, -1); + if (ret < 0) error(errno, errno, "poll"); if (!(pollfd[0].revents & POLLIN)) continue; - ret = read(cfd, &gpkt, sizeof(gpkt)); + ret = saferead(cfd, &gpkt, sizeof(gpkt)); if (ret < sizeof(gpkt)) { /* * Out of sync with host. Close port and start over. |