-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stream: don't deadlock duplexpair #29836
Conversation
If nothing is buffered then _read will not be called and the callback will not invoked, effectivly deadlocking. Fixes: nodejs#29758
test/common/duplexpair.js
Outdated
this[kOtherSide].push(chunk); | ||
if (!this[kOtherSide].readableLength) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have no readableLength _read will never be called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be clear that I’m not misunderstanding – this is because _read() was already called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But wouldn’t .push()
schedule another ._read()
call, because the readable side’s buffer is empty once the data from .push()
is used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@addaleax push(chunk)
should not schedule another read if push(null)
is called in the same tick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation disregards this invariant of Readable
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This made me consider why push(null)
is called before _read
. Could be that _final
is called before all writes having finished. Let me check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, it simply that an empty push will not trigger another read, as it is sensible to assume that if we couldn't push data then there is no data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, that kind of makes sense, but it’s also weird that .push()
with an empty chunk leads to different behaviour than .push()
with a non-empty chunk…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I've been trying to get my head around it for a few days. But as you write, it's weird but makes sense. The alternative is more confusing and leads to other problems such as livelocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this variant seems a bit more intuitive to me 👍
This is basically the workaround I suggested in #29758 (comment). |
Yep, it took me a bit longer to come to the same conclusion. |
To rephrase #29649 (comment): this looks good, I'm just surprised it requires a fix to the DuplexPair implementation (the part I was hoping to not change, since that code is copied in so many places)—but I guess that makes sense. |
If nothing is buffered then _read will not be called and the callback will not be invoked, effectivly deadlocking. Fixes: #29758 PR-URL: #29836 Refs: #29649 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
PR-URL: #29836 Refs: #29758 Refs: #29649 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
Landed in 0b495a8...28c3a9d |
If nothing is buffered then _read will not be called and the callback will not be invoked, effectivly deadlocking. Fixes: #29758 PR-URL: #29836 Refs: #29649 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
PR-URL: #29836 Refs: #29758 Refs: #29649 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
If nothing is buffered then _read will not be called and the callback will not invoked, effectivly deadlocking.
Fixes: #29758
Refs: #29649
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes