2017-02-12 53 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和錯誤路徑;從您引用的片段中可能不適用什麼是不明確的。