2

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/
ikegami
  • 367,544
  • 15
  • 269
  • 518
Thomas Anderson
  • 511
  • 1
  • 5
  • 14

1 Answers1

6

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;.
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • In the thread I just need to accept connection and then the thread continue do his job waiting for new connections. It never close file descriptor. All file readings/writings and closing perform in another worker thread. So I know exactly it does not close FD. And I know exactly that connection do not lose via client because it tested with other software. – Thomas Anderson Jul 29 '16 at 17:50
  • Re "It never close file descriptor", The code you showed does. The next time you assign to `$a`, you remove the last reference to the handle that `$a` previously contained, causing the underlying fd to be closed. – ikegami Jul 29 '16 at 18:24
  • please explain where if it implicitly close file descriptor I have one mistake in the code: $a = $socket->accept() should be my $a = $socket->accept() – Thomas Anderson Jul 29 '16 at 18:46
  • Since you are using lexical (`my`) variable like I did, you implicitly close the variable exactly the same place I did in my demonstration, at the end of the scope, where it says "File handle closed here". /// Updated my answer to reflect the updated question. – ikegami Jul 29 '16 at 19:13
  • Thanks a lot. I understood. – Thomas Anderson Jul 29 '16 at 19:44