從 scanadf 腳本呼叫時 pnmtops 子程序掛起
幾年來,我一直很高興地使用
scanadf
這些-S script --script-wait
參數。我的腳本名為
scan_perpage
,通過呼叫 ,通過pnmtops
管道將圖像數據轉換為 pdfps2pdf
。但是最近(我懷疑自從我從 Fedora 17 更新到 19),被呼叫的腳本掛起,因此
scanadf
掛起。腳本掛在pnmtops
命令上。pnmtops
命令本身正在等待其分叉的“子”輸出pnmtops
過濾器完成,但它永遠不會完成。
scan_perpage
直接在原始掃描器頁面輸出上執行腳本可以正常工作。直接執行pnmtops
命令也可以正常工作。只有當從scanadf
via執行時-S
,腳本才會掛在pnmtops
.版本:
# rpm -q --info sane-backends Name : sane-backends Version : 1.0.23 Release : 13.fc19 # rpm -q --info sane-frontends Name : sane-frontends Version : 1.0.14 Release : 16.fc19 # rpm -q --info netpbm Name : netpbm Version : 10.61.02 Release : 5.fc19
這是我的
scan
腳本的輸出,它呼叫scanadf -vv
:$ scan -o output.pdf Scanning... scanadf: value for --resolution is: 300 scanadf: scanning image of size 2544x3300 pixels at 1 bits/pixel scanadf: acquiring gray frame Started script `/usr/local/bin/scan_perpage' as pid=10902 Scanned document scan-0001 pnmtops: Input maxval is 1. Postscript raster will have 1 bits per sample, so maxval = 1 pnmtops: Image will be 610.56 points wide by 792.00 points high, left edge 0.72 points from left edge of page, bottom edge 0.00 points from bottom of page; NOT turned to landscape orientation pnmtops: output filter spawned: pid 10904 pnmtops: Waiting for PID 10904 to exit Scanned 1 pages <the script hangs here>
這是掛起點的程序樹:
10897 32072 /bin/sh /usr/local/bin/scan -o output.pdf 10898 10897 scanadf -vvv -d fujitsu -S /usr/local/bin/scan_perpage --script-wait --resolution 300 --mode Lineart -o scan-%04d 10902 10898 /bin/bash /usr/local/bin/scan_perpage scan-0001 10903 10902 pnmtops -verbose -imagewidth 8.5 -imageheight 11 scan-0001 10904 10903 pnmtops -verbose -imagewidth 8.5 -imageheight 11 scan-0001
程序 10904(分叉的
pnmtops
“輸出過濾器”)永遠不會完成。strace 表示它正在等待“讀取”。我不知道為什麼
pnmtops
呼叫 via 時會掛起scanadf
,但是當直接在同一個文件上呼叫時,它工作得非常好。此外,如果
pnmtops
子程序被手動殺死,一切都會繼續進行,沒有任何問題。
來自 netpbm 的維護者 Bryan Henderson:
我發現並修復了導致此症狀的錯誤。
$$ … $$修復在 Netpbm 10.64.02 中。 導致 Pnmtops 有時掛起有時不掛起的環境差異是打開文件的數量。如果呼叫 Pnmtops 時打開的文件超過 10 個,則會發生掛起。
如果您關心病理是什麼:當管道輸送給它的管道發出 EOF 信號時,孩子就會退出。當管道發送端的文件描述符的每個副本都關閉時,就會發生這種情況。唯一應該存在的副本是父程序正在寫入數據的副本。但是孩子必須繼承管道兩端的文件描述符的副本。如果孩子沒有關閉它 的管道發送端的副本,孩子將永遠不會在接收端看到 EOF,因此將永遠等待。
這意味著孩子必須關閉正在餵牠的管道發送端的副本。為了做到這一點,並修復一些其他類似的問題,孩子在啟動時嘗試關閉除了它實際使用的兩個文件描述符之外的每個文件描述符。但是 POSIX 沒有提供知道打開文件描述符列表的方法,所以孩子只是盲目地關閉 0-9(不包括它需要的兩個),因為知道 Pnmtops 不會使用比這更多的文件。錯誤在於程序沒有考慮到程序出生時的文件描述符。修復是 Pnmtops 在啟動時關閉文件描述符 0-9,以便它創建的任何管道都將具有 0-9 範圍內的文件描述符編號,從而被盲目的 0-9 關閉關閉。