modperl_fork_inherits_socket_connection

This is part of The Pile, a partial archive of some open source mailing lists and newsgroups.



To: modperl <modperl@apache.org>
From: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
Subject: fork inherits socket connection
Date: Thu, 14 Dec 2000 15:36:26 +0000 (GMT)

On our intranet server I have a page that allows the user to 
start a long running process. In order not to hang a httpd 
child I fork off the process and detach it from the calling 
process. This works fine most of the time.

However in the unusual situation where apache needs to be 
restarted while the long running process is still running I 
can not restart apache. It complains that: 'Address already 
in use: make_sock: could not bind to address', which as far 
as I can make out is because the long running process has 
inherited the open sockets from the apache child.

Has anyone got an idea how to get around this? Can I get to 
the inherited socket connection and close it when I have 
detached from the calling process?


===
To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Thu, 14 Dec 2000 18:10:26 +0100 (CET)

On Thu, 14 Dec 2000, Kees Vonk 7249 24549 wrote:

> On our intranet server I have a page that allows the user to 
> start a long running process. In order not to hang a httpd 
> child I fork off the process and detach it from the calling 
> process. This works fine most of the time.
> 
> However in the unusual situation where apache needs to be 
> restarted while the long running process is still running I 
> can not restart apache. It complains that: 'Address already 
> in use: make_sock: could not bind to address', which as far 
> as I can make out is because the long running process has 
> inherited the open sockets from the apache child.
> 
> Has anyone got an idea how to get around this? Can I get to 
> the inherited socket connection and close it when I have 
> detached from the calling process?

How about 

close STDOUT;
close STDIN;
close STDERR;

in your child code?

check this out:

http://perl.apache.org/guide/performance.html#Forking_and_Executing_Subprocess

it's explained there.

===
To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: "G.W. Haywood" <ged@www.jubileegroup.co.uk>
Subject: Re: fork inherits socket connection
Date: Thu, 14 Dec 2000 17:45:44 +0000 (GMT)

Hi there,

On Thu, 14 Dec 2000, Kees Vonk 7249 24549 wrote:

> However in the unusual situation where apache needs to be 
> restarted while the long running process is still running I 
> can not restart apache. It complains that: 'Address already 
> in use: make_sock: could not bind to address'

We sometimes used to see this problem if a database server on the same
machine had swallowed up a load of sockets in the 1025+ area and we
were using high ports in the same area for developers to run private
copies of Apache.  You might want to try to make sure you're using
known port numbers (er - as opposed to well-known port numbers :).

===

To: modperl <modperl@apache.org>
From: Vivek Khera <khera@kciLink.com>
Subject: Re: fork inherits socket connection
Date: Thu, 14 Dec 2000 12:59:37 -0500

>>>>> "KV72" == Kees Vonk 7249 24549 <KEES.VONK@uktransco.com> writes:

KV72> Has anyone got an idea how to get around this? Can I get to 
KV72> the inherited socket connection and close it when I have 
KV72> detached from the calling process?

After you fork, why not close all open file descriptors you are not
using?

===

To: Stas Bekman <stas@stason.org>
From: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
Subject: Re: fork inherits socket connection
Date: Tue, 19 Dec 2000 10:56:53 +0000 (GMT)

> Kees, if you are doing system() call just put setsid back, 
> and add this:
> 
>  tie *OUT, 'Apache';
>  close OUT;
> 
> Apache keeps the socket tied. Tell me whether this works
> for you.
> 
> I'll document these things shortly and post for your
> review.

Adding (between fork and setsid):

  tie *OUT, 'Apache';
  close OUT;

causes the following error:

  Can't locate object method "TIEHANDLE" via package "Apache"
  at /app/env_control/bin/depldctl line 142.

(where depldctl is my long running process).
When I add 'use Apache;' I get the following error:

  Can't locate object method "request" via package "Apache"
  at /opt/perl5/lib/site_perl/PA-RISC2.0/Apache.pm line 191.

any ideas?

===
To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Tue, 19 Dec 2000 13:47:47 +0100 (CET)

On Tue, 19 Dec 2000, Kees Vonk 7249 24549 wrote:

> > Kees, if you are doing system() call just put setsid back, 
> > and add this:
> > 
> >  tie *OUT, 'Apache';
> >  close OUT;
> > 
> > Apache keeps the socket tied. Tell me whether this works
> > for you.
> > 
> > I'll document these things shortly and post for your
> > review.
> 
> Adding (between fork and setsid):
> 
>   tie *OUT, 'Apache';
>   close OUT;
> 
> causes the following error:
> 
>   Can't locate object method "TIEHANDLE" via package "Apache"
>   at /app/env_control/bin/depldctl line 142.
> 
> (where depldctl is my long running process).
> When I add 'use Apache;' I get the following error:
> 
>   Can't locate object method "request" via package "Apache"
>   at /opt/perl5/lib/site_perl/PA-RISC2.0/Apache.pm line 191.

Yes, yes, yes it was a bad suggestion. Sorry about that.
I still didn't complete this section, looking for a clean solution to find
a way to close only the fd that keeps the socket busy.
So far you can use the closing fds in loop -- at least it works.


===

To: Stas Bekman <stas@stason.org>
From: Tom Brown <tbrown@baremetal.com>
Subject: Re: fork inherits socket connection
Date: Tue, 19 Dec 2000 10:06:56 -0800 (PST)

> 
> Yes, yes, yes it was a bad suggestion. Sorry about that.
> I still didn't complete this section, looking for a clean solution to find
> a way to close only the fd that keeps the socket busy.
> So far you can use the closing fds in loop -- at least it works.

yuck... you'd either have to find some way to extract that information 
directly from apache, or loop through all the file descriptors calling
getsockname() and then close any descriptor connected to port 80/443/?
(depends how your daemon is setup, if you've got multiple Listen
statements you will have to close multiple sockets ... but normally it
would just be one or two (port 0.0.0.0:80 and/or 0.0.0.0:443)

===

To: Tom Brown <tbrown@baremetal.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Tue, 19 Dec 2000 19:13:30 +0100 (CET)

On Tue, 19 Dec 2000, Tom Brown wrote:

> > 
> > Yes, yes, yes it was a bad suggestion. Sorry about that.
> > I still didn't complete this section, looking for a clean solution to find
> > a way to close only the fd that keeps the socket busy.
> > So far you can use the closing fds in loop -- at least it works.
> 
> yuck... you'd either have to find some way to extract that information 
> directly from apache, or loop through all the file descriptors calling
> getsockname() and then close any descriptor connected to port 80/443/?
> (depends how your daemon is setup, if you've got multiple Listen
> statements you will have to close multiple sockets ... but normally it
> would just be one or two (port 0.0.0.0:80 and/or 0.0.0.0:443)

The Apache API ap_note_cleanups_for_socket(p, s); does that, I'm trying to
work this out with Apache::SubProcess. It works if you call system/exec,
but I'm still looking to make it working with code running within fork
without calling any variant of execve. I'll keep your posted, so far you
have at least one working solution, even not the nicest one.

===

To: modperl <modperl@apache.org>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Tue, 19 Dec 2000 22:47:10 +0100 (CET)

Below is a solution to this problem:

* fork the long running process from mod_perl
* and be able to restart the server 
   o without killing this process 
   o without this process keeping the socket busy 
     and thus preventing the server restart

Thanks to Doug for the hint. You need to patch Apache::SubProcess (CPAN):

 --- SubProcess.xs.orig	Sat Sep 25 19:17:12 1999
+++ SubProcess.xs	Tue Dec 19 21:03:22 2000
@@ -103,6 +103,14 @@
 	XPUSHs(io_hook(ioep, io_hook_read));
     }
 
+
+void
+ap_cleanup_after_fork(r)
+    Apache r
+
+    CODE:
+    ap_cleanup_for_exec();  
+
 int
 ap_call_exec(r, pgm=r->filename)
     Apache r


which makes the new method available: cleanup_after_fork() 

This is the clean test case that shows that the conditions are fulfilled
properly:

  use strict;
  use POSIX 'setsid';
  use Apache::SubProcess;

  my $r = shift;
  $r->send_http_header("text/plain");

  $SIG{CHLD} = 'IGNORE';
  defined (my $kid = fork) or die "Cannot fork: $!\n";
  if ($kid) {
    print "Parent $$ has finished, kid's PID: $kid\n";
  } else {
      $r->cleanup_after_fork();
      chdir '/'                or die "Can't chdir to /: $!";
      open STDIN, '/dev/null'  or die "Can't read /dev/null: $!";
      open STDOUT, '>/dev/null'
          or die "Can't write to /dev/null: $!";
      open STDERR, '>/tmp/log' or die "Can't write to /tmp/log: $!";
      setsid or die "Can't start a new session: $!";

      local $|=1;
      warn "started\n";
      # do something time-consuming
      sleep 1, warn "$_\n" for 1..20;
      warn "completed\n";
      # we want the process to be terminated, Apache::exit() won't
      # terminate the process
      CORE::exit(0);
  }

both processes are completely idependent now. Watch the /tmp/log as the
forked process works, while you can restart the server.

When I'll complete the rewrite of this section I'll post it all, with the
solutions for exec/system as well (using Apache::SubProcess of course).

And just a note, you always need setsid, so the server won't kill the
spawned process when the server restarts. 

More cases/explanations to come soonish.

Thanks to those who have raised this problem.

===

To: Stas Bekman <stas@stason.org>
From: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
Subject: Re: fork inherits socket connection
Date: Thu, 21 Dec 2000 10:45:19 +0000 (GMT)

> Below is a solution to this problem:
> 
> * fork the long running process from mod_perl
> * and be able to restart the server 
>    o without killing this process 
>    o without this process keeping the socket busy 
>      and thus preventing the server restart
> 
> Thanks to Doug for the hint. You need to patch Apache::SubProcess 
> (CPAN):
> 
> --- SubProcess.xs.orig  Sat Sep 25 19:17:12 1999
> +++ SubProcess.xs       Tue Dec 19 21:03:22 2000
> @@ -103,6 +103,14 @@
>         XPUSHs(io_hook(ioep, io_hook_read));
>      }
>  
> +
> +void
> +ap_cleanup_after_fork(r)
> +    Apache r
> +
> +    CODE:
> +    ap_cleanup_for_exec();  
> +
>  int
>  ap_call_exec(r, pgm=r->filename)
>      Apache r
> 
> 
> which makes the new method available: cleanup_after_fork() 
> 
> This is the clean test case that shows that the conditions are
> fulfilled properly:
> 
>   use strict;
>   use POSIX 'setsid';
>   use Apache::SubProcess;
> 
>   my $r = shift;
>   $r->send_http_header("text/plain");
> 
>   $SIG{CHLD} = 'IGNORE';
>   defined (my $kid = fork) or die "Cannot fork: $!\n";
>   if ($kid) {
>     print "Parent $$ has finished, kid's PID: $kid\n";
>   } else {
>       $r->cleanup_after_fork();
>       chdir '/'                or die "Can't chdir to /: $!";
>       open STDIN, '/dev/null'  or die "Can't read /dev/null: $!";
>       open STDOUT, '>/dev/null'
>           or die "Can't write to /dev/null: $!";
>       open STDERR, '>/tmp/log' or die "Can't write to /tmp/log: $!";
>       setsid or die "Can't start a new session: $!";
> 
>       local $|=1;
>       warn "started\n";
>       # do something time-consuming
>       sleep 1, warn "$_\n" for 1..20;
>       warn "completed\n";
>       # we want the process to be terminated, Apache::exit() won't
>       # terminate the process
>       CORE::exit(0);
>   }
> 
> both processes are completely idependent now. Watch the /tmp/log as 
> the forked process works, while you can restart the server.

Thank you very much, that works great and it looks much neater than what 
I had before.

BTW. what is the function of the chdir '/', is that needed or can I 
leave that out?


===

To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Thu, 21 Dec 2000 13:33:46 +0100 (CET)

On Thu, 21 Dec 2000, Kees Vonk 7249 24549 wrote:

> > Below is a solution to this problem:
> > 
> > * fork the long running process from mod_perl
> > * and be able to restart the server 
> >    o without killing this process 
> >    o without this process keeping the socket busy 
> >      and thus preventing the server restart
> > 
[snip]
> >   defined (my $kid = fork) or die "Cannot fork: $!\n";
> >   if ($kid) {
> >     print "Parent $$ has finished, kid's PID: $kid\n";
> >   } else {
> >       $r->cleanup_after_fork();
> >       chdir '/'                or die "Can't chdir to /: $!";
[snip]

> Thank you very much, that works great and it looks much neater than what 
> I had before.

thanks goes to doug for cleanup_after_fork :) BTW, in the official release
it'll be called cleanup_for_exec(), so you better use this one from the
beginning.

> BTW. what is the function of the chdir '/', is that needed or can I 
> leave that out?

it's useful in case you decide to umount the partition later, see perlipc
manpage. You can leave it out of course.

===
To: Stas Bekman <stas@stason.org>
From: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
Subject: Re: fork inherits socket connection
Date: Thu, 21 Dec 2000 12:50:41 +0000 (GMT)

> BTW, in the official release it'll be called
> cleanup_for_exec(), so you better use this one from the
> beginning.

Does that mean I don't have to patch SubProcess.xs? Is 
cleanup_for_exec available by default?


===
To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Thu, 21 Dec 2000 14:25:58 +0100 (CET)

On Thu, 21 Dec 2000, Kees Vonk 7249 24549 wrote:

> > BTW, in the official release it'll be called
> > cleanup_for_exec(), so you better use this one from the
> > beginning.
> 
> Does that mean I don't have to patch SubProcess.xs? Is 
> cleanup_for_exec available by default?

You'll have it in the next version of Apache::SubProcess. I suggested to
adjust my patch to use cleanup_for_exec, so when you upgrade to the new
Apache::SubProcess things won't go broken.

===

To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 13:07:46 +0100 (CET)

On Fri, 15 Dec 2000, Kees Vonk 7249 24549 wrote:

> Stas writes:
> > How about 
> > 
> > close STDOUT;
> > close STDIN;
> > close STDERR;
> > 
> > in your child code?
> > 
> > check this out:
> > 
> > http://perl.apache.org/guide/performance.html#Forking_and_Executing_Subprocess
> > 
> > it's explained there.
> 
> 
> I have tried closing STDOUT, STDIN and STDERR, but that 
> doesn't make any difference.
> 
> What I do at the moment is:
> 
> 1. Start the long running process (runs indefinitly for the 
>    purpose of this test), which closes STDOUT, STDIN and 
>    STDERR and then calls setsid().

Why do you call setsid()?

Are you spawning a process with shell or fork? 

* If you spawn the process with fork remove setsid() and it'll work.

* If you spawn the process with ``/system it works with what you've
described.

I've tested both on my machine.

> I think the following might be the solution, we have done 
> that in a (not internet related) C program here to solve 
> almost the same problem.
> 
> 
> Vivek writes: 
>  
> > KV72> Has anyone got an idea how to get around this? Can I get to  
> > KV72> the inherited socket connection and close it when I have  
> > KV72> detached from the calling process? 
> >  
> > After you fork, why not close all open file descriptors you are not 
> > using? 

What Vivek meant I suppose is the same: STDOUT and STDIN.

> I have had a look throught the camel book. How do I close a 
> file descriptor (or find out if it is open), the perl close 
> function only accepts file handles.

% perldoc -q descriptor
Found in /usr/lib/perl5/5.6.0/pod/perlfaq5.pod
       How do I close a file descriptor by number?

       This should rarely be necessary, as the Perl close()
       function is to be used for things that Perl opened itself,
       even if it was a dup of a numeric descriptor, as with
       MHCONTEXT above.  But if you really have to, you may be
       able to do this:

           require 'sys/syscall.ph';
           $rc = syscall(&SYS_close, $fd + 0);  # must force numeric
           die "can't sysclose $fd: $!" unless $rc == -1;

       Or just use the fdopen(3S) feature of open():

           {
               local *F;
               open F, "<&=$fd" or die "Cannot reopen fd=$fd: $!";
               close F;
           }


===

To: Stas Bekman <stas@stason.org>
From: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 12:36:52 +0000 (GMT)

Stas,

I had the following in my code:

      my($nOrgPID) = fork;
      exit if $nOrgPID;
      die "Could not fork: $!" unless defined $nOrgPID;

      close STDIN;
      close STDOUT;
      close STDERR;
      setsid() or die "Could not start new session: $!";


but that didn't work, however when I changed it to this:

      my($nOrgPID) = fork;
      exit if $nOrgPID;
      die "Could not fork: $!" unless defined $nOrgPID;

      require 'sys/syscall.ph';
      for (my $i=0; $i<=255; $i++) {
         syscall(&SYS_close, $i + 0);  # must force numeric
      }

      setsid() or die "Could not start new session: $!";


the socket got released and I could restart the server. I 
know it is a little crud, but it seems to work.


===
To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 13:46:28 +0100 (CET)

On Fri, 15 Dec 2000, Kees Vonk 7249 24549 wrote:

> Stas,
> 
> I had the following in my code:
> 
>       my($nOrgPID) = fork;
>       exit if $nOrgPID;
>       die "Could not fork: $!" unless defined $nOrgPID;
> 
>       close STDIN;
>       close STDOUT;
>       close STDERR;
>       setsid() or die "Could not start new session: $!";
> 
> 
> but that didn't work, however when I changed it to this:
> 
>       my($nOrgPID) = fork;
>       exit if $nOrgPID;
>       die "Could not fork: $!" unless defined $nOrgPID;
> 
>       require 'sys/syscall.ph';
>       for (my $i=0; $i<=255; $i++) {
>          syscall(&SYS_close, $i + 0);  # must force numeric
>       }
> 
>       setsid() or die "Could not start new session: $!";
> 
> 
> the socket got released and I could restart the server. I 
> know it is a little crud, but it seems to work.

But you don't need to call setsid() when you fork. Why looking for
complicated workaround when you can do it properly without any workaround.
Have you ever seen an example of fork that uses setsid?

===

To: "Stas Bekman" <stas@stason.org>,
From: "Jeremy Howard" <jh_lists@fastmail.fm>
Subject: Re: fork inherits socket connection
Date: Sat, 16 Dec 2000 00:13:41 +1100

Stas Bekman wrote:
> But you don't need to call setsid() when you fork. Why looking for
> complicated workaround when you can do it properly without any workaround.
> Have you ever seen an example of fork that uses setsid?
>
But your Guide says:
 ----
A much better approach would be to spawn a sub-process, hand it the
information it needs to do the task, and have it detach (close STDIN, STDOUT
and STDERR + execute setsid()).
 ----


===

To: Jeremy Howard <jh_lists@fastmail.fm>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 14:21:27 +0100 (CET)

On Sat, 16 Dec 2000, Jeremy Howard wrote:

> Stas Bekman wrote:
> > But you don't need to call setsid() when you fork. Why looking for
> > complicated workaround when you can do it properly without any workaround.
> > Have you ever seen an example of fork that uses setsid?
> >
> But your Guide says:
> ----
> A much better approach would be to spawn a sub-process, hand it the
> information it needs to do the task, and have it detach (close STDIN, STDOUT
> and STDERR + execute setsid()).
> ----

True, it's a mish-mash of two techniques. I'm working at this very moment
to make things clear. My follow-up was based on the fact that I told Kees
in the original reply that setsid shoudn't be used with fork.

Will be fixed in the next release, sorry about that.

===
To: Jeremy Howard <jh_lists@fastmail.fm>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 14:27:08 +0100 (CET)

On Fri, 15 Dec 2000, Stas Bekman wrote:

> On Sat, 16 Dec 2000, Jeremy Howard wrote:
> 
> > Stas Bekman wrote:
> > > But you don't need to call setsid() when you fork. Why looking for
> > > complicated workaround when you can do it properly without any workaround.
> > > Have you ever seen an example of fork that uses setsid?
> > >
> > But your Guide says:
> > ----
> > A much better approach would be to spawn a sub-process, hand it the
> > information it needs to do the task, and have it detach (close STDIN, STDOUT
> > and STDERR + execute setsid()).
> > ----

In fact this is correct. You've taken this snippet out of the context. It
was in the section talking about spawning a process without fork. So it's
absolutely correct.


===
To: modperl <modperl@apache.org>
From: "Richard L. Goerwitz" <richard@catlin.cis.brown.edu>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 08:30:58 -0500

Stas Bekman wrote:

> > 1. Start the long running process (runs indefinitly for the
> >    purpose of this test), which closes STDOUT, STDIN and
> >    STDERR and then calls setsid().
> 
> Why do you call setsid()?

He's probably thinking of traditional the traditional way in which
you background a daemon by forking, setsid'ing, then forking again
to prevent the process from ever reacquiring a controlling terminal
(your point, that this isn't needed here, is well taken).

===

To: Stas Bekman <stas@stason.org>
From: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 13:15:29 +0000 (GMT)

> But you don't need to call setsid() when you fork. Why
> looking for complicated workaround when you can do it
> properly without any workaround. Have you ever seen an
> example of fork that uses setsid?

Ok,

here is my confusion: I call the the long running process 
from the modperl script with a system() call that was why I 
was using the setsid() (in the longrunning process).

I have now changed the code my long running process to:

   my($nOrgPID) = fork;
   exit if $nOrgPID;
   die "Could not fork: $!" unless defined $nOrgPID;

   close STDIN;
   close STDOUT;
   close STDERR;


and that does not work, I have also tried putting it in the 
modperl script instead but that doesn't work either.

What am I doing wrong and why would the setsid() be a 
showstopper, especially as it is called after the close 
statements (it doesn't reopen the filehandles does it).
I could understand that it would possibly be unnecessary, but 
how could it stop this code from working?

Another (more detailed) run through.

 1. modperl script starts long running process (lrp) with a 
    system() call.
 2. lrp runs the code above (fork + close (tried this with 
    and without setsid)).
 3. stop apache
 4. start apache - fails (port in use)
 5. netstat -na reveals port in LISTEN state.
 6. kill lrp
 7. netstat -na reveals port no longer in use.
 8. start apache - now starts fine


I think I am doing something wrong somewhere, but I am not 
sure where. Is it right that I have to do the system call and 
the fork?

===
To: Stas Bekman <stas@stason.org>
From: Rafael Caceres <rcaceres@aasa.com.pe>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 08:44:05 -0500

At 01:46 PM 12/15/00 +0100, you wrote:
>On Fri, 15 Dec 2000, Kees Vonk 7249 24549 wrote:
>
> > Stas,
> >
> > I had the following in my code:
> >
> >       my($nOrgPID) = fork;
> >       exit if $nOrgPID;
> >       die "Could not fork: $!" unless defined $nOrgPID;
> >
> >       close STDIN;
> >       close STDOUT;
> >       close STDERR;
> >       setsid() or die "Could not start new session: $!";
> >
> >
> > but that didn't work, however when I changed it to this:
> >
> >       my($nOrgPID) = fork;
> >       exit if $nOrgPID;
> >       die "Could not fork: $!" unless defined $nOrgPID;
> >
> >       require 'sys/syscall.ph';
> >       for (my $i=0; $i<=255; $i++) {
> >          syscall(&SYS_close, $i + 0);  # must force numeric
> >       }
> >
> >       setsid() or die "Could not start new session: $!";
> >
> >
> > the socket got released and I could restart the server. I
> > know it is a little crud, but it seems to work.
>
>But you don't need to call setsid() when you fork. Why looking for
>complicated workaround when you can do it properly without any workaround.
>Have you ever seen an example of fork that uses setsid?

Yes, the following is taken straight out from the perlipc documentation:
 -----------------------------
Complete Dissociation of Child from Parent

In some cases (starting server processes, for instance) you'll want to 
completely dissociate the child process from the
parent. This is often called daemonization. A well behaved daemon will also 
chdir() to the root directory (so it
doesn't prevent unmounting the filesystem containing the directory from 
which it was launched) and redirect its standard
file descriptors from and to /dev/null (so that random output doesn't wind 
up on the user's terminal).

     use POSIX 'setsid';

     sub daemonize {
         chdir '/'               or die "Can't chdir to /: $!";
         open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
         open STDOUT, '>/dev/null'
                                 or die "Can't write to /dev/null: $!";
         defined(my $pid = fork) or die "Can't fork: $!";
         exit if $pid;
         setsid                  or die "Can't start a new session: $!";
         open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
     }

The fork() has to come before the setsid() to ensure that you aren't a 
process group leader (the setsid() will fail if you are). If your system 
doesn't have the setsid() function, open /dev/tty and use the TIOCNOTTY 
ioctl() on it instead. See tty(4) for details.

===

To: Kees Vonk 7249 24549 <KEES.VONK@uktransco.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 15:58:00 +0100 (CET)

On Fri, 15 Dec 2000, Kees Vonk 7249 24549 wrote:

> > But you don't need to call setsid() when you fork. Why
> > looking for complicated workaround when you can do it
> > properly without any workaround. Have you ever seen an
> > example of fork that uses setsid?
> 
> Ok,
> 
> here is my confusion: I call the the long running process 
> from the modperl script with a system() call that was why I 
> was using the setsid() (in the longrunning process).
> 
> I have now changed the code my long running process to:
> 
>    my($nOrgPID) = fork;
>    exit if $nOrgPID;
>    die "Could not fork: $!" unless defined $nOrgPID;
> 
>    close STDIN;
>    close STDOUT;
>    close STDERR;
> 
> 
> and that does not work, I have also tried putting it in the 
> modperl script instead but that doesn't work either.

Kees, if you are doing system() call just put setsid back, and add this:

 tie *OUT, 'Apache';
 close OUT;

Apache keeps the socket tied. Tell me whether this works for you.

I'll document these things shortly and post for your review.

===

To: Rafael Caceres <rcaceres@aasa.com.pe>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 16:02:11 +0100 (CET)

> >But you don't need to call setsid() when you fork. Why looking for
> >complicated workaround when you can do it properly without any workaround.
> >Have you ever seen an example of fork that uses setsid?
> 
> Yes, the following is taken straight out from the perlipc documentation:
> -----------------------------
> Complete Dissociation of Child from Parent
> 
> In some cases (starting server processes, for instance) you'll want to 
> completely dissociate the child process from the
> parent. This is often called daemonization. A well behaved daemon will also 
> chdir() to the root directory (so it
> doesn't prevent unmounting the filesystem containing the directory from 
> which it was launched) and redirect its standard
> file descriptors from and to /dev/null (so that random output doesn't wind 
> up on the user's terminal).
> 
>      use POSIX 'setsid';
> 
>      sub daemonize {
>          chdir '/'               or die "Can't chdir to /: $!";
>          open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
>          open STDOUT, '>/dev/null'
>                                  or die "Can't write to /dev/null: $!";
>          defined(my $pid = fork) or die "Can't fork: $!";
>          exit if $pid;
>          setsid                  or die "Can't start a new session: $!";
>          open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
>      }
> 
> The fork() has to come before the setsid() to ensure that you aren't a 
> process group leader (the setsid() will fail if you are). If your system 
> doesn't have the setsid() function, open /dev/tty and use the TIOCNOTTY 
> ioctl() on it instead. See tty(4) for details.
> -----------------
> 
> Am I missing something?

You don't miss anything, the above code is an example of daemonization.
You don't really need to call setsid() for a *forked* process that was
started to execute something and quit. 

It's different if you call system() to spawn the process. But since it's a
child of the parent httpd it's not a leader anyway so you don't need the
extra fork I suppose. Am I correct?

In fact it's good that you've posted this doc snippet, I'll use it as it's
more complete and cleaner. Thanks.

===
To: modperl@apache.org
From: Bill Moseley <moseley@hank.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 07:24:27 -0800

At 04:02 PM 12/15/00 +0100, Stas Bekman wrote:
>> Am I missing something?
>
>You don't miss anything, the above code is an example of daemonization.
>You don't really need to call setsid() for a *forked* process that was
>started to execute something and quit. 
>
>It's different if you call system() to spawn the process. But since it's a
>child of the parent httpd it's not a leader anyway so you don't need the
>extra fork I suppose. Am I correct?
>
>In fact it's good that you've posted this doc snippet, I'll use it as it's
>more complete and cleaner. Thanks.

Thank goodness!  I like this thread -- It's been hard keeping up with all
the posts just to see if PHP or Java is better than mod_perl ;)

Stas, will you please post your additions/notification about this when you
are done?  I do hope you go into a bit of detail on this, as I've posted
questions about setsid a number of times and locations and I'm still
unclear about when or when not to use it, why to use it, and how that might
relate to mod_perl and why it makes a difference between system() vs. fork.
 I've just blindly followed perlipc's recommendations.

BTW -- this isn't related to the infrequently reported problem of an Apache
child that won't die even with kill -9, is it?

===
To: modperl <modperl@apache.org>
From: Vivek Khera <khera@kciLink.com>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 10:50:33 -0500

>>>>> "KV72" == Kees Vonk 7249 24549 <KEES.VONK@uktransco.com> writes:

KV72>       require 'sys/syscall.ph';
KV72>       for (my $i=0; $i<=255; $i++) {
KV72>          syscall(&SYS_close, $i + 0);  # must force numeric
KV72>       }


KV72> the socket got released and I could restart the server. I 
KV72> know it is a little crud, but it seems to work.

No, it is not crud.  If you want your forked process to act like a
daemon, you must make sure to perform the necessary actions.  That
includes closing all open file descriptors you are not using.


===
To: modperl <modperl@apache.org>
From: Vivek Khera <khera@kciLink.com>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 10:56:35 -0500

>>>>> "SB" == Stas Bekman <stas@stason.org> writes:

SB> In fact this is correct. You've taken this snippet out of the context. It
SB> was in the section talking about spawning a process without fork. So it's
SB> absolutely correct.

How exactly does one spawn a process without fork() in unix?

(It is a rhetorical question, in case you didn't figure that out.)

===
To: Vivek Khera <khera@kciLink.com>
From: Stas Bekman <stas@stason.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 17:07:57 +0100 (CET)

On Fri, 15 Dec 2000, Vivek Khera wrote:

> >>>>> "SB" == Stas Bekman <stas@stason.org> writes:
> 
> SB> In fact this is correct. You've taken this snippet out of the context. It
> SB> was in the section talking about spawning a process without fork. So it's
> SB> absolutely correct.
> 
> How exactly does one spawn a process without fork() in unix?
> 
> (It is a rhetorical question, in case you didn't figure that out.)

Hold on folks, gimme a little time and I'll come up with a clear
explanation of all the mess that I admittedly created. I'll post the fresh
corrected docs and then you will tell me if some things are still vague...
Ok? Thanks for your patience.

===

To: modperl@apache.org
From: Bill Moseley <moseley@hank.org>
Subject: Re: fork inherits socket connection
Date: Fri, 15 Dec 2000 15:32:50 -0800

At 04:02 PM 12/15/00 +0100, Stas Bekman wrote:
>>          open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
>>          open STDOUT, '>/dev/null'
>>                                  or die "Can't write to /dev/null: $!";
>>          defined(my $pid = fork) or die "Can't fork: $!";
>>          exit if $pid;
>>          setsid                  or die "Can't start a new session: $!";
>>          open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";

>You don't miss anything, the above code is an example of daemonization.
>You don't really need to call setsid() for a *forked* process that was
>started to execute something and quit.

Oh, so that's the difference between system and fork/exec!  That's what I
get for following perlipc instead of the Guide.

I've always done it the Hard Way (tm) before.  That is, in my mod_perl
handler I would fork, then waitpid, call setsid, fork again freeing Apache
to continue (and double fork to avoid zombies), and then finally exec my
long running program.  With this method I had to call setsid or else
killing the Apache parent would kill the long running process.

Calling system() in the handler and then doing a simple fork in the long
running program is much cleaner (but you all knew that already).  I just
didn't realize that it freed me from calling setsid.  I just have to
remember not to system() something that doesn't fork or return right away.

But, I'm really posting about the original problem of the socket bound the
by the forked program.  I tried looking through mod_cgi to see why mod_cgi
can fork off a long running process that won't hold the socket open but I
my poor reading of it didn't turn anything up.

Anyone familiar enough with Apache (and/or mod_cgi) to explain the
difference?  Does mod_cgi explicitly close the socket file descriptor(s)
before forking?

===


the rest of The Pile (a partial mailing list archive)

doom@kzsu.stanford.edu