-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
wasi-sockets: Fix shutdown
bugs
#9225
wasi-sockets: Fix shutdown
bugs
#9225
Conversation
And rename `abort_wait` to `cancel`
…ter `shutdown(sock, SHUT_RD)` has been called.
Calling `shutdown` _after_ data has been accepted by `write`, but _before_ it has been fully flushed, caused the in-flight data to be lost.
Thanks for this! Would it be possible to use |
… regular async code
Certainly. Just pushed the changes. |
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 you'll indulge me a bit more, in thinking more about this I'm second-guessing the coupling where TcpState
owns the reader/writer streams instead of just the socket. That to me seems possible indicative of future changes being required to wasi:sockets
which wouldn't require such coupling, but we can't do that now so that's less the issue.
In this situation though, if I'm understanding this right, the only reason for this split is so an active write isn't blocked out by accident when the tcp socket is shut down without going through the writer stream, right? If that's the case do you think it would be worthwhile to change the current storage of Arc<TcpStream>
to just that plus a Arc<Mutex<SomeWriterState>>
? That way it's clear that there's only one shared piece of state and it's just the internals of the writer.
My hope is that it would be more obvious that the intention is to not hand out multiple readers/writers via the Arc<Mutex<...>>
and also minimize the scope/breadth of the mutex in question.
If you think the refactoring isn't worth it though then I think this is ok as-is.
#[async_trait::async_trait] | ||
impl Subscribe for TcpWriteStream { | ||
async fn ready(&mut self) { | ||
self.0.lock().await.ready().await |
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.
Could this use the try_lock_*
helpers instead of lock()
to consistently trap on contention? That might help prevent covering up bugs by accident where some contention is handled in some places but not others.
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.
Subscribe::ready has no return type, so I can't return a trap
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.
Hm well actually as I look into looks like stdio is already inconsistent, so let's leave this as-is.
Apologies. Maybe its getting too late for me, but I don't understand what you're saying. Could you maybe clarify with a simple code snippet? |
I'm wondering if we can change the previous |
A completely different way to go around this all is to revert the Mutex entirely and let the fn shutdown(&mut self, this: Resource<tcp::TcpSocket>, shutdown_type: ShutdownType) -> SocketResult<()> {
let table = self.table();
if let ShutdownType::Receive | ShutdownType::Both = shutdown_type {
let input = table.iter_children(&this)?.find_map(|c| c.downcast_mut::<InputStream>());
input.shutdown();
}
// etc.
} but this would require some kind of upcasting feature to get from |
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.
Ah ok, nah if this is needed for the read bits anyway this is fine to land. Let's go ahead and land as-is and can always consider refactorings later if necessary, but I don't think it's urgent or really required.
shutdown(sock, SHUT_RD)
has been called.shutdown
after data has been accepted bywrite
, but before it has been fully flushed, caused the in-flight data to be lost. Now, the nativeshutdown
syscall is deferred until the background write finishes.To facilitate the parent/child resource communication, I've placed the TCP stream implementations behind an
Arc<Mutex<..>>
. WASI is single threaded, so in practice these Mutexes should never be contended. It does make async functions likeready
a bit awkward, though.Tangentially related:
abort_wait
->cancel
LastWrite
->WriteState
Done
->Ready
Waiting
->Writing