使用合成文件句柄与EV (perl)

3

我有一个文件句柄对象,创建方式如下(为了更清晰,稍作修改):

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;

我希望能够将其与AnyEvent一起使用。它可以与AnyEvent::Impl::Perl良好地配合使用,但是与AnyEvent::Impl::EV无法正常工作。我认为这是由于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;
}

我认为它未通过SvTYPE(fh) == SVt_PVGV测试。使用Devel::Peek的Dump()方法,我得到:

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

如果您能提供帮助,指导我如何调整我的句柄创建方式以通过此测试,将不胜感激。

1个回答

2
绑定文件句柄在Perl中仅部分实现,并且与EV不兼容。绑定句柄通常无法与事件库一起使用:虽然某些特定情况可能有效,但在大多数使用绑定句柄的情况下,它们无法工作,因为底层文件描述符的就绪通知与绑定句柄的就绪通知无关。
如果您只是想在真实文件描述符周围包装一件东西,则一种方法是复制IO :: Handle和/或FileHandle所做的(非常丑陋,但这是Perl中唯一可行的方法),或将它们用作基类。这样做不允许您执行有趣的事情,例如挂钩读取和写入,但挂钩它们很可能会使它们与事件库不兼容。
另一种方法是实现perlio层(PerlIO :: via)。根据我的经验,该模块有点脆弱,但提供了所有选项。同样,如果您引入缓冲或更多解耦文件描述符与实际I/O的有趣事物,则不能使其正常工作。
最后,如果您想添加新类型的句柄,则可以创建新的观察者类型。这可以简单地使用一个函数my_handle_io_watcher来完成,该函数接受您的句柄,检查其是否就绪并创建所需的低级观察者类型。

谢谢Marc,我想这就涵盖了。 - awy
Marc,我该如何在http_get IO句柄上指定“:via(myfilter)”? - James Anderson
似乎使用perlio层不起作用,因为AnyEvent :: Handle使用sysread绕过了任何这样的层。同样,通过使用tcp_connect回调来包装返回的文件句柄来使用IO :: Handle失败,因为sysread以非OO方式使用。 - awy
与面向对象编程风格有无无关 - 基本上任何不是直接sysread的套接字读取方式都不能工作,因为这些方法不支持I/O就绪通知。 - Remember Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接