2017-02-12 56 views
0

我写过Zsh模块。在那里我有一个内置函数映射到Zsh命令。这个函数可以复制其标准输入文件描述符:dup(fileno(stdin)),然后产生32个线程 - > I/O错误

/* Duplicate standard input */ 
oconf->stream = fdopen(dup(fileno(stdin)), "r"); 

然后,线程派生,其获得oconf结构。在该线程,我做的:

errno = 0; 

/* Read e.g. 5 characters, putting them after previous portion */ 
int count = fread(buf + index, 1, read_size, oconf->stream); 
/* Ensure that our whole data is a string - null terminated */ 
buf[ index + count ] = '\0'; 

if (errno) { 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno) > 
} 

如果我产卵32个线程的zsh:

for ((i=1; i<=32; i ++)); do 
    ls -R /Users/myuser/Documents | mybuiltin -A myhash_$i $i 
done 

然后2-3线程都从上面fprintf()报道的I/O错误,如:

读取错误(描述符:7):输入/输出错误

读取错误(描述符:5)不适当的ioctl用于设备

读取错误(描述:14):用于设备

不适当的ioctl

调试说,这些线程,经过多次(5-20​​)FREAD()重复,被堵在内核__read_nocancel()。因此,文件描述符正在变得非常糟糕。

否则这个工程。管道正确传递来自ls -R的数据,它被定制内建读取。那么危险在哪里? dup()如何在主线程中执行导致fread()不可读?我可能会怀疑我是否会在辅助线程中执行dup()。但我只保留在安全的地方 - 主线程,然后将准备好的流FILE *流传递到辅助线程。还试用POSIX open(),read()close(),结果是一样的。

回答

0

您正在测试errno错误。如果设置它的函数报告了错误,则只应检查errno。标准C或POSIX库中的任何函数都不会将errno设置为零。并且函数可以将errno设置为非零而不报告错误。

例如,在Solaris上,在写操作之后,如果文件流不是终端(例如,重定向到文件或管道),它就是这种情况(并且可能仍是这种情况)。没有问题;输出设备不是终端,因此终端操作失败,将errno设置为ENOTTY

您目前有:

/* Read e.g. 5 characters, putting them after previous portion */ 
int count = fread(buf + index, 1, read_size, oconf->stream); 
/* Ensure that our whole data is a string - null terminated */ 
buf[ index + count ] = '\0'; 

if (errno) { 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno)); 
} 

你需要更多的使用类似:

int count = fread(buf + index, 1, read_size, oconf->stream); 
if (count == 0) 
{ 
    /* EOF or error — this might be a time to use feof() or ferror() */ 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno)); 
    …flow control?… 
} 
else 
    buf[index + count] = '\0'; 

你可能需要一些其他流的控制信息(退货或折断或设置标志)在EOF和错误路径;从您引用的片段中可能不适用什么是不明确的。