summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-04-01 19:39:52 +0530
committerAmit Shah <amit.shah@redhat.com>2010-04-06 20:00:37 +0530
commit7798bff7fa23ea2218a1480fecbcdd981fed4039 (patch)
treecfe65e0d09a5275697bfd45a65dafee54146a973
parent873d4e83413cbd1be336c7157d28f763f8e7208e (diff)
downloadtest-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.c149
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.