Using synthetic filehandle with EV (perl)

180 Views Asked by At

I have a filehandle object that is created thus (edited slightly for clarity):

sub TIEHANDLE
{
    return $_[0] if ref($_[0]);
    my $class = shift;
    my $self = bless Symbol::gensym(), $class;
    return $self;
}

sub new
{
    my ($class, $fh, $chunk, $interval, $cb) = @_;

    my $self = bless Symbol::gensym(), ref($class) || $class;
    tie *$self, $self;  

    my $data = {
        fh       => $fh,
    };

    ${*$self}{'data'} = $data;

    return $self;
}

sub fileno
{
    my $self = $_[0];
    return ${*$self}{'data'}->{'fh'}->fileno();
}

*FILENO = \&fileno;

I want to use this with AnyEvent. It works fine with AnyEvent::Impl::Perl but fails with AnyEvent::Impl::EV. I think that I have tracked it down to this method from EV:

static int
s_fileno (SV *fh, int wr)
{
  dTHX;
  SvGETMAGIC (fh);

  if (SvROK (fh))
    {
      fh = SvRV (fh);
      SvGETMAGIC (fh);
    }

  if (SvTYPE (fh) == SVt_PVGV)
    return PerlIO_fileno (wr ? IoOFP (sv_2io (fh)) : IoIFP (sv_2io (fh)));

  if (SvOK (fh) && (SvIV (fh) >= 0) && (SvIV (fh) < 0x7fffffffL))
    return SvIV (fh);

  return -1;
}

I think it is failing the SvTYPE (fh) == SVt_PVGV test. Using Devel::Peek's Dump() method I get:

SV = PVMG(0x9c98460) at 0x44313b0
  REFCNT = 1
  FLAGS = (PADMY,ROK)
  IV = 0
  NV = 0
  RV = 0x9c21d00
  SV = PVGV(0x9c35510) at 0x9c21d00
    REFCNT = 1
    FLAGS = (OBJECT,RMG,MULTI)
    MAGIC = 0x9a68ee0
      MG_VIRTUAL = &PL_vtbl_backref
      MG_TYPE = PERL_MAGIC_backref(<)
      MG_OBJ = 0x9c217a8
    STASH = 0x4374440   "MetadataStream"
    NAME = "GEN5"
    NAMELEN = 4
    GvSTASH = 0x25d01c8 "Symbol"
    GP = 0x9a43d50
      SV = 0x0
      REFCNT = 1
      IO = 0x9c214a8
      FORM = 0x0  
      AV = 0x0
      HV = 0x9c21ce8
      CV = 0x0
      CVGEN = 0x0
      LINE = 102
      FILE = "/usr/share/perl5/Symbol.pm"
      FLAGS = 0x2
      EGV = 0x9c21d00   "GEN5"
  PV = 0x9c21d00 ""
  CUR = 0
  LEN = 0

Any assistance as to how I might adjust the creation of my handle such that it can pass this test would be appreciated.

1

There are 1 best solutions below

4
On BEST ANSWER

tied file handles are only partially implemented in perl, and don't work with EV. Tied handles cannot be made to work with an event library in general: While some specific cases might work, in most cases where tied handles are used, they can't work because the readiness notification of an underlying file descriptor doesn't relate to readiness notifications of the tied handle.

If your goal is to merely have a thing wrapper around a real file descriptor, then one way to do it is to copy what IO::Handle and/or FileHandle do (very ugly, but the only way that works in perl), or use them as base classes. This doesn't allow you to do interesting things such as hooking reads and writes, but chances are hooking them makes them incompatible with event libraries.

Another way is to implement a perlio layer (PerlIO::via). In my experience, this module is a bit fragile, but gives you all the options. Again, if you introduce buffering or more interesting things that decouple the file descriptor from the actual I/O, then it can't be made to work.

Lastly, if you want to add a new type of handle, then you can create a new watcher type. This can be as simple as having a function my_handle_io_watcher that takes your handle, checks for readiness and creates the kind of low-level watcher that is required.