Non-blocking pipes still appear to be isBlocking

Robert Engels rengels at ix.netcom.com
Wed Jan 31 00:54:29 UTC 2024


Rather than sharing the file descriptors why not use a named pipe. Each side that opens the pipe controls their blocking/non-blocking mode. 

> On Jan 30, 2024, at 6:36 PM, Charles Oliver Nutter <headius at headius.com> wrote:
> 
> On Tue, Jan 30, 2024 at 1:12 AM Alan Bateman <Alan.Bateman at oracle.com> wrote:
>> The source/sink ends of a Pipe are selectable channels and can therefore be configured non-blocking. I wonder if the user's code chokes with usages like this:
>> 
>> pipe.source().configureBlocking(false);
>> pipe.sink().configureBlocking(false);
> 
> The user's code is actually in the child process, expecting that the
> child stream will be configured as blocking. The issue is that when
> you create a pipe using java.nio.channels.Pipe, both ends are secretly
> set non-blocking at the native level, but both appear to be blocking
> at a Java level.
> 
> JRuby's subprocess logic uses posix_spawn directly, and we set up the
> pipes for it. In order to maintain the old behavior, where the child
> ends of the pipes are blocking, we'll have to clear the O_NONBLOCK
> bit... but in order to do that, we have to set the Java channel as
> nonblocking {so its AbstractSelectableChannel.nonblock flag gets set)
> and then set it to blocking (now that the nonblock flag is set, it
> will clear it and proceed to the native fcntl call to remove
> O_NONBLOCK).
> 
> This is pretty cumbersome.
> 
>> As regards the underlying blocking mode: It's okay for a SelectableChannel to implement blocking semantics when then underlying socket/fifo is configured non-blocking.
> 
> JRuby's IO has worked this way for over a decade, since we needed
> blocking IO operations to be interruptible without destroying the
> channel (NIO will just close the channel if a blocking IO call is
> interrupted).
> 
>> Mostly they are the equal, meaning if the SelectableChannel blocking mode is true then the underlying socket/fifo's blocking mode is also true. For the network channels, the first use of a virtual thread will change the channel's socket to be non-blocking. The pipe channels are a  bit different in that they eagerly change the underlying fifo to be non-blocking. Both are valid approaches as it's transparent to anything using the API. The pipe channel could be changed to work like the network channels and change it lazily, I think they were only done this week for expediency rather than anything else.
> 
> To be clear, I don't have any real problem with setting O_NONBLOCK for
> the streams consumed by JVM code. Ruby's recent push for structured
> concurrency with fibers (like vthreads) has led them to do the same
> thing: O_NONBLOCK at a native level, but simulated blocking at a
> user-facing API level. JRuby has largely worked this way for years.
> But in CRuby, the child side of the pipes are *not* set nonblocking.
> In order to maintain compatibility, we're going to need to reset
> blocking status once we know a channel is going to the child. That
> means performing this ugly set+clear operation some time before we
> call posix_spawn.
> 
>> 
>> -Alan


More information about the loom-dev mailing list