Interesting! Did you consider using expect to implement this? I’ve seen some pretty wild implementations using expect!
I did not! I am not familiar with expect. How might it help?
expect is a great program for driving interactive programs however you choose, check this out.
Here is test.expect:
set timeout 1
send "echo input1 | rev\n"
puts "Got 1tupni!"
puts "didn't get 1tupni soon enough..."
send "echo input2 | rev\n"
puts "Got 2tupni!"
puts "didn't get 2tupni soon enough..."
# Note I used `input3` here but look for `input4`
send "echo input3 | rev\n"
puts "Got 4tupni!"
puts "didn't get 4tupni soon enough..."
And running it:
Morbo> expect ./test.expect
echo input1 | rev
[grahamc@Morbo:~/projects/student-programs]$ echo input1 | rev
echo input2 | rev
[grahamc@Morbo:~/projects/student-programs]$ echo input2 | rev
echo input3 | rev
[grahamc@Morbo:~/projects/student-programs]$ echo input3 | rev
[grahamc@Morbo:~/projects/student-programs]$ didn't get 4tupni soon enough...
Morbo> echo $?
Whoa, that’s nuts. Good to know for the future, definitely!
lots of languages have “expect” libraries, I had good results with a python one.
I think your code is missing some calls to make_pipe? The child_* arrays are never initialized.
You’re absolutely right. In the cleanup for my post I accidentally removed those. I will fix that.
One potential issue with your program: it pushes all input to the program before reading any of its output. In a case where the program does a significant amount of output, it may block - and in fact, deadlock, since it will stop consuming input, which may cause your driver program to block as it attempts to write to the pipe.
This might not be a real concern, though, if the amount of input/output is always limited.
Edit: a more comprehensive solution might be to loop while both pushing some input to the student program using non-blocking I/O and read some of its output (also using non-blocking I/O). Once you’ve pushed all input, you could leave the loop and assume the pipe buffer contains all significant output (as you do now), or perhaps better, flush the buffer and then sleep for a little before checking for more output (using non-blocking I/O).
Hm, interesting. The good news is there is not generally a significant amount of output – mostly user-interactive output, ~500B at a time. The bad news is you’re right. I didn’t realize non-blocking I/O in C was possible. Will investigate…