-
Notifications
You must be signed in to change notification settings - Fork 46
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
refactor: Shared to use internal mutability #197
base: master
Are you sure you want to change the base?
refactor: Shared to use internal mutability #197
Conversation
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.
Thank you for your PR @akaladarshi!
Some comments.
yamux/src/connection/stream.rs
Outdated
self.with_mut(|inner| inner.update_state(cid, sid, next)) | ||
} | ||
|
||
pub fn with_mut<F, R>(&self, f: F) -> R |
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.
parking_lot::Mutex
doesn't support re-entrant locking, thus a nested call to this would cause a deadlock.
To avoid this, the function should take &mut self
.
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.
Thanks for pointing this out!
I need a suggestion regarding the design choices in the code snippet below. We are frequently using Pin<&mut Self>
in connection.rs
. So if we change fn with _mut
to take &mut self
then, we would run into borrow checkers issue.
So to fix it, is the below snippet a good choice or we could do something like take a mutexGuard
on sharedInner or is there any better way?.
Here’s the code for reference (stream.rs -> fn poll_next):
let conn_id = self.conn.clone();
let stream_id = self.id.clone();
let shared = &mut self.shared;
let poll_state = shared.with_mut(|inner| {
if let Some(bytes) = inner.buffer.pop() {
let off = bytes.offset();
let mut vec = bytes.into_vec();
if off != 0 {
// This should generally not happen when the stream is used only as
// a `futures::stream::Stream` since the whole point of this impl is
// to consume chunks atomically. It may perhaps happen when mixing
// this impl and the `AsyncRead` one.
log::debug!(
"{}/{}: chunk has been partially consumed",
conn_id,
stream_id,
);
vec = vec.split_off(off)
}
return Poll::Ready(Some(Ok(Packet(vec))));
}
// Buffer is empty, let's check if we can expect to read more data.
if !inner.state.can_read() {
log::debug!("{}/{}: eof", conn_id, stream_id);
return Poll::Ready(None); // stream has been reset
}
// Since we have no more data at this point, we want to be woken up
// by the connection when more becomes available for us.
inner.reader = Some(cx.waker().clone());
Poll::Pending
});
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.
Updated the with_mut
to use &mut
.
I added another lock()
function, which will allows us to use simple lock wherever it's necessary and also keeping the with_mut
so we can use whichever we need.
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 need a suggestion regarding the design choices in the code snippet below. We are frequently using
Pin<&mut Self>
inconnection.rs.
So if we changefn with_mut
to take&mut self
then, we would run into borrow checkers issue.
You could use Pin::get_mut
and then destructure Self
to access the distinct fields, which would satisfy the borrow checker:
let Self {
conn, shared, id, ..
} = self.get_mut();
shared.with_mut(|inner| {
inner.update_state(*conn, *id, State::SendClosed);
});
I added another
lock()
function, which will allows us to use simple lock wherever it's necessary and also keeping thewith_mut
so we can use whichever we need.
lock
also needs to take &mut self
for the same reasons.
Generally, I am not a fan of having both lock
and with_mut
since they are just two ways of doing the same thing. I am okay with either of them, but we should decide for one.
aabc8a2
to
f7ad5e9
Compare
Fixes: #170
This PR changes:
Shared
struct internally handles the mutex.Shared
struct now hasinner: Arc<Mutex<SharedInner>>