diff -urN user/thttpd/libhttpd.c user/thttpd/libhttpd.c
--- user/thttpd/libhttpd.c	2008-06-11 21:27:34.000000000 -0400
+++ user/thttpd/libhttpd.c	2008-10-29 14:04:03.000000000 -0400
@@ -83,6 +83,11 @@
 #include "timers.h"
 #include "match.h"
 #include "tdate_parse.h"
+#include "fdwatch.h"
+
+#ifndef READ_TIMEOUT
+#define READ_TIMEOUT 5000 /* 5000 ms*/
+#endif
 
 #ifndef STDIN_FILENO
 #define STDIN_FILENO 0
@@ -3316,8 +3321,13 @@
     (void) httpd_write_fully( hc->conn_fd, headers, headers_len );
 
     /* Echo the rest of the output. */
+    fdwatch_add_fd(rfd, (void*) 0, FDW_READ);
     for (;;)
 	{
+        int num_ready = fdwatch( READ_TIMEOUT);
+        if(num_ready == 0) break;
+        if( num_ready < 0 || !fdwatch_check_fd(rfd)) continue;
+
 	r = read( rfd, buf, sizeof(buf) );
 	if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
 	    {
@@ -3329,9 +3339,77 @@
 	if ( httpd_write_fully( hc->conn_fd, buf, r ) != r )
 	    break;
 	}
+    fdwatch_del_fd(rfd);
     shutdown( hc->conn_fd, SHUT_WR );
     }
 
+static void 
+cgi_do_exec( httpd_conn* hc, char** argp )
+	{
+    char** envp;
+    char* binary;
+    char* directory;
+
+    /* Make the environment vector. */
+    envp = make_envp( hc );
+
+    /* At this point we would like to set close-on-exec again for hc->conn_fd
+    ** (see previous comments on Linux's broken behavior re: close-on-exec
+    ** and dup.)  Unfortunately there seems to be another Linux problem, or
+    ** perhaps a different aspect of the same problem - if we do this
+    ** close-on-exec in Linux, the socket stays open but stderr gets
+    ** closed - the last fd duped from the socket.  What a mess.  So we'll
+    ** just leave the socket as is, which under other OSs means an extra
+    ** file descriptor gets passed to the child process.  Since the child
+    ** probably already has that file open via stdin stdout and/or stderr,
+    ** this is not a problem.
+    */
+    /* (void) fcntl( hc->conn_fd, F_SETFD, 1 ); */
+
+#ifdef CGI_NICE
+    /* Set priority. */
+    (void) nice( CGI_NICE );
+#endif /* CGI_NICE */
+
+    /* Split the program into directory and binary, so we can chdir()
+    ** to the program's own directory.  This isn't in the CGI 1.1
+    ** spec, but it's what other HTTP servers do.
+    */
+    directory = strdup( hc->expnfilename );
+    if ( directory == (char*) 0 )
+	binary = hc->expnfilename;      /* ignore errors */
+    else
+	{
+	binary = strrchr( directory, '/' );
+	if ( binary == (char*) 0 )
+	    binary = hc->expnfilename;
+	else
+	    {
+	    *binary++ = '\0';
+	    (void) chdir( directory );  /* ignore errors */
+	    }
+	}
+
+    /* Default behavior for SIGPIPE. */
+#ifdef HAVE_SIGSET
+    (void) sigset( SIGPIPE, SIG_DFL );
+#else /* HAVE_SIGSET */
+    (void) signal( SIGPIPE, SIG_DFL );
+#endif /* HAVE_SIGSET */
+
+    /* Run the program. */
+    (void) execve( binary, argp, envp );
+
+    /* Something went wrong. */
+    syslog( LOG_ERR, "execve %.80s - %m", hc->expnfilename );
+    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+    httpd_write_response( hc );
+#ifdef __uClinux__
+	_exit( 1 );
+#else
+    exit( 1 );
+#endif
+	}
 
 /* CGI child process. */
 static void
@@ -3339,9 +3417,6 @@
     {
     int r;
     char** argp;
-    char** envp;
-    char* binary;
-    char* directory;
 
     /* Unset close-on-exec flag for this socket.  This actually shouldn't
     ** be necessary, according to POSIX a dup()'d file descriptor does
@@ -3352,6 +3427,7 @@
     */
     (void) fcntl( hc->conn_fd, F_SETFD, 0 );
 
+#ifndef __uClinux__
     /* Close the syslog descriptor so that the CGI program can't
     ** mess with it.  All other open descriptors should be either
     ** the listen socket(s), sockets from accept(), or the file-logging
@@ -3359,6 +3435,7 @@
     ** have to close anything else.
     */
     closelog();
+#endif
 
     /* If the socket happens to be using one of the stdin/stdout/stderr
     ** descriptors, move it to another descriptor so that the dup2 calls
@@ -3377,9 +3454,6 @@
 	*/
 	}
 
-    /* Make the environment vector. */
-    envp = make_envp( hc );
-
     /* Make the argument vector. */
     argp = make_argp( hc );
 
@@ -3396,13 +3470,18 @@
 	    syslog( LOG_ERR, "pipe - %m" );
 	    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
 	    httpd_write_response( hc );
+#ifdef __uClinux__
+		_exit( 1 );
+#else
 	    exit( 1 );
-	    }
+#endif
+	    }	/* Need to schedule a kill for process r; but in the main process! */
+
 #ifdef __uClinux__
-	r = vfork( );
+	/* we can't fork in parallel under uClinux, so we'll need to process up front */
+	cgi_interpose_input( hc, p[1] );
 #else
 	r = fork( );
-#endif
 	if ( r < 0 )
 	    {
 	    syslog( LOG_ERR, "fork - %m" );
@@ -3419,6 +3498,7 @@
 	    exit( 0 );
 	    }
 	/* Need to schedule a kill for process r; but in the main process! */
+#endif
 	(void) close( p[1] );
 	if ( p[0] != STDIN_FILENO )
 	    {
@@ -3445,13 +3525,48 @@
 	    syslog( LOG_ERR, "pipe - %m" );
 	    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
 	    httpd_write_response( hc );
+#ifdef __uClinux__
+		_exit( 1 );
+#else
 	    exit( 1 );
+#endif
 	    }
 #ifdef __uClinux__
+	/* Oohkay, this is a little tricky.  Again, we can't parallel fork, so
+	** we'll need to spawn the CGI app (with vfork) and then do our output
+	** processing when we get control back.  Sadly this means that the user
+	** won't see any output at all until we're all done...
+	*/
 	r = vfork( );
+	if ( r < 0 )
+	    {
+	    syslog( LOG_ERR, "vfork - %m" );
+	    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
+	    httpd_write_response( hc );
+	    _exit( 1 );
+	    }
+	if ( r == 0 )
+	    {
+	    /* CGI exec process. */
+		(void) close( p[0] );
+		if ( p[1] != STDOUT_FILENO )
+		    (void) dup2( p[1], STDOUT_FILENO );
+		if ( p[1] != STDERR_FILENO )
+		    (void) dup2( p[1], STDERR_FILENO );
+		if ( p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO )
+		    (void) close( p[1] );
+	    sub_process = 1;
+		cgi_do_exec( hc, argp );
+		_exit( 0 );
+		}
+
+	(void) close( p[1] );
+	/* And finally we'll do the output processing */
+    cgi_interpose_output( hc, p[0] );
+	(void) close( p[0] );
+	_exit( 0 );
 #else
 	r = fork( );
-#endif
 	if ( r < 0 )
 	    {
 	    syslog( LOG_ERR, "fork - %m" );
@@ -3475,6 +3590,7 @@
 	    (void) dup2( p[1], STDERR_FILENO );
 	if ( p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO )
 	    (void) close( p[1] );
+#endif
 	}
     else
 	{
@@ -3485,58 +3601,7 @@
 	    (void) dup2( hc->conn_fd, STDERR_FILENO );
 	}
 
-    /* At this point we would like to set close-on-exec again for hc->conn_fd
-    ** (see previous comments on Linux's broken behavior re: close-on-exec
-    ** and dup.)  Unfortunately there seems to be another Linux problem, or
-    ** perhaps a different aspect of the same problem - if we do this
-    ** close-on-exec in Linux, the socket stays open but stderr gets
-    ** closed - the last fd duped from the socket.  What a mess.  So we'll
-    ** just leave the socket as is, which under other OSs means an extra
-    ** file descriptor gets passed to the child process.  Since the child
-    ** probably already has that file open via stdin stdout and/or stderr,
-    ** this is not a problem.
-    */
-    /* (void) fcntl( hc->conn_fd, F_SETFD, 1 ); */
-
-#ifdef CGI_NICE
-    /* Set priority. */
-    (void) nice( CGI_NICE );
-#endif /* CGI_NICE */
-
-    /* Split the program into directory and binary, so we can chdir()
-    ** to the program's own directory.  This isn't in the CGI 1.1
-    ** spec, but it's what other HTTP servers do.
-    */
-    directory = strdup( hc->expnfilename );
-    if ( directory == (char*) 0 )
-	binary = hc->expnfilename;      /* ignore errors */
-    else
-	{
-	binary = strrchr( directory, '/' );
-	if ( binary == (char*) 0 )
-	    binary = hc->expnfilename;
-	else
-	    {
-	    *binary++ = '\0';
-	    (void) chdir( directory );  /* ignore errors */
-	    }
-	}
-
-    /* Default behavior for SIGPIPE. */
-#ifdef HAVE_SIGSET
-    (void) sigset( SIGPIPE, SIG_DFL );
-#else /* HAVE_SIGSET */
-    (void) signal( SIGPIPE, SIG_DFL );
-#endif /* HAVE_SIGSET */
-
-    /* Run the program. */
-    (void) execve( binary, argp, envp );
-
-    /* Something went wrong. */
-    syslog( LOG_ERR, "execve %.80s - %m", hc->expnfilename );
-    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
-    httpd_write_response( hc );
-    exit( 1 );
+	cgi_do_exec( hc, argp );
     }
 
 
@@ -3545,6 +3610,15 @@
     {
     int r;
     ClientData client_data;
+#ifdef __uClinux__
+	/* this is not super-safe, but we're relying on the pointers at least staying
+	** read-only.  hopefully the contained code only fiddles with the file descriptors
+	** and other integer fields.
+	*/
+	httpd_server forked_hs = *hc->hs;
+	httpd_conn forked_hc = *hc;
+	forked_hc.hs = &forked_hs;
+#endif
 
     if ( hc->method == METHOD_GET || hc->method == METHOD_POST )
 	{
@@ -3573,11 +3647,17 @@
 	    {
 	    /* Child process. */
 	    sub_process = 1;
+#ifdef __uClinux__
+	    httpd_unlisten( &forked_hs );
+	    cgi_child( &forked_hc );
+#else
 	    httpd_unlisten( hc->hs );
 	    cgi_child( hc );
+#endif
 	    }
 
 	/* Parent process. */
+	sub_process = 0;
 	syslog( LOG_INFO, "spawned CGI process %d for file '%.200s'", r, hc->expnfilename );
 #ifdef CGI_TIMELIMIT
 	/* Schedule a kill for the child process, in case it runs too long */
