sysread返回undef,errno是EINVAL,但有效吗?

时间:2014-08-01 09:30:17

标签: perl file-io

我为系统事件文件中的非阻塞输入设置了一些代码。

sysopen(FILE, $targetInput, O_NONBLOCK|O_RDONLY) or die "Failed to open $targetInput, quitting.\n";
binmode(FILE);


#More assignments and preparations here...

while (1) {

    #Code that justifies non-blocking I/O here...

    $rBytes = sysread(FILE, $buffer, 16);

    printf("%d vs %d\n", $!, EAGAIN);       
    print defined($rBytes) ? "Defined!\n" : "Undef!\n";


    if (!defined($rBytes) && $! == EAGAIN) {
        #Nothing actually read in non-blocking mode:
        usleep(1000);
    } else {
        #Got an event, moving on:
        print "Got it!\n";
        print "$rBytes!\n";
        last;
    }

}

#Logic using $buffer here...

这是一个非常标准的设置,有很多例子可用于此事。但是,我发现,100%的时间$rBytes仍未定义,$!设置为代码22,EINVAL(无效参数)。已经进行了大量的测试,以确保它是sysread函数专门导致这一点,并且在它之前绝对没有任何内容。

问题是,它的工作原理。正如您所看到的,我的代码假定的任何内容都是$rBytes未定义的组合(始终为true) $!为{{1总是假的,只是假设一切都很好,因为我还没有添加任何错误处理。这个代码块后面是一个巨大的开关/情况;不存在的数据"无害的"将它全部传递过来,然后循环回来再次尽可能快地完成它。

当收到有效输入 时,EAGAIN 仍然未定义。但由于$rBytes仍然不是$!,因此它也会传递到程序的其余部分并按预期正常运行,其中EAGAIN包含其应有的内容。如果我没有看过我的CPU使用率表,我实际上根本不会注意到这个问题,如果它是一个快速的一次性脚本,可能不会尝试修复它。

我可以肯定地说,指责"无效的争论"是虚假的。问题是,为什么它会提供错误代码,为什么$buffer 总是未定义?

1 个答案:

答案 0 :(得分:0)

当我拼凑一个快速的剧本来嘲笑迄今为止做出的假设时,我实际上偶然发现了答案;果然,所有必要的信息一直存在于问题中。

典型的系统事件文件使用长度为24个字节的消息。当然,这段代码试图从这些事件中提取16位时间戳,并将其余时间保留为未消耗。由于我不理解的原因,sysread不喜欢这样。

通过确保所需长度大于或等于24,sysread将报告读取的字节数和$!。 24可能是一个神奇的数字,或者它可能只是在从非阻塞资源中读取部分消息时遇到问题(在阻塞模式下不会发生错误)。它仍然将适当的数据放入$buffer,大概是因为底层代码通过引用传递它并且在发生错误时不会将其归零,这就是为什么显示的块之后的所有内容都能正常工作。