Search code examples
timeoutgtkglibvala

How to timeout a vala Subprocess?


I'm trying to run an executable in a GLib.Subprocess and extract its result. However, it could be an infinite loop and never end. So, I want the Subprocess to end after 1 second. Here is what I have tried:

string executable = "/path/to/executable";
string input = "some_input";
uint timeout_id = 0;
...
...
try {
    string output_string;
    var subp = new GLib.Subprocess.newv ({executable}, SubprocessFlags.STDIN_PIPE | SubprocessFlags.STDOUT_PIPE);
    timeout_id = GLib.Timeout.add (1, () => {
        subp.force_exit ();
        source_remove ();
        return false;
    });
    subp.communicate_utf8 (input, null, out output_string, null);
} catch (GLib.Error e) {
    print ("Error: %s\n", e.message);
}
...
...
void source_remove () {
    if (timeout_id > 0) {
        Source.remove (timeout_id);
        timeout_id = 0;
    }
}

I have also tried using {"timeout", "1", executable} but if an executable is an infinte loop it doesn't stop.


Solution

  • The problem is in this line:

        subp.communicate_utf8 (input, null, out output_string, null);
    

    You're using the synchronous GSubProcess.communicate_utf8() call, which will block until the process is terminated. Since your timeout callback is also called in the mainloop (which means the same thread), it won't be called either. To prevent this, you should use the asynchronous variant, GSubProcess.communicate_utf8_async() .

    Note: you don't need the source_remove() call inside your timeout callback: the GSource will already be automatically removed by returning false.