-
Notifications
You must be signed in to change notification settings - Fork 762
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
New windows implementation strategies from wepoll #1034
Conversation
Changed readv, writev function signature from ```&self``` to ```&mut self```
Added possible fix line on Token documentation.
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 doing this @PerfectLaugh. This one of the major blocking points for v0.7 so I've been looking forward to this for a while.
I've left some comments, but I didn't review the actual implementation as I don't know enough about IOCP to review this.
Now all the test suite is passed. |
src/sys/windows/selector.rs
Outdated
trace!("returning"); | ||
Ok(()) | ||
} | ||
// Codes to emulate ET in mio |
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.
@PerfectLaugh
Can you elaborate a bit on how this works?
In wepoll there's no way I can emulate edge-triggered, because I don't know when the user has attempted to read/write from a socket, so I don't know when to re-submit the AFD_POLL overlappped operation. I think in mio's case it might be possible because we can know when a socket read/write results in WSAEWOULDBLOCK.
But I don't see how that works here.
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 work is in tcp.rs udp.rs. where I hooked all possible calls the WouldBlock could appear.
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.
And the codes here is to eliminate those events that have been read. So we can simulate proper ET behavior (probably?
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 you explain how this code eliminates events that have been read?
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 code simply rely on assumption that mio can control and intercept every aspects that user will do to this socket. With this assumption (As long as rawsocket is not being manipulated by external library or raw api calls), we can wipe down the interests that user hasn't done it, simulating the ET behavior.
Strangely this compiles in debug but not release mode (x86_64-pc-windows-msvc) |
Fixed. |
src/sys/windows/sourcerawsocket.rs
Outdated
/// fn register(&self, registry: &Registry, token: Token, interests: Interests) | ||
/// -> io::Result<()> | ||
/// { | ||
/// SourceRawSocket::new(&self.raw_socket).register(registry, token, interests) |
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 usage is rather expensive if we're creating a new Arc<Mutex<..>>
each call to register. If we can't do without the SockState
we might need to go for a different design.
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 problem is we need to simulate ET behavior. Then we do need SockState to maintain what interests have been read
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.
That is fine, but would the example still work then? It throws about the same after each call to (re)register doesn't it?
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.
Indeed. You are right. I cannot hold all the actions user took on the RawSocket.
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.
Then the library will need to take level trigger approach rather than edge trigger
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.
or just remove SourceRawSocket
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.
Let's remove it for now then and we'll find another approach later.
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.
Removed
src/sys/windows/afd.rs
Outdated
|
||
pub fn cancel(&self, iosb: &mut IO_STATUS_BLOCK) -> io::Result<()> { | ||
unsafe { | ||
if iosb.u.Status != STATUS_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.
The IO_STATUS_BLOCK can be updated by the kernel any time when the operation is pending.
So it should probably be wrapped in an UnsafeCell and be pinned.
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.
UnsafeCell has no Deref trait implemented therefore cannot be pinned. I used the Box instead.
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 can guarantee that certain memory doesn't move it can be pinned, then you don't need to use Box
. But these kind of optimisations can be done later.
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.
Uploaded new code. Please check
Please check the documentation I added also. My English is the worst of the world and I don't want any syntax/grammar error. |
src/sys/windows/selector.rs
Outdated
/// and once complete they'll be put back in. | ||
buffers: Mutex<BufferPool>, | ||
pub struct SockState { | ||
iosb: Pin<IoStatusBlock>, |
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 don't think this Pin
is current. I didn't following the entire previous discussion but I think IoStatusBlock
can't move right? If that is the case it need to implemented !Pin
(by using std::marker::PhantomPinned
). Next it needs to be allocated in memory where it won't move, likely on the heap. The easier way to do that is to use Pin<Box<IoStatusBlock>>
. Later we can figure out if we can remove the box by making SockState
pinned.
Also note that all methods on IoStatusBlock
should accept Pin<&mut Self>
rather then &mut self
(see the std::future::Future
trait for an example).
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.
SockState is wrapped by Arc<Mutex> all the time. I think it is actually safe not using Pin though.
I will do Pin<Box> for now.
} | ||
events.events.push(Event::new(Ready::READABLE, token)); | ||
continue; | ||
unsafe { |
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.
Can you reduce this unsafe block and add a comment why it is safe?
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 cannot because the logic is connected. It is better to put this still.
// We use the status info in IO_STATUS_BLOCK to determine the socket poll status. It is unsafe to use a pointer of IO_STATUS_BLOCK.
@PerfectLaugh can you not mention me via @ in commits, now I'm going to get an email from GitHub every time something happens with that commit, thanks. |
sorry |
I would like to get this PR merged sooner than later. Any non critical follow up change can be tracked in a follow up issue. @Thomasdezeeuw @piscisaureus could you list out any changes that are blocking merging this? |
I'm fine with merging now, all my comments can be fixed later. |
I opened #1041 to track changes. Once we get the 👍 from @piscisaureus, I will merge this and extract all remaining items & questions into #1041. |
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.
LGTM
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 doing this @PerfectLaugh 👍 💯
Thank you @PerfectLaugh you've helped us with one of the major blockers for Mio v0.7! |
Currently this passed most of the test suite. Except for a test in Token documentation.
https://gist.github.com/PerfectLaugh/07fb4766be01e797a678357706828f1d