Search code examples
multithreadingperlfile-descriptorshared-objects

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/

Solution

  • 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.[1]

    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 could store them in an array or hash keyed by fd, and the other thread could let the parent thread know which handles it no longer needs via another shared structure.


    1. 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;.