Skip to content
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

windows: support custom completion port integrations #1047

Closed
piscisaureus opened this issue Jul 27, 2019 · 11 comments
Closed

windows: support custom completion port integrations #1047

piscisaureus opened this issue Jul 27, 2019 · 11 comments
Assignees
Labels
windows Related to the Windows OS.

Comments

@piscisaureus
Copy link
Contributor

The new "wepoll" strategy is great for sockets but it makes it impossible to use the thread's I/O completion port for other purposes.
I would suggest to add a low-level "plugin" system so that other crates can share the completion port for different purposes.

This could be used for supporting named pipes and files, which can use overlapped I/O but their APIs work differently; more exotic examples are ReadDirectoryChangesW (file change notifications), GetAddrInfoExW (async DNS name lookup), and Job Objects (notifications about child processes).

Job objects in particular are exotic in that windows will send messages to the completion port where lpOverlapped does not actually point to a struct OVERLAPPED, but rather contains an indication of the event that happened.

So I would propose to to "switch" based on the lpCompletionKey value. The most simple solution would be to store a function pointer in it which receives the raw completion information, e.g. fn handle_completion(&OVERLAPPED_ENTRY).

To illustrate what I mean, here's a crude prototype: piscisaureus@ac40cd7

Notice how the Selector is no longer knows anything about Wake events.
They work simply because the lpCompletionKey contains an appropriate function pointer

@Thomasdezeeuw
Copy link
Collaborator

Related #526.

@Thomasdezeeuw Thomasdezeeuw added this to the v0.7 milestone Aug 20, 2019
@Thomasdezeeuw
Copy link
Collaborator

I think this is related to a SourceSocket idea as discussed in #880 (comment).

@Thomasdezeeuw Thomasdezeeuw added the windows Related to the Windows OS. label Sep 27, 2019
@Thomasdezeeuw
Copy link
Collaborator

Punting to v1.0.

@Thomasdezeeuw Thomasdezeeuw modified the milestones: v0.7, v1.0 Dec 4, 2019
@carllerche carllerche mentioned this issue Dec 4, 2019
16 tasks
@carllerche
Copy link
Member

@piscisaureus I have a question re: this proposal.

My understanding is that, when an OVERLAPPED operation is submitted to the OS, the OS needs "ownership" of the pointer. Ownership is returned back to the caller when the operation is completed and the overlapped is received during a "poll".

This implies that the selector needs to know about "in-flight" operations. This needs to happen so that when the Poll handle is dropped, it knows to wait until "in-flight" operations complete.

It gets a bit more complicated with "read" like operations that may not complete... in those cases, Poll needs to know about all inflight operations, signal to them to start shutting down, then wait to receive the OVERLAPS before dropping.

Do you have thoughts on how to model this?

@dtacalau
Copy link
Contributor

dtacalau commented Dec 5, 2019

@Thomasdezeeuw please assign this issue to me, will start working on it.

@carllerche
Copy link
Member

@dtacalau before writing code we should have a solid proposal in place. I think bert’s sketch is a good starting point but we want to figure out the answers to my previous comment as well as a nice rust API to expose.

@dtacalau dtacalau mentioned this issue Dec 7, 2019
@piscisaureus
Copy link
Contributor Author

@carllerche

My understanding is that, when an OVERLAPPED operation is submitted to the OS, the OS needs "ownership" of the pointer. Ownership is returned back to the caller when the operation is completed and the overlapped is received during a "poll".
Do you have thoughts on how to model this?

Make sure the Overlapped is wrapped (either directly or indirectly) wrapped in an Arc.

When an async I/O operation is successfully started (and you know the kernel now implicitly owns the OVERLAPPED) you artificially increase the Arc's reference count by cloning and forgetting the Arc.

When the operation completes and you receive a OVERLAPPED* from GetQueuedCompletionStatus, do some pointer math if necessary to get back at the wrapper struct, and then transmute/cast that back to an Arc, thereby effectively reversing the std::mem::forget::() we did after starting the operation.

I think the most elegant way was in this (rejected) patch:

@Thomasdezeeuw
Copy link
Collaborator

@piscisaureus that patch, with modifications, made it into the code base:

/// Converts the pointer to a `SockState` into a raw pointer.
/// To revert see `from_overlapped`.
fn into_overlapped(sock_state: Pin<Arc<Mutex<SockState>>>) -> PVOID {
let overlapped_ptr: *const Mutex<SockState> =
unsafe { Arc::into_raw(Pin::into_inner_unchecked(sock_state)) };
overlapped_ptr as *mut _
}
/// Convert a raw overlapped pointer into a reference to `SockState`.
/// Reverts `into_overlapped`.
fn from_overlapped(ptr: *mut OVERLAPPED) -> Pin<Arc<Mutex<SockState>>> {
let sock_ptr: *const Mutex<SockState> = ptr as *const _;
unsafe { Pin::new_unchecked(Arc::from_raw(sock_ptr)) }
}
. I think we're doing it correctly now, the way you've explained it.

@carllerche
Copy link
Member

Instead of making an API to hook into IOCP, would it be plausible to provide bindings to all the IOCP compatible types? The various types could be guarded w/ feature flags.

@Thomasdezeeuw Thomasdezeeuw removed this from the v1.0 milestone Jan 5, 2021
@Thomasdezeeuw
Copy link
Collaborator

Not blocking a v1.0 release.

@Thomasdezeeuw
Copy link
Collaborator

We have/had a partially working solution in #1345, but there is not enough interest to make this work. Because of this I'm closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
windows Related to the Windows OS.
Projects
None yet
Development

No branches or pull requests

4 participants