Usando filehandle sintético com EV (perl)
Pergunta
Eu tenho um objeto filehandle que é criado assim (editado um pouco para maior clareza):
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;
Eu quero usar isso com AnyEvent
.Funciona bem com AnyEvent::Impl::Perl
mas falha comAnyEvent::Impl::EV
.Acho que rastreei esse método desde 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;
}
Eu acho que está falhando SvTYPE (fh) == SVt_PVGV
teste.Usando Devel::Peek
método Dump() que recebo:
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
Qualquer assistência sobre como eu poderia ajustar a criação do meu identificador para que ele passasse neste teste seria apreciada.
Solução
As alças de arquivo amarradas são implementadas apenas parcialmente no Perl e não funcionam com o EV.Manças amarradas não podem ser feitas para trabalhar com uma biblioteca de eventos em geral:Embora alguns casos específicos possam funcionar, na maioria dos casos em que as alças amarradas são usadas, elas não podem funcionar porque a notificação de prontidão de um descritor de arquivo subjacente não se relaciona com as notificações de prontidão do identificador amarrado.
Se o seu objetivo é apenas ter um embalagem em torno de um descritor de arquivo real, uma maneira de fazer isso é copiar o que io :: handle e/ou FileHandle Do (muito feio, mas a única maneira que funciona em Perl) ou Use -os como classes base.Isso não permite que você faça coisas interessantes, como conectar leituras e gravações, mas as chances estão conectadas as torna incompatíveis com as bibliotecas de eventos.
Outra forma é implementar uma camada perlio (PerlIO::via).Na minha experiência, este módulo é um pouco frágil, mas oferece todas as opções.Novamente, se você apresentar buffers ou coisas mais interessantes que desacoplam o descritor de arquivos da E/S real, não pode ser feito para funcionar.
Por fim, se você deseja adicionar um novo tipo de alça, poderá criar um novo tipo de observador.Isso pode ser tão simples quanto ter uma função my_handle_io_watcher que leva o seu identificador, verifica a prontidão e cria o tipo de observador de baixo nível necessário.