Restart failed system calls interrupted with errno of EINTR
In number of places we don't handle properly system calls failures
when the errno is EINTR (i.e., the system call was interrupted
by a signal). In all our use cases, the system calls should be
restarted. The handling of the following system calls (as used in the code)
has been updated/fixed:
poll, send, recv, sendmsg, nanosleep, epoll_wait
read - mostly (e.g., socket-like fds)
write - mostly (e.g., socket-like fds)
select, accept, connect
Bug: 28471477
Bug: 28658141
Change-Id: I03e6f0f67e33876780fb6d02c33eb84547ba8f95
diff --git a/osi/include/osi.h b/osi/include/osi.h
index ed8fc2a..966c617 100644
--- a/osi/include/osi.h
+++ b/osi/include/osi.h
@@ -64,6 +64,9 @@
// Effort is made for this to come from a real random source.
int osi_rand(void);
+// Re-run |fn| system call until the system call doesn't cause EINTR.
+#define OSI_NO_INTR(fn) do {} while ((fn) == -1 && errno == EINTR)
+
#ifdef __cplusplus
}
#endif
diff --git a/osi/include/socket.h b/osi/include/socket.h
index ac49921..b27e681 100644
--- a/osi/include/socket.h
+++ b/osi/include/socket.h
@@ -62,20 +62,24 @@
// block. This function returns a positive integer representing the number
// of bytes copied into |buf| on success, 0 if the socket has disconnected,
// and -1 on error. This function may return a value less than |count| if not
-// enough data is currently available. If this function returns -1, errno will also
-// be set (see recv(2) for possible errno values). If there were no bytes available
-// to be read, this function returns -1 and sets errno to EWOULDBLOCK. Neither
-// |socket| nor |buf| may be NULL.
+// enough data is currently available. If this function returns -1, errno will
+// also be set (see recv(2) for possible errno values). However, if the reading
+// system call was interrupted with errno of EINTR, the read operation is
+// restarted internally without propagating EINTR back to the caller. If there
+// were no bytes available to be read, this function returns -1 and sets errno
+// to EWOULDBLOCK. Neither |socket| nor |buf| may be NULL.
ssize_t socket_read(const socket_t *socket, void *buf, size_t count);
// Writes up to |count| bytes from |buf| into |socket|. This function will not
// block. Returns a positive integer representing the number of bytes written
-// to |socket| on success, 0 if the socket has disconnected, and -1 on error. This
-// function may return a value less than |count| if writing more bytes would result
-// in blocking. If this function returns -1, errno will also be set (see send(2) for
-// possible errno values). If no bytes could be written without blocking, this
-// function will return -1 and set errno to EWOULDBLOCK. Neither |socket| nor |buf|
-// may be NULL.
+// to |socket| on success, 0 if the socket has disconnected, and -1 on error.
+// This function may return a value less than |count| if writing more bytes
+// would result in blocking. If this function returns -1, errno will also be
+// set (see send(2) for possible errno values). However, if the writing system
+// call was interrupted with errno of EINTR, the write operation is restarted
+// internally without propagating EINTR back to the caller. If no bytes could
+// be written without blocking, this function will return -1 and set errno to
+// EWOULDBLOCK. Neither |socket| nor |buf| may be NULL.
ssize_t socket_write(const socket_t *socket, const void *buf, size_t count);
// This function performs the same write operation as |socket_write| and also