Hello,

One of the most usual errors found by Hurd's developers is the "zalloc's
panic" one. I think that this panic could be (usually) related with the
extremly high number of threads that some translators (i.e. ext2fs)
spawn when there's a significant amount number of activity over it
(already discussed here
http://lists.gnu.org/archive/html/bug-hurd/2002-04/msg00003.html and
http://lists.gnu.org/archive/html/bug-hurd/2002-06/msg00263.html).
Antrik have also done a research about this issue
( http://hurd.gnufans.org/bin/view/Hurd/ZallocPanics ).

This is an experimental (just for testing) patch that (I hope) helps
with debuging this issue, and also seems to make the system a little
more robust. 

It is extremly simple. Everytime a thread is going to serve a request,
it checks if nreqthreads == 0, and spawns a new thread if true. But
before spawning the new thread, it increments nreqthreads by 1 (to count
the new thread), so until this new thread receives a request
(nreqthreads is decremented at internal_demuxer), more threads can't be
created. What we do is, if a certain number of threads are already
spawned (THREAD_DELAY), we put the new thread to sleep for a time
(DELAY), so we're implicity delaying threads creation, giving time to
other threads to finish their requests.

On some machines (fast processor, slow I/O, or both), this isn't enough
to avoid a slowly but constant thread incrementation due to Mach's
pageouts, so a fixed limit is needed (THREAD_MAX) for self-paged
translators.

It's recommended to play with this values (THREAD_DELAY, THREAD_MAX,
DELAY) and enable debug (LP_DEBUG) to see how new threads are created.

Happy hacking!
--- manage-multithread.c.orig	2005-08-10 13:38:18.000000000 +0200
+++ manage-multithread.c	2005-08-10 13:34:30.000000000 +0200
@@ -23,6 +23,19 @@
 #include <assert.h>
 #include <cthreads.h>
 #include <mach/message.h>
+#include <unistd.h> 		/* For sleep() */
+
+#define LP_DEBUG	0
+
+#if LP_DEBUG
+#include <stdio.h>		/* For printf() */
+#endif
+
+#define THREAD_MAX	250	/* Maximum number of threads */
+#define THREAD_DELAY 	64	/* Number of threads created as needed
+                                   without delay */
+#define DELAY		2	/* Time to sleep() each delayed thread
+                                   (in seconds) */
 
 void
 ports_manage_port_operations_multithread (struct port_bucket *bucket,
@@ -43,6 +56,7 @@
     {
       int spawn = 0;
       int status;
+      int type = 0; 	/* 0 = standard, 1 = master, 2 = delayed */
       struct port_info *pi;
       struct rpc_info link;
       register mig_reply_header_t *outp = (mig_reply_header_t *) outheadp;
@@ -59,8 +73,11 @@
       spin_lock (&lock);
       assert (nreqthreads);
       nreqthreads--;
-      if (nreqthreads == 0)
-	spawn = 1;
+      if (nreqthreads == 0 && totalthreads <= THREAD_MAX) {
+      	spawn = 1;
+      	if (totalthreads >= THREAD_DELAY)
+      	  type = 2;
+      }
       spin_unlock (&lock);
 
       if (spawn)
@@ -69,7 +86,8 @@
 	  totalthreads++;
 	  nreqthreads++;
 	  spin_unlock (&lock);
-	  cthread_detach (cthread_fork ((cthread_fn_t) thread_function, 0));
+	  cthread_detach (cthread_fork ((cthread_fn_t) thread_function,
+	                                (any_t)(intptr_t) type));
 	}
       
       /* Fill in default response. */
@@ -117,15 +135,31 @@
     }
 
   int
-  thread_function (int master)
+  thread_function (int type)
     {
       int timeout;
       error_t err;
-
+      
+      if (type == 2) {
+#if LP_DEBUG
+        printf("libports: delayed thread number: %d || ", totalthreads);
+        fflush(stdout);
+#endif  
+        sleep(DELAY);	/* Take a little break */
+#if LP_DEBUG
+        printf("libports: delayed thread running (%d)\n", totalthreads);
+        fflush(stdout);
+#endif
+      }
+#if LP_DEBUG
+      else {
+        printf("libports: new thread without delay running\n");
+      }
+#endif
       if (hook)
 	(*hook) ();
 
-      if (master)
+      if (type == 1)
 	timeout = global_timeout;
       else
 	timeout = thread_timeout;
@@ -138,7 +172,7 @@
 				       timeout);
       while (err != MACH_RCV_TIMED_OUT);
 
-      if (master)
+      if (type == 1)
 	{
 	  spin_lock (&lock);
 	  if (totalthreads != 1)
_______________________________________________
Bug-hurd mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-hurd

Reply via email to