Browse Source

base io: faux_read_block() works for non-blocked fds

Serj Kalichev 1 year ago
parent
commit
620d5c390f
2 changed files with 33 additions and 12 deletions
  1. 31 10
      faux/base/io.c
  2. 2 2
      faux/eloop/eloop.c

+ 31 - 10
faux/base/io.c

@@ -138,7 +138,8 @@ ssize_t faux_read(int fd, void *buf, size_t n)
  *
  * The system read() can be interrupted by signal or can read less bytes
  * than specified. This function will continue to read data until all data
- * will be readed or error occured.
+ * will be readed or error occured. Function works even for non-blocking
+ * file descriptors.
  *
  * @param [in] fd File descriptor.
  * @param [in] buf Buffer to write.
@@ -149,23 +150,43 @@ ssize_t faux_read(int fd, void *buf, size_t n)
  */
 size_t faux_read_block(int fd, void *buf, size_t n)
 {
-	ssize_t bytes_readed = 0;
 	size_t total_readed = 0;
 	size_t left = n;
 	void *data = buf;
+	struct pollfd fds = {};
 
+	fds.fd = fd;
+	fds.events = POLLIN;
 	do {
-		bytes_readed = read(fd, data, left);
-		if (bytes_readed < 0) {
+		int prc = 0;
+		fds.revents = 0; // Reset revents before poll()
+		prc = poll(&fds, 1, -1);
+		if (prc < 0) {
+			if (EINTR == errno)
+				continue;
 			if (total_readed != 0)
-				return total_readed;
+				break;
+			return -1;
+		}
+		if (fds.revents & POLLIN) {
+			ssize_t bytes_readed = 0;
+			bytes_readed = read(fd, data, left);
+			if (bytes_readed < 0) {
+				if (total_readed != 0)
+					break;
+				return -1;
+			}
+			if (0 == bytes_readed) // EOF
+				break;
+			data += bytes_readed;
+			left = left - bytes_readed;
+			total_readed += bytes_readed;
+		}
+		if (fds.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+			if (total_readed != 0)
+				break;
 			return -1;
 		}
-		if (0 == bytes_readed) // EOF
-			return total_readed;
-		data += bytes_readed;
-		left = left - bytes_readed;
-		total_readed += bytes_readed;
 	} while (left > 0);
 
 	return total_readed;

+ 2 - 2
faux/eloop/eloop.c

@@ -337,13 +337,13 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop)
 #ifdef HAVE_SIGNALFD
 			if (fd == eloop->signal_fd) {
 				struct signalfd_siginfo signal_info = {};
-				while (faux_read_block(fd, &signal_info,
+				while (faux_read(fd, &signal_info,
 					sizeof(signal_info)) == sizeof(signal_info)) {
 					int signo = signal_info.ssi_signo;
 #else
 			if (fd == signal_pipe[0]) {
 				int tmp = 0;
-				while (faux_read_block(fd, &tmp,
+				while (faux_read(fd, &tmp,
 					sizeof(tmp)) == sizeof(tmp)) {
 					int signo = tmp;
 #endif // HAVE_SIGNALFD