Ive launched a process and set its output mode to .Pipe. Now I want to read whatever was printed without it blocking. How do I do that?
Context: I am trying to make a gui that calls to a cli whose output I want to show in realtime.
Ive launched a process and set its output mode to .Pipe. Now I want to read whatever was printed without it blocking. How do I do that?
Context: I am trying to make a gui that calls to a cli whose output I want to show in realtime.
There are several approaches to non-blocking I/O. What you probably want to do is to use poll
or select
to get notified when the input is ready to read or after a timeout. std.io.poll
will work here.
Huh okay I knew std.io.poll existed, I just thought that it wouldnt work here for some reason, and hoped that if it did that there would be a nicer way.
Non-blocking I/O in low-level languages is a bit of a pain in the ass both because blocking I/O is simpler and because there is a wealth of incompatible APIs:
Yea Im not too familiar with the topic, but i have heard some of those words and the sheer amount of them scared me off every digging deeper regarding that topic.
I was hoping that someone would inform me about the forgotten child, something like a method of file that just does something like this (this was from a school project where my glass used java and my teacher let me use zig), just in a simpler way.
Speaking of which: Why is poller such a complex struct instead of just a function? Is it a code smell to use it the way I did there? Why the ability to poll multiple files with just one poller?
Why is poller such a complex struct instead of just a function?
I believe it’s mainly for convenience.
Is it a code smell to use it the way I did there?
I don’t think so, for your application it seems fine.
Why the ability to poll multiple files with just one poller?
Many applications like servers need to be notified of many file descriptors.
Just an addition. “Non-blocking” I/O in literal sense is when you set O_NONBLOCK
flag for a file descriptor (socket for ex.) and then do read()
or write()
in a loop (with optional small pause), checking if errno
is EWOULDBLOCK/EAGAIN
in case when these calls return -1
. Of course, this is a CPU hog, but such an approach is quite applicable when you know for sure that data is almost always available.
Also O_NONBLOCK
is often set even when using epoll
and alike because there may be “spurious” POLLIN
notifications. To deal with them you
O_NONBLOCK``and check for
EAGAIN` as when doing “pure” non-blocking i/oioctl(FIONREAD)
) and if it is zero, do not perform a read()
You are technically correct! The best kind of correct!
How do I do the O_NONBLOCK thing? Im pretty sure ive done it before but just dont know how and where.
Something like this. There non-blocking mode is used for asynchronous tcp-connect.
fcntl(F_GETFL)
|=
to themfcntl(F_SETFL)
Alright thank you!
Wait theres no way this is crossplatform is there?
No it cant be.
I need this to be crossplatform (windows and linux)
Then select()
is probably your choice (see also this comment). But I am not sure if this is really good advice.
I ended up just using std.io.poll which to my surprise actually worked.
It surprised me because just calling read on the stream just blocked until the execution of the subtask was fully over, I thought that this would mean that polling for input would also just skip until the subtask is fully done, leading to non-realtime output. TIL: it does give me realtime output.