Search code examples
vala

Read stdin non-blocking


I'm writing a Vala program which is spawned as a child_process using stdout & stdin for message transfer with parent. In an async method I call read_stdin(sb) to check for incoming messages. I tried various stdin methods like gets and getc, but they all appear to block on '\n' newline. I need to read all chars available and return immediately (non-blocking).

    const int STDIN_BUF_SIZE=1024;
    char[] stdin_buffer;
    bool read_stdin (StringBuilder sb) {
        int iPos=0;
        int c;
        int buf_size=STDIN_BUF_SIZE-1;
        // Char by char:
        while (true) {
            c = stdin.getc ();
            if(c ==  GLib.FileStream.EOF) break;
            stdin_buffer[iPos]=(char)c;
            iPos++;
            if ((char)c=='\n'||iPos==buf_size){
                break;
                }
            }
        if(iPos>0){
            stdin_buffer[iPos]=0;
            sb.append((string)stdin_buffer);
            return true;
            }
        return false;
    }

Can stdin be used for non-blocking IO or do I need to create something like...

DataInputStream stdin_reader = new DataInputStream(stdin);

Solution

  • You use the term "non-blocking", but I don't think that means what you think it means. It would be pretty easy to simply open /dev/stdin with O_NONBLOCK if non-blocking I/O was what you really wanted. In that case, getc would instantly return EOF until there is data available.

    AFAICT, what you want is actually for the getc call to block until new data is available, then immediately return. Technically, that's what is happening. The wrinkle is that terminal applications typically buffer data until a newline, which explains why you can edit data and not have any edits appear to your application; go ahead, try typing "AB" into your program, and all you'll see will be "B\n".

    Basically, you need to use a curses library. Vala includes a curses.vapi, so you should just need to link to the relevant library (probably ncurses) and add --pkg curses to your valac invocation and you'll be good to go. IIRC the relevant function is getch, but I haven't done any curses programming in a long time.