about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-04-28 02:43:30 +0000
committerUlrich Drepper <drepper@redhat.com>2003-04-28 02:43:30 +0000
commit0fdb4f42e49b92035f8531f086647e30da169693 (patch)
tree5423b2803cceb06a766865a140b8742a9e1f2403
parentbf7725a9bca677ec1a28805c881036d3e518580c (diff)
downloadglibc-0fdb4f42e49b92035f8531f086647e30da169693.tar.gz
glibc-0fdb4f42e49b92035f8531f086647e30da169693.tar.xz
glibc-0fdb4f42e49b92035f8531f086647e30da169693.zip
(client_queued): New variable. (nscd_run): Revamp the loop. Don't call poll except for cleanup threads. Keep track of the number of delays caused because of busy worker threads.
-rw-r--r--nscd/connections.c222
1 files changed, 122 insertions, 100 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index 3628877dab..c80ba96dc5 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -19,6 +19,7 @@
    02111-1307 USA.  */
 
 #include <assert.h>
+#include <atomic.h>
 #include <error.h>
 #include <errno.h>
 #include <grp.h>
@@ -130,6 +131,9 @@ int nthreads = -1;
 /* Socket for incoming connections.  */
 static int sock;
 
+/* Number of times clients had to wait.  */
+unsigned long int client_queued;
+
 
 /* Initialize database information structures.  */
 void
@@ -435,145 +439,163 @@ nscd_run (void *p)
   long int my_number = (long int) p;
   struct pollfd conn;
   int run_prune = my_number < lastdb && dbs[my_number].enabled;
-  time_t now = time (NULL);
-  time_t next_prune = now + CACHE_PRUNE_INTERVAL;
-  int timeout = run_prune ? 1000 * (next_prune - now) : -1;
+  time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
+  static unsigned long int nready;
 
   conn.fd = sock;
   conn.events = POLLRDNORM;
 
   while (1)
     {
-      int nr = poll (&conn, 1, timeout);
+      int nr;
+
+      /* One more thread available.  */
+      atomic_increment (&nready);
+
+    no_conn:
+      if (run_prune)
+	do
+	  {
+	    time_t now = time (NULL);
+	    int timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
+
+	    nr = poll (&conn, 1, timeout);
+
+	    if (nr == 0)
+	      {
+		/* The `poll' call timed out.  It's time to clean up the
+		   cache.  */
+		atomic_decrement (&nready);
+		assert (my_number < lastdb);
+		prune_cache (&dbs[my_number], time(NULL));
+		now = time (NULL);
+		next_prune = now + CACHE_PRUNE_INTERVAL;
+		goto try_get;
+	      }
+	  }
+	while ((conn.revents & POLLRDNORM) == 0);
+
+    got_data:;
+      /* We have a new incoming connection.  Accept the connection.  */
+      int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
+      request_header req;
+      char buf[256];
+      uid_t uid = 0;
+#ifdef SO_PEERCRED
+      pid_t pid = 0;
+#endif
 
-      if (nr == 0)
+      if (__builtin_expect (fd, 0) < 0)
 	{
-	  /* The `poll' call timed out.  It's time to clean up the cache.  */
-	  assert (my_number < lastdb);
-	  now = time (NULL);
-	  prune_cache (&dbs[my_number], now);
-	  next_prune = now + CACHE_PRUNE_INTERVAL;
-	  timeout = 1000 * (next_prune - now);
-	  continue;
+	  dbg_log (_("while accepting connection: %s"),
+		   strerror_r (errno, buf, sizeof (buf)));
+	  goto no_conn;
 	}
 
-      /* We have a new incoming connection.  */
-      if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
+      /* This thread is busy.  */
+      atomic_decrement (&nready);
+
+      /* Now read the request.  */
+      if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
+			    != sizeof (req), 0))
 	{
-	  /* Accept the connection.  */
-	  int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
-	  request_header req;
-	  char buf[256];
-	  uid_t uid = 0;
+	  if (debug_level > 0)
+	    dbg_log (_("short read while reading request: %s"),
+		     strerror_r (errno, buf, sizeof (buf)));
+	  close (fd);
+	  continue;
+	}
+
+      /* Some systems have no SO_PEERCRED implementation.  They don't
+	 care about security so we don't as well.  */
 #ifdef SO_PEERCRED
-	  pid_t pid = 0;
-#endif
+      if (secure_in_use)
+	{
+	  struct ucred caller;
+	  socklen_t optlen = sizeof (caller);
 
-	  if (__builtin_expect (fd, 0) < 0)
+	  if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
 	    {
-	      dbg_log (_("while accepting connection: %s"),
+	      dbg_log (_("error getting callers id: %s"),
 		       strerror_r (errno, buf, sizeof (buf)));
-	      continue;
-	    }
-
-	  /* Now read the request.  */
-	  if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req,
-							  sizeof (req)))
-				!= sizeof (req), 0))
-	    {
-	      if (debug_level > 0)
-		dbg_log (_("short read while reading request: %s"),
-			 strerror_r (errno, buf, sizeof (buf)));
 	      close (fd);
 	      continue;
 	    }
 
-	  /* Some systems have no SO_PEERCRED implementation.  They don't
-	     care about security so we don't as well.  */
-#ifdef SO_PEERCRED
-	  if (secure_in_use)
-	    {
-	      struct ucred caller;
-	      socklen_t optlen = sizeof (caller);
-
-	      if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
-			      &caller, &optlen) < 0)
-		{
-		  dbg_log (_("error getting callers id: %s"),
-			   strerror_r (errno, buf, sizeof (buf)));
-		  close (fd);
-		  continue;
-		}
-
-	      if (req.type < GETPWBYNAME || req.type > LASTDBREQ
-		  || secure[serv2db[req.type]])
-		uid = caller.uid;
+	  if (req.type < GETPWBYNAME || req.type > LASTDBREQ
+	      || secure[serv2db[req.type]])
+	    uid = caller.uid;
 
 	      pid = caller.pid;
-	    }
-	  else if (__builtin_expect (debug_level > 0, 0))
-	    {
-	      struct ucred caller;
-	      socklen_t optlen = sizeof (caller);
+	}
+      else if (__builtin_expect (debug_level > 0, 0))
+	{
+	  struct ucred caller;
+	  socklen_t optlen = sizeof (caller);
 
-	      if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
-			      &caller, &optlen) == 0)
-		pid = caller.pid;
-	    }
+	  if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
+	    pid = caller.pid;
+	}
 #endif
 
-	  /* It should not be possible to crash the nscd with a silly
-	     request (i.e., a terribly large key).  We limit the size
-	     to 1kb.  */
-	  if (__builtin_expect (req.key_len, 1) < 0
-	      || __builtin_expect (req.key_len, 1) > 1024)
+      /* It should not be possible to crash the nscd with a silly
+	 request (i.e., a terribly large key).  We limit the size to 1kb.  */
+      if (__builtin_expect (req.key_len, 1) < 0
+	  || __builtin_expect (req.key_len, 1) > 1024)
+	{
+	  if (debug_level > 0)
+	    dbg_log (_("key length in request too long: %d"), req.key_len);
+	  close (fd);
+	  continue;
+	}
+      else
+	{
+	  /* Get the key.  */
+	  char keybuf[req.key_len];
+
+	  if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
+							  req.key_len))
+				!= req.key_len, 0))
 	    {
 	      if (debug_level > 0)
-		dbg_log (_("key length in request too long: %d"), req.key_len);
+		dbg_log (_("short read while reading request key: %s"),
+			 strerror_r (errno, buf, sizeof (buf)));
 	      close (fd);
 	      continue;
 	    }
-	  else
+
+	  if (__builtin_expect (debug_level, 0) > 0)
 	    {
-	      /* Get the key.  */
-	      char keybuf[req.key_len];
-
-	      if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
-							      req.key_len))
-				    != req.key_len, 0))
-		{
-		  if (debug_level > 0)
-		    dbg_log (_("short read while reading request key: %s"),
-			     strerror_r (errno, buf, sizeof (buf)));
-		  close (fd);
-		  continue;
-		}
-
-	      if (__builtin_expect (debug_level, 0) > 0)
-		{
 #ifdef SO_PEERCRED
-		  if (pid != 0)
-		    dbg_log (_("\
+	      if (pid != 0)
+		dbg_log (_("\
 handle_request: request received (Version = %d) from PID %ld"),
-			     req.version, (long int) pid);
-		  else
+			 req.version, (long int) pid);
+	      else
 #endif
-		    dbg_log (_("\
+		dbg_log (_("\
 handle_request: request received (Version = %d)"), req.version);
-		}
+	    }
 
-	      /* Phew, we got all the data, now process it.  */
-	      handle_request (fd, &req, keybuf, uid);
+	  /* Phew, we got all the data, now process it.  */
+	  handle_request (fd, &req, keybuf, uid);
 
-	      /* We are done.  */
-	      close (fd);
-	    }
+	  /* We are done.  */
+	  close (fd);
 	}
 
-      if (run_prune)
+      /* Just determine whether any data is present.  We do this to
+	 measure whether clients are queued up.  */
+    try_get:
+      nr = poll (&conn, 1, 0);
+      if (nr != 0)
 	{
-	  now = time (NULL);
-	  timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
+	  if (nready == 0)
+	    ++client_queued;
+
+	  atomic_increment (&nready);
+
+	  goto got_data;
 	}
     }
 }