summary refs log tree commit diff
path: root/nscd
diff options
context:
space:
mode:
Diffstat (limited to 'nscd')
-rw-r--r--nscd/connections.c35
-rw-r--r--nscd/nscd.conf4
-rw-r--r--nscd/nscd.h4
-rw-r--r--nscd/nscd_conf.c8
-rw-r--r--nscd/nscd_stat.c22
5 files changed, 55 insertions, 18 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index ace69fb455..45042beaab 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -69,6 +69,8 @@ static gid_t *server_groups;
 #endif
 static int server_ngroups;
 
+static pthread_attr_t attr;
+
 static void begin_drop_privileges (void);
 static void finish_drop_privileges (void);
 
@@ -167,8 +169,10 @@ static struct database_dyn *const serv2db[LASTREQ] =
 #define CACHE_PRUNE_INTERVAL	15
 
 
-/* Number of threads to use.  */
+/* Initial number of threads to use.  */
 int nthreads = -1;
+/* Maximum number of threads to use.  */
+int max_nthreads = 32;
 
 /* Socket for incoming connections.  */
 static int sock;
@@ -1206,6 +1210,19 @@ fd_ready (int fd)
     {
       ++client_queued;
       do_signal = false;
+
+      /* Try to start another thread to help out.  */
+      pthread_t th;
+      if (nthreads < max_nthreads
+	  && pthread_create (&th, &attr, nscd_run,
+			     (void *) (long int) nthreads) == 0)
+	{
+	  /* We got another thread.  */
+	  ++nthreads;
+	  /* The new thread might new a kick.  */
+	  do_signal = true;
+	}
+
     }
 
   pthread_mutex_unlock (&readylist_lock);
@@ -1452,21 +1469,29 @@ start_threads (void)
 
   /* Create the attribute for the threads.  They are all created
      detached.  */
-  pthread_attr_t attr;
   pthread_attr_init (&attr);
   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+  /* Use 1MB stacks, twice as much for 64-bit architectures.  */
+  pthread_attr_setstacksize (&attr, 1024 * 1024 * (sizeof (void *) / 4));
 
   /* We allow less than LASTDB threads only for debugging.  */
   if (debug_level == 0)
     nthreads = MAX (nthreads, lastdb);
 
+  int nfailed = 0;
   for (long int i = 0; i < nthreads; ++i)
     {
       pthread_t th;
-      pthread_create (&th, &attr, nscd_run, (void *) i);
+      if (pthread_create (&th, &attr, nscd_run, (void *) (i - nfailed)) != 0)
+	++nfailed;
+    }
+  if (nthreads - nfailed < lastdb)
+    {
+      /* We could not start enough threads.  */
+      dbg_log (_("could only start %d threads; terminating"),
+	       nthreads - nfailed);
+      exit (1);
     }
-
-  pthread_attr_destroy (&attr);
 
   /* Determine how much room for descriptors we should initially
      allocate.  This might need to change later if we cap the number
diff --git a/nscd/nscd.conf b/nscd/nscd.conf
index 35f65a4a36..87e7a84487 100644
--- a/nscd/nscd.conf
+++ b/nscd/nscd.conf
@@ -7,7 +7,8 @@
 #
 #	logfile			<file>
 #	debug-level		<level>
-#	threads			<#threads to use>
+#	threads			<initial #threads to use>
+#	max-threads		<maximum #threads to use>
 #	server-user             <user to run server as instead of root>
 #		server-user is ignored if nscd is started with -S parameters
 #       stat-user               <user who is allowed to request statistics>
@@ -29,6 +30,7 @@
 
 #	logfile			/var/log/nscd.log
 #	threads			6
+#	max-threads		128
 #	server-user		nobody
 #	stat-user		somebody
 	debug-level		0
diff --git a/nscd/nscd.h b/nscd/nscd.h
index 56073ebd0c..4e00f69fb9 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -102,8 +102,10 @@ extern const struct iovec grp_iov_disabled;
 extern const struct iovec hst_iov_disabled;
 
 
-/* Number of threads to run.  */
+/* Initial number of threads to run.  */
 extern int nthreads;
+/* Maximum number of threads to use.  */
+extern int max_nthreads;
 
 /* Tables for which we cache data with uid.  */
 extern int secure_in_use; /* Is one of the above 1?  */
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
index 591dea8d64..d21f2fc501 100644
--- a/nscd/nscd_conf.c
+++ b/nscd/nscd_conf.c
@@ -184,6 +184,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
 	  if (nthreads == -1)
 	    nthreads = MAX (atol (arg1), lastdb);
 	}
+      else if (strcmp (entry, "max-threads") == 0)
+	{
+	  max_nthreads = MAX (atol (arg1), lastdb);
+	}
       else if (strcmp (entry, "server-user") == 0)
         {
           if (!arg1)
@@ -282,6 +286,10 @@ cannot get current working directory: %s; disabling paranoia mode"),
 	}
     }
 
+  /* Enforce sanity.  */
+  if (max_nthreads < nthreads)
+    max_nthreads = nthreads;
+
   /* Free the buffer.  */
   free (line);
   /* Close configuration file.  */
diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
index a56a381b25..9231642278 100644
--- a/nscd/nscd_stat.c
+++ b/nscd/nscd_stat.c
@@ -143,8 +143,8 @@ receive_print_stats (void)
   int fd;
   int i;
   uid_t uid = getuid ();
-  const char *yesstr = _("     yes");
-  const char *nostr = _("      no");
+  const char *yesstr = nl_langinfo (YESSTR);
+  const char *nostr = nl_langinfo (NOSTR);
 
   /* Find out whether there is another user but root allowed to
      request statistics.  */
@@ -225,22 +225,22 @@ receive_print_stats (void)
   else
     printf (_("            %2lus  server runtime\n"), diff);
 
-  printf (_("%15lu  number of times clients had to wait\n"
+  printf (_("%15d  current number of threads\n"
+	    "%15d  maximum number of threads\n"
+	    "%15lu  number of times clients had to wait\n"
 	    "%15s  paranoia mode enabled\n"
 	    "%15lu  restart internal\n"),
-	  data.client_queued, paranoia ? yesstr : nostr,
-	  (unsigned long int) restart_interval);
+	  nthreads, max_nthreads, data.client_queued,
+	  paranoia ? yesstr : nostr, (unsigned long int) restart_interval);
 
   for (i = 0; i < lastdb; ++i)
     {
       unsigned long int hit = data.dbs[i].poshit + data.dbs[i].neghit;
       unsigned long int all = hit + data.dbs[i].posmiss + data.dbs[i].negmiss;
-      const char *enabled = nl_langinfo (data.dbs[i].enabled ? YESSTR : NOSTR);
-      const char *check_file = nl_langinfo (data.dbs[i].check_file
-					    ? YESSTR : NOSTR);
-      const char *shared = nl_langinfo (data.dbs[i].shared ? YESSTR : NOSTR);
-      const char *persistent = nl_langinfo (data.dbs[i].persistent
-					    ? YESSTR : NOSTR);
+      const char *enabled = data.dbs[i].enabled ? yesstr : nostr;
+      const char *check_file = data.dbs[i].check_file ? yesstr : nostr;
+      const char *shared = data.dbs[i].shared ? yesstr : nostr;
+      const char *persistent = data.dbs[i].persistent ? yesstr : nostr;
 
       if (enabled[0] == '\0')
 	/* The locale does not provide this information so we have to