compio-rs / compio

A thread-per-core Rust runtime with IOCP/io_uring/polling.
MIT License
420 stars 37 forks source link

Registered fd support #37

Closed DXist closed 1 year ago

DXist commented 1 year ago

This is initial implementation of registered file descriptors - tested only on IO uring.

A pool of descriptors is registered when driver is created. For each operation that creates a file descriptor users provide the chosen RegisteredFd values and driver issues synchronous register_files_update.

For Windows driver emulates registration and maps registered fd to raw fds during interaction with kerhel.

I changed File's open/create method to async because it's possible to open files asyncronously with IO uring.

Later it's possible to implement async OpenAt and Socket operations that could create a direct registered file descriptor.

Berrysoft commented 1 year ago

Please do not change the signature of File::open etc. to accept RegisteredFd. That's terrible. RegisteredFd is a low-level implementation detail. Instead, let the runtime or the driver allocate the registered fd.

It's OK to change open, connect, bind etc. to async, and you don't need to think about IOCP and mio.

Just leaving registered fd feature as io-uring specific is OK. IOCP and mio don't need registered fd because it will increase overhead.

DXist commented 1 year ago

It seems that bind & listen for direct socket descriptors aren't supported yet - https://github.com/axboe/liburing/issues/941

These syscalls don't do any IO and are issued not often. Probably doesn't make sense to provide async API.

DXist commented 1 year ago

@Berrysoft , I've added logic that tracks registered file descriptors in boxed bit slice. Tests on IO uring pass except the doctests related to async open operation.

IOCP port is configured inside registration logic so I removed attach method.

Berrysoft commented 1 year ago

Would you resolve the conflicts? There are many changes merged recently.

DXist commented 1 year ago

Ok. Do you think it makes sense to provide non async File methods when runtime feature is not enabled?

Berrysoft commented 1 year ago

I prefer a unified interface. If only one target needs async, make the method async on all platforms and add comments about that. (see sync_* in File.)

DXist commented 1 year ago

I reverted to sync open for unified interface and integrated RegisteredFd with mio.

Also set blocking socket for Linux and fixed tcp_connect tests.

Berrysoft commented 1 year ago

The error on Windows is WSAEFAULT, which means the sockaddr pointer or length is invalid.

https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2

Berrysoft commented 1 year ago

In this PR, you chose to add registered file descriptor as a cross-platform feature. That's what I'm against to. RegFds should be only for io-uring. Neither IOCP nor mio will benefit from that.

However, if you just make the RawFd on Linux means the registered file descriptor, that's OK, because it won't influence the logic of other drivers.

Or, if you make the registered as a platform-dependent feature, it's also OK. When a user uses this feature, they should be aware that it's a Linux-only feature.

DXist commented 1 year ago

Another option is to have another fd type for operations that support registered file descriptors. On mio/windows it could be a type alias for RawFd. For IO uring we could alias it to io_uring::types::Target. Or use own type wrapper and own UseFixed trait.

High level API (File, Socket, etc.) items are always created with raw fds. It's possible to provide optional registration/deregistration for advanced users targeting Linux.

So user will have control on file descriptor tables both on application side (open/close) and kernel side (register/unregister).

Berrysoft commented 1 year ago

Why not define RawFd as an alias of Target for io-uring? However, Target is a private type, so we may need to declare a new one.

DXist commented 1 year ago

Why not define RawFd as an alias of Target for io-uring? However, Target is a private type, so we may need to declare a new one.

Yes, it's inside a sealed module.

We can make a structure that always holds RawFd (for AsRawFd implementation always point to RawFd) and Option<RegFd>. RegFd wraps Tokio's Fixed(u32) and non Send/Sync marker.

IO uring implementation either uses Fixed(u32) or creates Fd(RawFd).

Berrysoft commented 1 year ago

What I was always saying is

pub type RawFd = io_uring::types::Target;

-OR-

pub enum RawFd {
    Fd(i32),
    Fixed(u32),
}

but you were always saying defining two types... Did you understand my comments above?

DXist commented 1 year ago

We could do like that. For operations that are done via syscalls instead of IO uring we check if we got Fd(_) variant. If we got Fixed - it's a users mistake and we reveal it in runtime and panic.

DXist commented 1 year ago

Can we have Fd type in operations? In mio/windows Fd is RawFd alias.

On Linux it's an enum

pub enum Fd {
    Raw(RawFd),
    Fixed(RegFd),
}
Berrysoft commented 1 year ago

The name Fd is OK.

George-Miao commented 1 year ago

Closed for lack of activity. Re-open if you're interested in continuing contribution.