views:

724

answers:

4

I am using

Server version: Apache/1.3.34 (Debian)
mod_perl - 1.29

By refering to STDIN, STDOUT, and STDERR Streams

#!/usr/bin/perl5
package main;

use strict 'vars';

{
    # Our mighty holy legacy code love to print out message in the middle of operation. Shihh....
    # Let's quietly redirect those message to /dev/null.
    my $nullfh = Apache::gensym( );
    open $nullfh, '>/dev/null' or warn "Can't open /dev/null: $!";
    local *STDOUT = $nullfh;
    print "BYE BYE WORLD";    # Shouldn't show in webpage.
    close $nullfh;
}

print "X BEGIN HELLO WORLD";  # Should show in webpage.

I realize that it is not working all the time. For example, I refresh the page for 10 times. x times it will print out "X BEGIN HELLO WORLD". (10-x) time it just print out nothing.

I cannot find any reason why it behave this way. May I know anyone of you encounter similar problem as me?

+1  A: 

I bet it is an interaction of mod_perl, and the reassignment of the STDOUT glob - you are effectively running one instance of perl in the webserver, then this will lead to a race condition on when the local goes out of scope, and when the various print's and close's happen.

This is basically a guess of mine, I don't know for sure that it is happening so keep that in mind. Roughly speaking the race condition would be between when you do this:

local *STDOUT = $nullfh;

and when this local goes out of scope. I think that requests to the web server are handled as different threads (since we are using mod_perl), and each thread may be able to see the new value for the glob.

1800 INFORMATION
Can you be a little more verbose? That didn't make a lot of sense.
ysth
I've added more detail
1800 INFORMATION
It is in my assumption too. However, race condition will only happen, if multiple processes is sharing a same STDOUT. However, the fact is, every process shall have their own STDOUT, which every STDOUT is piped to the every browsers request. So, where does the race condition come from?
Yan Cheng CHEOK
+1  A: 

Try:

local $|=1;

before print. This bypass the buffering.

See http://perldoc.perl.org/perlvar.html#HANDLE-%3Eautoflush%28EXPR%29

J-16 SDiZ
+1  A: 

Buffering is the most likely problem, as noted already, but there's another approach if that doesn't work for you for whatever reason. You can use the oft-ignored one-arg select() built-in to change the default output filehandle for print output.

Peter Corlett
+1  A: 

I need to explicitly store and restore. It works for my case. But I am not sure why.

# Take copies of the file descriptors
open OLDOUT, '>&STDOUT';
my $returned_values = 0;
{
    # Our mighty holy legacy code love to print out message in the middle of operation. Shihh....
    # Let's quietly redirect those message to /dev/null.
    local *STDOUT;
    open STDOUT, '>/dev/null' or warn "Can't open /dev/null: $!";
    print "BYE BYE WORLD";    # Shouldn't show in webpage.
    close STDOUT;
}
# Restore stdout.
open STDOUT, '>&OLDOUT' or die "Can't restore stdout: $!";
# Avoid leaks by closing the independent copies.
close OLDOUT or die "Can't close OLDOUT: $!";
Yan Cheng CHEOK