From 38c7c6686d0af4419eba35ddf4532bec58f0633f Mon Sep 17 00:00:00 2001
From: Jiri Palecek <jirka@debian.(none)>
Date: Tue, 11 Nov 2008 15:29:06 +0100
Subject: [PATCH] Nonblocking sync IO in tlibio

Added handling of nonblocking sync IO to tlibio, with select() as
waiting mechanism. Also, removed some kludges in pipeio which are no
longer needed
---
 lib/tlibio.c                         |   97 +++++++++++++++++++++------------
 testcases/kernel/ipc/pipeio/pipeio.c |   20 ++++---
 2 files changed, 74 insertions(+), 43 deletions(-)

diff --git a/lib/tlibio.c b/lib/tlibio.c
index 79d806b..e07cf0c 100644
--- a/lib/tlibio.c
+++ b/lib/tlibio.c
@@ -482,6 +482,15 @@ lio_random_methods(long curr_mask)
     return mask;
 }
 
+static void wait4sync_io(int fd, int read)
+{
+  fd_set s;
+  FD_ZERO(&s);
+  FD_SET(fd, &s);
+
+  select(fd+1, read ? &s : NULL, read ? NULL : &s, NULL, NULL);
+}
+
 /***********************************************************************
  * Generic write function 
  * This function can be used to do a write using write(2), writea(2),
@@ -715,25 +724,33 @@ long wrd;	/* to allow future features, use zero for now */
         if ( Debug_level ) {
 	    printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
         }
-
-	if ((ret = write(fd, buffer, size)) == -1) {
-	    sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
-		__FILE__, __LINE__,
-		fd, size, errno, strerror(errno));
-	    return -errno;
-	}
-
-	if ( ret != size ) {
-            sprintf(Errormsg,
-		"%s/%d write(%d, buf, %d) returned=%d",
-		    __FILE__, __LINE__,
-		    fd, size, ret);
+        while(1) {
+          if (((ret = write(fd, buffer, size)) == -1) && errno!=EAGAIN && errno!=EINTR) {
+            sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
+                    __FILE__, __LINE__,
+                    fd, size, errno, strerror(errno));
+            return -errno;
+          }
+
+          if(ret!=-1) {
+            if ( ret != size ) {
+              sprintf(Errormsg,
+                      "%s/%d write(%d, buf, %d) returned=%d",
+                      __FILE__, __LINE__,
+                      fd, size, ret);
+              size-=ret;
+              buffer+=ret;
+            }
+            else {
+              if ( Debug_level > 1 )
+                printf("DEBUG %s/%d: write completed without error (ret %d)\n",
+                       __FILE__, __LINE__, ret);
+
+              return ret;
+            }
+          }
+          wait4sync_io(fd, 0);
         }
-        else if ( Debug_level > 1 )
-            printf("DEBUG %s/%d: write completed without error (ret %d)\n",
-                __FILE__, __LINE__, ret);
-
-        return ret;
 
     }
 
@@ -1259,24 +1276,34 @@ long wrd;	/* to allow future features, use zero for now */
 	    printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
         }
 
-	if ((ret = read(fd, buffer, size)) == -1) {
-	    sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
-		    __FILE__, __LINE__,
-		fd, size, errno, strerror(errno));
-	    return -errno;
-	}
-
-	if ( ret != size ) {
-            sprintf(Errormsg,
-		"%s/%d read(%d, buf, %d) returned=%d",
-		    __FILE__, __LINE__,
-		    fd, size, ret);
+        while(1) {
+          if (((ret = read(fd, buffer, size)) == -1) && errno!=EINTR && errno!=EAGAIN) {
+            sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
+                    __FILE__, __LINE__,
+                    fd, size, errno, strerror(errno));
+            return -errno;
+          }
+
+          if(ret==0) return 0;
+          if(ret!=-1) {
+            if ( ret != size ) {
+              sprintf(Errormsg,
+                      "%s/%d read(%d, buf, %d) returned=%d",
+                      __FILE__, __LINE__,
+                      fd, size, ret);
+              size-=ret;
+              buffer+=ret;
+            }
+            else {
+              if ( Debug_level > 1 )
+                printf("DEBUG %s/%d: read completed without error (ret %d)\n",
+                       __FILE__, __LINE__, ret);
+
+              return ret;
+            }
+          }
+          wait4sync_io(fd, 1);
         }
-        else if ( Debug_level > 1 )
-            printf("DEBUG %s/%d: read completed without error (ret %d)\n",
-                __FILE__, __LINE__, ret);
-
-        return ret;
 
     }
 
diff --git a/testcases/kernel/ipc/pipeio/pipeio.c b/testcases/kernel/ipc/pipeio/pipeio.c
index 6c7b8af..8b67038 100644
--- a/testcases/kernel/ipc/pipeio/pipeio.c
+++ b/testcases/kernel/ipc/pipeio/pipeio.c
@@ -485,11 +485,13 @@ printf("num_wrters = %d\n", num_wrters);
 printf("child after fork pid = %d\n", getpid());
 #endif
 		if ( ! unpipe ) {
-			if (ndelay) sleep(1);
-			if ((write_fd = open(pname,O_WRONLY|ndelay)) == -1) {
+			if ((write_fd = open(pname,O_WRONLY)) == -1) {
 				tst_resm (TFAIL, "child pipe open(%s, %#o) failed: %s", pname, O_WRONLY|ndelay, strerror(errno));
 				exit(1);
 			}
+			if(ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
+				tst_brkm(TBROK, tst_exit, "Failed setting the pipe to nonblocking mode: %s", strerror(errno));
+			}
 		}
 		else {
 			close(read_fd);
@@ -521,9 +523,6 @@ printf("child after fork pid = %d\n", getpid());
                                           j, cp, strerror(errno));
                                 exit(1);
                         }
-			if ( ndelay && nb == 0 ) {
-				j--;
-			}
 			/*
 			 * If lio_write_buffer returns a negative number,
 			 * the return will be -errno.
@@ -567,10 +566,13 @@ printf("child after fork pid = %d\n", getpid());
 #endif /* linux */
 
 		if ( ! unpipe ) {
-			if ((read_fd = open(pname,O_RDONLY|ndelay)) == -1) {
-				tst_resm (TFAIL, "parent pipe open(%s, %#o) failed: %s", pname, O_WRONLY|ndelay, strerror(errno));
+			if ((read_fd = open(pname,O_RDONLY)) == -1) {
+				tst_resm (TFAIL, "parent pipe open(%s, %#o) failed: %s", pname, O_RDONLY, strerror(errno));
 				exit(1);
 			}
+			if(ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
+				tst_brkm(TBROK, tst_exit, "Failed setting the pipe to nonblocking mode: %s", strerror(errno));
+			}
 		}
 		else {
 			close(write_fd);
@@ -610,8 +612,8 @@ printf("child after fork pid = %d\n", getpid());
 					fprintf(stdout,
 						"%s: Nothing on the pipe (%d),read count %d (read not counted)\n",
 						TCID,empty_read,count);
- */
 					fflush(stdout);
+ */
 					++i;
 					count--;
 					continue;
@@ -644,6 +646,8 @@ printf("child after fork pid = %d\n", getpid());
 				}
 			}
 		}
+    if(empty_read)
+      tst_resm(TWARN, "%d empty reads", empty_read);
 output:
 		if (error)
 			tst_resm (TFAIL, "1 FAIL %d data errors on pipe, read size = %d, %s %s",
-- 
1.6.0.2

Signed-off-by: Jiri Palecek <jpalecek@web.de>
