Thomas Anderson Thomas Anderson - 4 months ago 34
Perl Question

Forward/pass file descriptors between threads

I have a task where I'm waiting for connections in one thread and forward them to another thread.
Maybe I something misunderstood but why I cannot reopen file descriptor in main thread?

Very simplified code:

sub inthread {
$socket = new IO::Socket::INET ( ... );
# ...
while ( my $client = $socket->accept() ) {
#if i print STDOUT, (fileno $client); # there i'll get 4
push ( @shared, fileno $client);
}
}


sub mainthread {
if ( scalar @shared ) {
$fd = shift @shared;
# if i print (fileno $fd); # there i'll get 4
open my $f, "<&=$fd" or die " error $!"; ### error here: Can't open 4: Bad file descriptor
while ( <$f> ) { ... }
}
}

threads->create(\&inthread);
while(1) { mainthread; }


whole code is there http://dpaste.com/3381RKV

test:

perl -w ./testcode.pl --port=10102 &
wget -O - http://127.0.0.1:10102/

Answer

my $client creates a variable scoped to the loop body. And the end of the pass, the last reference to the contained handle is relinquished, freeing the file handle, which closes the associated file descriptor.

In your code you linked in the comments (as opposed to the code you posted), the file descriptor is instead closed when you call close $client;.

This happens before the other thread reaches open <&=, so the file descriptor is no longer valid when you try to create a new file handle for it.

Self-contained demonstration:

#!/usr/bin/perl

use strict;
use warnings;

my $fd;

{
   open(my $fh, '<', $0)
      or die($!);

   $fd = fileno($fh);
}                               # File handle closed here.

{
   open(my $fh, '<&=', $fd)
      or die($!);               # Bad file descriptor
}

You'll have to ensure that the file handle doesn't get closed prematurely. You might also have to use & (which dups the fd first) instead of &= (which creates a new file handle for the same fd) depending on how long you want to keep the original file handle alive.