2013-05-11 29 views
1

這是我在一個大的ruby腳本中遇到的錯誤。我設法把它歸結爲問題的本質。在討論這個問題時,腳本是由OS/X上的某個人運行的,沒有遇到同樣的問題,所以不是一個ruby問題,它似乎是一個linux問題。如何在EAGAIN錯誤後重置stdin?

#!/usr/bin/env ruby 

require "io/console" 


def read_char 
    state=`stty -g` 
    `stty raw -echo` 
    input = $stdin.getc.chr 
    input << $stdin.read_nonblock(3) rescue nil 
    return input 
ensure 
    `stty #{state}` 
    # Have also tried `stty -raw echo` 
end 

system("strace -o strace.log ./trace the start") 
puts "press a cursor key" 
c=read_char 
system("strace -o strace2.log ./trace regular key") 
puts "press a regular key" 
c=read_char 
system("strace -o strace3.log ./trace cursor key") 
puts "done press return to exit" 

觀光提及關於此代碼爲非Ruby愛好者,<<附加到陣列[1]

反攻行爲與sh相同。目前,我不知道Ruby如何專門實現​​。我正在挖掘它。如果問題仍未得到解答,請提及。

後來我會將C++源文件發佈到「trace」函數,但沒有源代碼很容易理解。閱讀命令行並寫入預定的文件。然後請求輸入。從STDIN讀取一些輸入後,將其保存到相同的文件並退出。它實質上是一個調試功能,它暫時替代了一些更復雜的功能。

問題

第三個系統調用不恰當的行爲,有點像人們接受它是從/dev/zero輸入。

的日誌條目爲從標準輸入讀取的樣子:

strace.log:read(0, "1\n", 1024)    = 2 
strace2.log:read(0, "2\n", 1024)    = 2 
strace3.log:read(0, 0x7fb388ba0000, 1024)  = -1 EAGAIN (Resource temporarily unavailable) 

那麼,爲什麼第三跟蹤讀內存映射IO?

爲其分配的內存命令的條目是:

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb388ba0000 

爲什麼mmap命令以-1的fd作爲參數? [2]

其他評論。根據我到目前爲止所描述的內容,我幾乎必須得出結論:當EAGAIN錯誤發生時,某些東西沒有正確清理,或者標準輸入狀態不知何故被破壞,現在stdin被堵塞。然後這被系統命令繼承。因此,標題問題:你如何重置標準輸入,以便它最初的行爲。

[1]是的,作爲一名C++程序員,我明白這可能會令人討厭。

[2]我不是那種熟悉UNIX內存映射IO的人,從來沒有寫過任何使用它的東西。 Windows內存映射IO我很久以前使用過。

+0

這是相當的計算器。此外,我認爲標題並不適合這個問題。 – 2013-05-12 00:25:12

+0

其實我覺得標題確實很合適。我添加了解釋它的評論。我只是忘了把它們綁在一起。 – 2013-05-12 00:38:03

+0

至於更多的stackoverflow,以及評論將解決,但它似乎是更多的Linux系統調用問題,然後編程peroblem,請注意事實問題是沒有看到OS/X,但在Linux上。 – 2013-05-12 00:39:53

回答

1

mmap()需要-1作爲文件描述符,因爲給出了標誌MAP_ANONYMOUS

MAP_ANONYMOUS給出零初始化緩衝區。沒有文件被讀取。

因此,它給出了地址爲0x7fb388ba0000的4096零初始化字節的r/w區域。


更新。好的,進一步看看它。

最有可能的是stdin留下O_NONBLOCK$stdin.read_nonblock(3)後。

不知道如何取消設置或防止傳統紅寶石I/O功能,但您可以通過使用fcntl修復它。所以,在Ruby中是這樣的:

require 'fcntl' 

def read_char 
    ... 
ensure 
    flags = $stdin.fcntl(Fcntl::F_GETFL, 0) 
    $stdin.fcntl(Fcntl::F_SETFL, (~Fcntl::O_NONBLOCK) & flags) 
end 

在C人們可以做一些方向:

#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h> 

... 

char buf[32] = {0}; 
int fd, flags; 

fd = fileno(stdin); 
if (fd == -1) { 
    perror("fileno"); 
    return 1; 
} 

flags = fcntl(fd, F_GETFL, 0); 

if (flags & O_NONBLOCK) { 
    flags &= (~O_NONBLOCK); 
    fcntl(fd, F_SETFL, flags); 
} 

if(!(fgets(buf, 32, stdin)) { 
    if (ferror (stdin)) 
     perror("fgets"); 
} 

... 
相關問題