httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@engelschall.com (Ralf S. Engelschall)
Subject [PATCH] FreeBSD and SIGPIPE: perhaps solved?
Date Sat, 12 Apr 1997 11:43:28 GMT

While currently developing the new net.sw (http://www.netsw.org/) which
entirely consists of CGI programs I want to make sure that Apache runs fine
with FreeBSD. The machine runs a 1.2b8 under 2.2.1-RELEASE.

I wrote a little test CGI script in Perl which does nothing except setting up
a signal handler for SIGPIPE and then endlessly loops with "print STDOUT ...;
sleep(1)".  When it gets run and I close the client connection (hit Stop
button on Netscape Navigator or "quit" in Telnet), Apache recognizes the
closed connection (error log says "send body lost connection to client
en1.engelschall.com"), but then both the CGI process and the Apache process
are frozen. A simple "top" shows that the CGI process is still in state
"pipewr" while the Apache process is also still in state "piperd". First I
thought they had never seen the client connection lost and just go on with
processing to nirvana (i.e. the CGI writes to its stdout which is connected to
Apache's script_in file descriptor).

But after tracing down mod_cgi I found that the "pipewr" of the CGI program is
the write to its stdout as expected, because it still has not received a
SIGPIPE and still wants to do its "print STDOUT ...". BUT: The "piperd" of the
Apache process is not the fread() from send_fd(). Actually it is the fread()
in mod_cgi which wants to soak the stderr of the CGI script. DEAD LOOP,
because the close of script_in is placed _after_ this fread-loop in mod_cgi!
So the CGI waits until Apache reads more from script_in while Apache reads
from script_err. The only solutions are either a timeout in Apache or a
SIGPIPE for the CGI script. But the SIGPIPE will not happen until Apache does
the close(script_in) in mod_cgi. And the timeout does also not happen.

I currently don't know (have not traced down any more) why no timeout on the
soaking of the scripts stderr happens, but a possible workaround would be to
interchange the order of script_err-soaking and script_in-closing. This worked
fine here. The CGI script gets its SIGPIPE and the Apache process is not
frozen.

Here is the possible patch:

*** mod_cgi.c.orig	Sun Apr  6 09:43:40 1997
--- mod_cgi.c	Sat Apr 12 13:36:50 1997
***************
*** 520,536 ****
  	
  	send_http_header(r);
  	if (!r->header_only)
  	    send_fd(script_in, r);
  
  	/* Soak up stderr */
  	soft_timeout("soaking script stderr", r);
  	while ((fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) &&
  	       !r->connection->aborted)
  	    continue;
  	kill_timeout(r);
- 
- 	pfclose (r->main ? r->main->pool : r->pool, script_in);
  	pfclose (r->main ? r->main->pool : r->pool, script_err);
      }
  
      if (nph) {
--- 520,535 ----
  	
  	send_http_header(r);
  	if (!r->header_only)
  	    send_fd(script_in, r);
+ 	pfclose (r->main ? r->main->pool : r->pool, script_in);
  
  	/* Soak up stderr */
  	soft_timeout("soaking script stderr", r);
  	while ((fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) &&
  	       !r->connection->aborted)
  	    continue;
  	kill_timeout(r);
  	pfclose (r->main ? r->main->pool : r->pool, script_err);
      }
  
      if (nph) {

I'm not sure if this is really enough to fix the problem in _a clean way_.
Better would be if we use the above patch _AND_ make sure the timeout happens,
too. The above patch should be ok anyway, I think (because the different order
has no negative side effects I can think of).

Any ideas or comments?

Greetings,
                                       Ralf S. Engelschall
                                       rse@engelschall.com
                                       www.engelschall.com

Mime
View raw message