net: add createPipe() and createSocketPair() - #65094
Open
kingces95 wants to merge 1 commit into
Open
Conversation
kingces95
marked this pull request as ready for review
August 7, 2026 01:52
Member
|
I dont think we should create a new module |
Member
|
+1, there's no justification for a new top-level module. |
kingces95
force-pushed
the
create-pipe
branch
4 times, most recently
from
August 7, 2026 20:33
83d8402 to
db5d657
Compare
Author
|
Yep. I'll move it to net. |
kingces95
force-pushed
the
create-pipe
branch
6 times, most recently
from
August 10, 2026 06:07
3621fab to
3c6c2d0
Compare
kingces95
marked this pull request as draft
August 10, 2026 06:25
Signed-off-by: Chris King <kingces95@gmail.com>
kingces95
marked this pull request as ready for review
August 10, 2026 07:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add
createPipe()tonetmodule returning a readable and writable endpoint owned by the parent process.The endpoints may be passed to
child_process.spawn()stdio. This lets the parent lend a pipe endpoint to a child without turning the parent stream itself into child-owned stdio. The parent can then reclaim unread bytes or lend the same endpoint to a later child.This is useful for bash-like partial consumption of long-lived streams. For example, a parent can keep ownership of a Server Sent Event stream while delegating bounded reads to external tools, then continue parsing from the exact byte where the child stopped.
Endpoints created by
pipe.createPipe()are rejected byspawnSync(), and an endpoint may only be leased to one child process at a time.net.createPipe
Child process 'sips' just a single character from the pipe leaving parent to drain what's left.
net.createSocketPair()
The
net.createPipe()andnet.createSocketPair()could be two separate PRs and can be easily cleaved on request. I included both because taken together they form a tidy family of handle backed streams.net.createPipe()exposes directional OS-backed endpoints:{ readable, writable }.net.createSocketPair()exposes symmetric duplex OS-backed endpoints:[left, right].Why leasing?
Node has policy which disallows pipes used to construct pipelines between children from being passed to other children; A pipe created by spawning a child process is marked with the symbol
kIsUsedAsStdiothe first time it is passed as stdio to another child process so an error can be raised should the pipe be passed to a third child process.To abide by that policy, the pipes returned from
createPipe()can be marked withkLeasedTowhich points to the child currently using the pipe. When the child exits the lease is released and the pipe can be handed to another child process. In this way, only one child is reading or writing at a time in accordance with Node policy. The new ability (limited to pipes created bycreatePipe()) to repass a pipe to a subsequent child allows emulation of the common shell idiom which is the impetus for the feature.Under The Hood
Under the hood,
createPipe()andcreateSocketPair()sit onuv_pipeanduv_socketpairrespectively. While thoselibuvAPIs do not appear to be used directly by Node’s own src/ today, their data types (uv_pipe_tanduv_os_sock_t) have been mapped into Javascript as NodePipe(). This makes exposing their functionality to Javascript straightforward: Create a pair ofPipe(), initialize them with an internal call topairPipes(pipe, pipe)orpairSockets(pipe, pipe), wrap in NodeSocket(), and return the result. Seelib/net.js.A stream descriptor of type
wrapis duplicated into a to child process without invoking any logic implying ownership by the node process abstraction for the child. For example, this happens when a child producer's stdout is passed as a child consumer's stdin. The producer "leases" its stream to the consumer. Pipes generated bycreatePipe()follow this same code path. They are "leased" by the parent to the child. Seeprocess_wrap.cpp. The difference is the former lease is never released while the latter is released when the child exits.A stream returned by
createSocketPair()follows the same wrapping model a TCP-backed net.Socket stream and makes use of use of the same IPC handle-transfer story between cooperating Node processes.Thank you!
Thank you for considering my pull request!