perlapio - PerlIO_findFILE()有效但将errno设置为"非法搜索" (ESPIPE 29)

时间:2017-01-25 19:28:04

标签: c perl perl-io

这个问题或多或少与embedded perl in C, perlapio - interoperability with STDIO有关,我认为我已经为Windows环境解决了这个问题。如果这个新问题也得到解决,我会发布一个完整的解决方案。

在链接的问题中, StoryTeller gave me the hint 使用PerlIO_findFILE()来解决当前的问题,但Linux上的相同代码表现得很奇怪。

Perl的dup2()似乎在Win32上有不同的行为,其中dup2()win32_dup2()的宏,据我所知只是使用{{1}来自dup2()

在Win32上,Perl的版本在成功时返回零,在出错时返回非零,但在Linux上将使用默认的ANSI io.h,而不是返回新的文件描述符。然后,如果一切顺利,我将不得不检查dup2()

如果拨打errno,则PerlIO_findFILE()设置为"非法搜索" (错误29 - errno),然后ESPIPEdupdup2pipe仍设置为"非法搜索" ,errno上的任何进一步检查仍然会看到相同的错误。

(在实践中,一切都对我有用,因为没有实际错误。此外,通过检查errno的解决方案不是线程安全的,因为在系统调用和检查之间另一个步骤可能会重置错误。)

请注意,我有

errno

实际上我使用Perl5.14.1。

我在这里做错了吗?

这是一个简化的代码段:

#define PERLIO_NOT_STDIO 0

1 个答案:

答案 0 :(得分:3)

除非C库调用或系统调用报告错误,否则

errno没有意义,因此不能用于确定是否发生错误。值得注意的是,这些调用不需要(通常也不会)成功重置errno。在通话之前清除errno甚至都不安全,因为即使没有发生错误,呼叫也可能设置errno

据我所知,Perl dup2的{​​{1}}返回与POSIX相同的值(错误时为-1,成功时为newfd)。

#ifndef HAS_DUP2
int
dup2(int oldfd, int newfd)
{
#if defined(HAS_FCNTL) && defined(F_DUPFD)
    if (oldfd == newfd)
        return oldfd;
    PerlLIO_close(newfd);
    return fcntl(oldfd, F_DUPFD, newfd);
#else
#define DUP2_MAX_FDS 256
    int fdtmp[DUP2_MAX_FDS];
    I32 fdx = 0;
    int fd;

    if (oldfd == newfd)
        return oldfd;
    PerlLIO_close(newfd);
    /* good enough for low fd's... */
    while ((fd = PerlLIO_dup(oldfd)) != newfd && fd >= 0) {
        if (fdx >= DUP2_MAX_FDS) {
            PerlLIO_close(fd);
            fd = -1;
            break;
        }
        fdtmp[fdx++] = fd;
    }
    while (fdx > 0)
        PerlLIO_close(fdtmp[--fdx]);
    return fd;
#endif
}
#endif

(来自5.24.1)

这意味着我们可以以独立于平台的方式检测错误,尽管您声称相反。因此,正确的用法是

if ( dup2(fdPipeStdOut[1], fdStdOutOriginal) >= 0 ) {
    //do some funny stuff
} else {
    //report error
}