Rogue has asked for the wisdom of the Perl Monks concerning the following question:

Monks,

I am writing a CGI script that creates a text file on the server and writes its PID to it. Then the script uploads a file to a server. I use a fork command and write the text file in one process and upload in the other process. The only problem is the text file isn't showing up until the upload finishes. I need the text file to show up well before the file finishes uploading. I have a feeling it's related to what I read on the perldoc site: "Note that if your forked child inherits system file descriptors like STDIN and STDOUT that are actually connected by a pipe or socket, even if you exit, then the remote server (such as, say, a CGI script or a backgrounded job launched from a remote shell) won't think you're done. You should reopen those to /dev/null if it's any issue."

I am using an open command for both the text file writing and file uploading, but the command is being called on two different files and the commands are called after the fork has been made, so I didn't know if they still shared file descriptors. I am still new to perl, so I dont know if STDIN and STDOUT are the same as using open() and I dont really understand what opening to dev/null looks like in code. I have tested this on an apache server running on windows and a lighttpd server running on cygwin and it happens in both cases. So how do I get the writing to text file to finish (and appear on the server) before the upload finishes??

my $fork_pid = fork(); if ($fork_pid == 0) #If its the chi +ld process { write_pid(); exit(0); } elsif ($fork_pid) #If its the paren +t process { wait(); if ($limit_file_size == 1) { checkFilesize(); } untaintInput(); uploadFile(); output(); dump_pid(); } else { die "Couldn't fork."; } sub uploadFile { my $upload_filehandle = $query->upload($form_input_name); + #grab handle of temporary file open ( UPLOADFILE, ">$upload_dir/$filename" ) or die "$!"; + #open file for write or report errors binmode UPLOADFILE; #write the file +in binary mode while ( <$upload_filehandle>) { print UPLOADFILE; #write actual fi +le from the temporary file } close UPLOADFILE; } sub output { #Output page print $query->header(); print "{success: true, data: 'Your file was uploaded successfully!' +}"; } sub write_pid { open(MYID, ">" . $upload_dir . '/' . 'current_upload_pid.txt'); print MYID $$; close(MYID); }

Replies are listed 'Best First'.
Re: Fork child process always finishes with parent
by markkawika (Monk) on Sep 02, 2009 at 23:53 UTC

    I am unable to duplicate what you describe. I modified your code to see if the pid file contains a pid after returning from the wait() call, and it does:

    When I run it, I get this:

    $ ./blah.pl I am 7202. Saw child pid 7203

    Indicating that the pid file is being written properly with the child's pid.

Re: Fork child process always finishes with parent
by Marshall (Canon) on Sep 03, 2009 at 01:36 UTC
    Right now I only have a Windows machine available to me, so I can't run your code in a *nix environment.

    However, it sounds to me like you have buffering problems. In Perl, $| =1; turns "auto-flush" on. This can be a pretty "expensive" (performance wise) thing to do. But the deal is that if you are writing to a file handle, the OS may not actually send that data until its buffer is full. Flush says send this data right now even though you might otherwise wait until this 4K or whatever buffer is full.

    If you have run Perl scripts and see messages from STDERR at the top of the listing when they actually happened time wise after the stuff from STDOUT, this is why. STDERR is unbuffered.

    /dev/null is a special device that sends bits written to it to the "bit bucket", ie, they are "deleted". Windows also has a device like this, but I always have to search and look to find the right syntax, but yes this concept exists on all OS'es that I've used (even from the "dark ages").

    A file handle re-open to the NULL device would cause a "flush",as would process termination, as would file handle close, or file handle flush.