3 ms·
So why does Java close the channel when an "interrupt" happens? I looked at the git-blame of [1] to see if the commit message would explain it, but it's just be
by Arnavion 4y ago
So why does Java close the channel when an "interrupt" happens? I looked at the git-blame of [1] to see if the commit message would explain it, but it's just been there since the first OpenJDK commit in 2007. The only other info I could find by searching for that exception name is [2] but it doesn't elaborate the "IO safety issues". And are these "interrupts" just the underlying syscall returning EINTR or something Java-specific?
[1]: https://github.com/openjdk/jdk/blame/c313e1ac7b3305b1c012755de4e94728b17e2505/src/java.base/share/classes/java/nio/channels/exceptions#L62 https://github.com/openjdk/jdk/blame/c313e1ac7b3305b1c012755...
[2]: https://stackoverflow.com/questions/1161297/ https://stackoverflow.com/questions/1161297/
---
Edit: marginalia_nu's and cesarb's comments make sense. Searching for "interruptiblechannel" yields:
https://www.taogenjia.com/2020/07/13/Java-understanding-nio/ https://www.taogenjia.com/2020/07/13/Java-understanding-nio/
>NIO’s designers chose to shut down a channel when a blocked thread is interrupted because they couldn’t find a way to reliably handle interrupted I/O operations in the same manner across operating systems. The only way to guarantee deterministic behavior was to shut down the channel.
Since the interrupts being talked about here are a Java concept, Java would need to interrupt the syscall itself, and it makes sense they chose to close the file since there's no way to do that equally well on all OSes.
- marginalia_nu 4y ago"AbstractInterruptibleChannel" seems to be doing this, and the comments/javadocs offer some hint. As to why they're designed this way, that's a good question. https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/...
- pron 4y agoIt's important for sockets, less so for files, but they inherit that behaviour from the specification of the interface (https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/nio/channels/InterruptibleChannel.html https://docs.oracle.com/en/java/javase/19/docs/api/java.base...). See an old discussion about that here: https://mail.openjdk.org/pipermail/nio-dev/2018-February/004756.html https://mail.openjdk.org/pipermail/nio-dev/2018-February/004...
- cesarb 4y ago> And are these "interrupts" just the underlying syscall returning EINTR or something Java-specific? It's something Java-specific: https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupt-- https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.h...
- nitwit005 4y agoNot every OS supports cancel-able file IO, but they all support closing the file outright, which will get this behavior of canceling all IO against the file.
- layer8 4y agoThread interrupts are a purely Java thing [1]. Probably when the blocking operation detects that the interrupt flag is set, they cancel the internally asynchronous operation, but can’t do so on all platforms without also closing the channel. You should still be able to share FileChannels between threads when all immediate client code is under your control so you can handle that situation gracefully. [1] It’s just a flag you can set on a thread, requesting the thread to stop its operation (the thread is not required to comply), and longer-running operations like I/O can choose to test that flag, and typically throw some exception when it is set. The default exception type for this is InterruptedException, but here they chose to throw a subclass of IOException, probably exactly because it also closes the channel.
- twic 4y agoThis is it - a thread that's blocked on I/O won't see the interrupt flag until the system call returns, so interrupting it also closes the file descriptor, to force the system call to return straight away. It's a nasty kludge. I wonder if the virtual threads from Project Loom could let the JVM do the right thing here, and interrupt the virtual thread without waiting for the carrier thread to return from the system call. That might be extremely hairy, though - your thread could return from a read call with an InterruptedException, and then some time later, the data from the read could end up in your buffer as if by magic!
- Szpadel 4y agojust a guess, afaik syscalls for reads and writes get buffer as a pointer, and java have GC, so if thread gets interrupted, there could happen GC cycle and memory could be moved to different location, so read would write to outdated memory location potentially causing memory corruption. (I didn't check code, but I bet canceling happens before suspending thread) Could be similar why rust have Pin macros.
- layer8 4y agoYou can be 100% sure the internal I/O buffers are pinned in Java’s implementation, and you seem to have a misconception about the Java-specific meaning of “thread interrupt” in this context (it has nothing to do with thread context switches).
- Szpadel 4y agoOh sorry, I don't know java well enough, I tried to approximate knowledge from other languages. This was for me only logical reason why you would need to cancel operation here. So this is about interrupt()? so basically canceling thread?
- vbezhenar 4y agoWhen you call thread.interrupt(), if a target thread sleeps in a blocking I/O call, this blocking call should throw Java exception. If target thread does not sleep in a blocking I/O (or uses some kind of unsupported blocking I/O, e.g. implemented with third-party JNI library), only some internal flag sets and no magic happens. It's pretty simple implementation actually. Thread is not cancelled or corrupted in any way, if you handle this situation, it's perfectly OK to continue execution in this thread. Usually interrupt is used to coordinate termination, indeed, but that's not the only use. So apparently they didn't find a better way to cancel a blocking I/O operation than just to close file handle from the other thread which causes OS to return some kind of error code from blocking call which translates to Java exception in the end.