#3442 defect new
t.i.stdio must not set nonblocking on stdio FDs
|Reported by:||jknight||Owned by:|
|Cc:||exarkun, itamar, jknight, glyph, ezyang||Branch:|
It seems that O_NONBLOCK is a property of file descriptions, not of file descriptors. This means that it's incorrect for any code to ever set it on a file descriptor that it did not just freshly create with open(), socket(), etc.
t.i.stdio needs to instead do a workaround like http://cr.yp.to/unix/nonblock.html describes. That is: use select/etc as usual to find when the fd is probably readable/writable. Then, try to read/write it. However, if it turns out select lied, you need a way to escape from the blocking read/write. So, you have to set a timer to send a signal to yourself (e.g. SIGALARM) around the read/write, so that it interrupts the syscall for you after a short period of time, in case select lied.
This is totally sucky but I can't see a correct alternative (other than using threads, like the windows version does).
<foom> yeah, so t.i.stdio is totally broken, it can't set nonblocking on random fds it inherits, because that's a property of the file description not file descriptor. <exarkun> Okay, that's a property of the file description. So? <foom> you run a t.i.stdio app. it sets stdout to nonblocking mode. Now, stdout is nonblocking for all processes that share that same stream. <exarkun> How many people want to share stdout among multiple processes? <foom> e.g. you return back to the shell, now the shell's stdout is nonblocking <exarkun> That'd be easily fixed by making them blocking again before exiting <foom> unless you don't exit cleanly <foom> or unless someone else is running concurrently <exarkun> If you don't exit cleanly, you might leave stdout in an inconsistent state anyway <exarkun> And concurrency is a different case :) <foom> you might? how? <glyph> foom: sys.stdout.write("\x1b") <foom> at least random other programs won't fail with EAGAIN <exarkun> I've never wanted to programmatically interact with stdout that was in concurrent use by another process <exarkun> That's why I said it was an uncommon case <foom> you've never ran program & in a shell? <foom> and had it print something? <exarkun> not when `program´ wanted to play with stdout <exarkun> well, not that's not true <exarkun> I have <exarkun> But whenever the program prints to stdout I get pissed up, foreground it and kill it. <exarkun> Why would I want a background process talking to my stdio? It's *background*! The foreground process is the one that gets to talk to stdio. <foom> so, in the meantime, since the shell printed something, it set the file back to blocking mode <exarkun> Anyway, that's irrelevant - it's *possible* to share, I'm not denying that <exarkun> But I really think it's very uncommon. <foom> and now your twisted program is blocking on stdio <foom> for the rest of its life <foom> well, I just ran into this in real life. <exarkun> Okay, so you probably want a fix :) <foom> and it took quite a while to realize what the hell was going on <exarkun> Before I was thinking that twisted.internet.stdio didn't need to change completely to accomodate an uncommon use-case <foom> because I didn't even realize nonblockingness was a property of the file description <exarkun> But now I'm thinking it can accomodate this use-case without changing completely <exarkun> What if it could dup stdio and make the copies non-blocking? <exarkun> Is that a fix? <foom> no <foom> dup doesn't copy the file description <foom> it copies the file descriptor <exarkun> okay <foom> see, this is really evil. <exarkun> shared mutable state usually is ;) <itamar> what do other applications do? <exarkun> itamar: I bet they break and die. <exarkun> foom just said what shells do - set the fd back to blocking, but I bet that's not a reliable fix for them <exarkun> (ie, what if twisted sets it non-blocking in between doing that and doing a read) <foom> they do that in response to EAGAIN I believe <foom> so it should work out okay for them. :) <exarkun> around every read we do, we could lock the fd and set it non-blocking :) <foom> lock it? how? <exarkun> mandatory non-posix locking of course <exarkun> (this is a joke) <exarkun> bbiaf, coffee <itamar> http://cr.yp.to/unix/nonblock.html <foom> man, that sucks, but it sure would work. <foom> select() would usually give the right answer, if it doesn't, the signal will break you out of the read. <foom> it shouldn't even be that hard to fix t.i.stdio to do that. <foom> sucksucksucksuck <itamar> do we still want to set non-block? <foom> no <foom> you can't <foom> it's basically incorrect to set nonblockingness on any fd you didn't create <itamar> :(