summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-10-13 18:02:24 +0000
committerUlrich Drepper <drepper@redhat.com>2007-10-13 18:02:24 +0000
commitf7140274a410838336adca1acb40f5a862e6cac9 (patch)
tree609c375a589fa62136d4cc021363d03bfa7ffa8c
parent656f02ce5b080fa4dfdd7c6f0ee52aa30b94c880 (diff)
downloadglibc-f7140274a410838336adca1acb40f5a862e6cac9.tar.gz
glibc-f7140274a410838336adca1acb40f5a862e6cac9.tar.xz
glibc-f7140274a410838336adca1acb40f5a862e6cac9.zip
[BZ #3242]
2007-10-13  Ulrich Drepper  <drepper@redhat.com>
	[BZ #3242]
	* nscd/nscd_helper.c (wait_on_socket): Take timeout as parameter.
	(__readall): If reading failed due to EAGAIN error wait a bit
	and possibly try again.
	(__readvall): Likewise.
-rw-r--r--ChangeLog8
-rw-r--r--nscd/nscd_helper.c103
2 files changed, 76 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog
index ede6541374..b0400a1c02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-10-13  Ulrich Drepper  <drepper@redhat.com>
+
+	[BZ #3242]
+	* nscd/nscd_helper.c (wait_on_socket): Take timeout as parameter.
+	(__readall): If reading failed due to EAGAIN error wait a bit
+	and possibly try again.
+	(__readvall): Likewise.
+
 2007-10-13  Bruno Haible  <bruno@clisp.org>
 
 	* intl/dcigettext.c (_nl_find_msg): Unlock the conversions_lock
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index 6718d922f3..b499f9cf99 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -38,6 +38,45 @@
 #include "nscd-client.h"
 
 
+/* Extra time we wait if the socket is still receiving data.  This
+   value is in microseconds.  Note that the other side is nscd on the
+   local machine and it is already transmitting data.  So the wait
+   time need not be long.  */
+#define EXTRA_RECEIVE_TIME 200
+
+
+static int
+wait_on_socket (int sock, long int usectmo)
+{
+  struct pollfd fds[1];
+  fds[0].fd = sock;
+  fds[0].events = POLLIN | POLLERR | POLLHUP;
+  int n = __poll (fds, 1, usectmo);
+  if (n == -1 && __builtin_expect (errno == EINTR, 0))
+    {
+      /* Handle the case where the poll() call is interrupted by a
+	 signal.  We cannot just use TEMP_FAILURE_RETRY since it might
+	 lead to infinite loops.  */
+      struct timeval now;
+      (void) __gettimeofday (&now, NULL);
+      long int end = now.tv_sec * 1000 + usectmo + (now.tv_usec + 500) / 1000;
+      long int timeout = usectmo;
+      while (1)
+	{
+	  n = __poll (fds, 1, timeout);
+	  if (n != -1 || errno != EINTR)
+	    break;
+
+	  /* Recompute the timeout time.  */
+	  (void) __gettimeofday (&now, NULL);
+	  timeout = end - (now.tv_sec * 1000 + (now.tv_usec + 500) / 1000);
+	}
+    }
+
+  return n;
+}
+
+
 ssize_t
 __readall (int fd, void *buf, size_t len)
 {
@@ -45,9 +84,17 @@ __readall (int fd, void *buf, size_t len)
   ssize_t ret;
   do
     {
+    again:
       ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
       if (ret <= 0)
-	break;
+	{
+	  if (__builtin_expect (ret < 0 && errno == EAGAIN, 0)
+	      /* The socket is still receiving data.  Wait a bit more.  */
+	      && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
+	    goto again;
+
+	  break;
+	}
       buf = (char *) buf + ret;
       n -= ret;
     }
@@ -61,7 +108,15 @@ __readvall (int fd, const struct iovec *iov, int iovcnt)
 {
   ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
   if (ret <= 0)
-    return ret;
+    {
+      if (__builtin_expect (ret == 0 || errno != EAGAIN, 1))
+	/* A genuine error or no data to read.  */
+	return ret;
+
+      /* The data has not all yet been received.  Do as if we have not
+	 read anything yet.  */
+      ret = 0;
+    }
 
   size_t total = 0;
   for (int i = 0; i < iovcnt; ++i)
@@ -83,9 +138,17 @@ __readvall (int fd, const struct iovec *iov, int iovcnt)
 	    }
 	  iovp->iov_base = (char *) iovp->iov_base + r;
 	  iovp->iov_len -= r;
+	again:
 	  r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
 	  if (r <= 0)
-	    break;
+	    {
+	      if (__builtin_expect (r < 0 && errno == EAGAIN, 0)
+		  /* The socket is still receiving data.  Wait a bit more.  */
+		  && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
+		goto again;
+
+	      break;
+	    }
 	  ret += r;
 	}
       while (ret < total);
@@ -187,36 +250,6 @@ __nscd_unmap (struct mapped_database *mapped)
 }
 
 
-static int
-wait_on_socket (int sock)
-{
-  struct pollfd fds[1];
-  fds[0].fd = sock;
-  fds[0].events = POLLIN | POLLERR | POLLHUP;
-  int n = __poll (fds, 1, 5 * 1000);
-  if (n == -1 && __builtin_expect (errno == EINTR, 0))
-    {
-      /* Handle the case where the poll() call is interrupted by a
-	 signal.  We cannot just use TEMP_FAILURE_RETRY since it might
-	 lead to infinite loops.  */
-      struct timeval now;
-      (void) __gettimeofday (&now, NULL);
-      long int end = (now.tv_sec + 5) * 1000 + (now.tv_usec + 500) / 1000;
-      while (1)
-	{
-	  long int timeout = end - (now.tv_sec * 1000
-				    + (now.tv_usec + 500) / 1000);
-	  n = __poll (fds, 1, timeout);
-	  if (n != -1 || errno != EINTR)
-	    break;
-	  (void) __gettimeofday (&now, NULL);
-	}
-    }
-
-  return n;
-}
-
-
 /* Try to get a file descriptor for the shared meory segment
    containing the database.  */
 static struct mapped_database *
@@ -265,7 +298,7 @@ get_mapping (request_type type, const char *key,
 
   msg.msg_controllen = cmsg->cmsg_len;
 
-  if (wait_on_socket (sock) <= 0)
+  if (wait_on_socket (sock, 5 * 1000) <= 0)
     goto out_close2;
 
 # ifndef MSG_CMSG_CLOEXEC
@@ -497,7 +530,7 @@ __nscd_open_socket (const char *key, size_t keylen, request_type type,
   if (sock >= 0)
     {
       /* Wait for data.  */
-      if (wait_on_socket (sock) > 0)
+      if (wait_on_socket (sock, 5 * 1000) > 0)
 	{
 	  ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
 						       responselen));