我在Mac OS 10.9上看到select()和poll()這兩個行爲都是我無法解釋的。幫助我理解我可能是做錯了,或者這可能是一個OS錯誤(很難相信...)select()和poll()在Mac OS上缺少一個關閉的管道
我在幹什麼
我的程序監視文件描述符成爲可讀在後臺線程中使用select()或poll()。這個bug在兩個實現中都是一樣的,所以我只描述一下poll的情況。
有問題的文件描述符是用forkpty()創建的,所以它是僞終端的一端。我調用execvp()在子進程中運行一個shell,最終它終止。這會導致父級中的文件描述符在讀取所有緩衝輸出(即,讀取返回0)後從read()生成文件結束結果。
正常的操作過程是通過調用read()對此文件描述符調用poll()。最終read()返回0,我可以清理,知道子進程已完成。
什麼錯
這裏是什麼意外:有時輪詢()時,子已完成,文件描述符處於EOF狀態將不會返回。
我爲什麼這麼認爲的poll()功能失常
下面是LLDB展示一個會話。在子進程完成後,我在poll()中阻塞的同時停止了它。
(lldb) bt
* thread #11: tid = 0x24ee79, 0x00007fff904a594a libsystem_kernel.dylib`poll + 10
frame #0: 0x00007fff904a594a libsystem_kernel.dylib`poll + 10
* frame #1: 0x00000001001f2672 iTerm`-[iTermPollHelper poll](self=0x000060800042db00, _cmd=0x00007fff9349800b) + 194 at iTermPollHelper.m:117
frame #2: 0x000000010014a87b iTerm`-[TaskNotifier run](self=0x000060000045c620, _cmd=0x00007fff8fda8066) + 4251 at TaskNotifier.m:216
frame #3: 0x00007fff8c86c76b Foundation`__NSThread__main__ + 1318
frame #4: 0x00007fff934a8899 libsystem_pthread.dylib`_pthread_body + 138
frame #5: 0x00007fff934a872a libsystem_pthread.dylib`_pthread_start + 137
好的,所以線程11在poll()中被阻塞。下面是我的投票電話的樣子:
numDescriptors = poll(pollfds, count, -1);
讓我們來看看它:1
(lldb) p count
(int) $2 = 2
(lldb) p pollfds[0]
(pollfd) $3 = (fd = 6, events = 1, revents = 0)
(lldb) p pollfds[1]
(pollfd) $4 = (fd = 5, events = 1, revents = 0)
事件字段的值對應於POLLIN。在這種情況下,fd 5是感興趣的。我們已經證明poll()正在監視文件描述符5,並且如果它處於EOF狀態,那麼輪詢現在應該已經返回。我可以這樣做:
(lldb) finish
和poll()不會返回。所以它肯定受阻,必須相信沒有什麼對FD讀5
我的方案包括這樣的功能:
void TryReadingFromFd(int fd) {
char buffer[1];
int n = read(fd, buffer, 1);
NSLog(@"Read returns %d, errno=%d", n, errno);
}
雖然在民意調查()還是停了下來,我從調試器中運行這個:
(lldb) expr (void)TryReadingFromFd(5)
2014-03-26 21:53:43.684 iTerm[48604:af07] Read returns 0, errno=35
如果讀取返回0,這是poll應該捕獲的文件結束條件。
Futher證據
如果我給poll()將超時,並在一個循環中運行它,就像這樣:
do {
numDescriptors = poll(pollfds, count, 1000);
} while (numDescriptors == 0);
然後問題消失了,我可以看到民意調查()塊,然後找到EOF的文件描述符,但永遠不會超過1秒的延遲。推測poll()在文件描述符在被調用之前已經關閉時起作用,但當它已經在poll()時關閉時會產生困惑。
還有什麼可能繼續?
這是一個複雜的程序,我不能在一個普通的小例子中再現這個問題。因此,在主線程上可能會發生混淆問題的情況。我希望有人能以這種方式建議可能干擾民意調查的事情()。從主線中刪除代碼會使問題發生得更少,因此在找到吸菸槍之前我無法解決問題。
來源 如果你真的很好奇,源代碼可以在這裏找到(注意分支是「pollHelper」): https://github.com/gnachman/iTerm2/tree/pollHelper
複製,打開一個新的終端,並密切與控制 - D.它發生在我20-30%的時間裏。
在後臺運行下面的程序使得它在我2013 13" 的MacBook Pro更經常發生:
int main() { while (1); return 0; }
使用'errno'用'perror'當'poll'失敗 –
目前還不清楚什麼順序如果事情。如果read()返回0,那麼在讀取()返回0後,如果您再次觀看文件描述符,則不能保證輪詢/選擇將發出任何信號。 – nos
您是否在輪詢之前將文件描述符設置爲非阻塞/選擇 ? – wildplasser