Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,21 @@ repository = "https://github.com/Berrysoft/compio"
[package.metadata.docs.rs]
all-features = true
default-target = "x86_64-pc-windows-msvc"
targets = ["x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu"]
targets = [
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-apple-darwin",
"aarch64-apple-ios",
"aarch64-linux-android",
"x86_64-unknown-dragonfly",
"x86_64-unknown-freebsd",
"x86_64-unknown-illumos",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-netbsd",
"x86_64-unknown-openbsd",
]

# Shared dependencies for all platforms
[dependencies]
async-task = { version = "4", optional = true }
bytes = { version = "1", optional = true }
Expand All @@ -25,12 +38,14 @@ once_cell = "1"
slab = { version = "0.4", optional = true }
socket2 = { version = "0.5", features = ["all"] }

# Shared dev dependencies for all platforms
[dev-dependencies]
criterion = { version = "0.5", features = ["async_tokio"] }
futures-channel = "0.3"
tempfile = "3"
tokio = { version = "1", features = ["fs", "io-util", "macros", "net", "rt"] }

# Windows specific dependencies
[target.'cfg(target_os = "windows")'.dependencies]
widestring = "1"
windows-sys = { version = "0.48", features = [
Expand All @@ -45,13 +60,20 @@ windows-sys = { version = "0.48", features = [
"Win32_System_Threading",
] }

# Windows specific dev dependencies
[target.'cfg(target_os = "windows")'.dev-dependencies]
windows-sys = { version = "0.48", features = ["Win32_Security_Authorization"] }

# Linux specific dependencies
[target.'cfg(target_os = "linux")'.dependencies]
io-uring = "0.6"
libc = "0.2"

# Other platform dependencies
[target.'cfg(all(not(target_os = "linux"), unix))'.dependencies]
mio = { version = "0.8.8", features = ["os-ext"] }
libc = "0.2"

[features]
default = ["runtime"]
runtime = ["dep:async-task", "dep:futures-util", "dep:slab"]
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![docs.rs](https://img.shields.io/badge/docs.rs-compio-latest)](https://docs.rs/compio)
[![Azure DevOps builds](https://strawberry-vs.visualstudio.com/compio/_apis/build/status/Berrysoft.compio?branch=master)](https://strawberry-vs.visualstudio.com/compio/_build)

A thread-per-core Rust runtime with IOCP/io_uring.
A thread-per-core Rust runtime with IOCP/io_uring/mio.
The name comes from "completion-based IO".
This crate is inspired by [monoio](https://github.com/bytedance/monoio/).

Expand All @@ -22,6 +22,7 @@ and `tokio` won't public APIs to control `mio` before `mio` reaches 1.0.
## Quick start

With `runtime` feature enabled, we can use the high level APIs to perform fs & net IO.

```rust,no_run
use compio::{fs::File, task::block_on};

Expand All @@ -36,6 +37,7 @@ println!("{}", buffer);
```

While you can also control the low-level driver manually:

```rust,no_run
use compio::{
buf::IntoInner,
Expand Down
23 changes: 22 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,39 @@ jobs:
cargo test --features all
displayName: TestStable

- job: Test_Mac
strategy:
matrix:
ventura:
image: macOS-13
monterey:
image: macOS-12
pool:
vmImage: $(image)

steps:
- script: |
rustup toolchain install nightly
cargo +nightly test --features all,nightly --no-default-features
displayName: TestNightly
- script: |
cargo test --features all
displayName: TestStable

- job: Doc
strategy:
matrix:
windows:
image: windows-latest
linux:
image: ubuntu-latest
macos:
image: macOS-latest
pool:
vmImage: $(image)

steps:
- script: |
rustup toolchain install nightly
cargo +nightly doc --features all --no-deps
cargo +nightly doc --all-features --no-deps
displayName: Build docs
115 changes: 6 additions & 109 deletions src/driver/iour/op.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
use std::io::{IoSlice, IoSliceMut};

use io_uring::{
opcode,
squeue::Entry,
types::{Fd, FsyncFlags},
};
use libc::{sockaddr_storage, socklen_t};
use socket2::SockAddr;
use libc::sockaddr_storage;

pub use crate::driver::unix::op::*;
use crate::{
buf::{AsIoSlices, AsIoSlicesMut, IntoInner, IoBuf, IoBufMut, OneOrVec},
driver::{OpCode, RawFd},
buf::{AsIoSlices, AsIoSlicesMut, IoBuf, IoBufMut},
driver::OpCode,
op::*,
};

Expand Down Expand Up @@ -44,29 +42,6 @@ impl OpCode for Sync {
}
}

/// Accept a connection.
pub struct Accept {
pub(crate) fd: RawFd,
pub(crate) buffer: sockaddr_storage,
pub(crate) addr_len: socklen_t,
}

impl Accept {
/// Create [`Accept`].
pub fn new(fd: RawFd) -> Self {
Self {
fd,
buffer: unsafe { std::mem::zeroed() },
addr_len: std::mem::size_of::<sockaddr_storage>() as _,
}
}

/// Get the remote address from the inner buffer.
pub fn into_addr(self) -> SockAddr {
unsafe { SockAddr::new(self.buffer, self.addr_len) }
}
}

impl OpCode for Accept {
fn create_entry(&mut self) -> Entry {
opcode::Accept::new(
Expand Down Expand Up @@ -108,96 +83,18 @@ impl<T: AsIoSlices> OpCode for SendImpl<T> {
}
}

/// Receive data and source address.
pub struct RecvFromImpl<T: AsIoSlicesMut> {
pub(crate) fd: RawFd,
pub(crate) buffer: T,
pub(crate) addr: sockaddr_storage,
pub(crate) slices: OneOrVec<IoSliceMut<'static>>,
msg: libc::msghdr,
}

impl<T: AsIoSlicesMut> RecvFromImpl<T> {
/// Create [`RecvFrom`] or [`RecvFromVectored`].
pub fn new(fd: RawFd, buffer: T::Inner) -> Self {
Self {
fd,
buffer: T::new(buffer),
addr: unsafe { std::mem::zeroed() },
slices: OneOrVec::One(IoSliceMut::new(&mut [])),
msg: unsafe { std::mem::zeroed() },
}
}
}

impl<T: AsIoSlicesMut> IntoInner for RecvFromImpl<T> {
type Inner = (T, sockaddr_storage, socklen_t);

fn into_inner(self) -> Self::Inner {
(self.buffer, self.addr, self.msg.msg_namelen)
}
}

impl<T: AsIoSlicesMut> OpCode for RecvFromImpl<T> {
#[allow(clippy::no_effect)]
fn create_entry(&mut self) -> Entry {
self.slices = unsafe { self.buffer.as_io_slices_mut() };
self.msg = libc::msghdr {
msg_name: &mut self.addr as *mut _ as _,
msg_namelen: 128,
msg_iov: self.slices.as_mut_ptr() as _,
msg_iovlen: self.slices.len(),
msg_control: std::ptr::null_mut(),
msg_controllen: 0,
msg_flags: 0,
};
self.set_msg();
opcode::RecvMsg::new(Fd(self.fd), &mut self.msg).build()
}
}

/// Send data to specified address.
pub struct SendToImpl<T: AsIoSlices> {
pub(crate) fd: RawFd,
pub(crate) buffer: T,
pub(crate) addr: SockAddr,
pub(crate) slices: OneOrVec<IoSlice<'static>>,
msg: libc::msghdr,
}

impl<T: AsIoSlices> SendToImpl<T> {
/// Create [`SendTo`] or [`SendToVectored`].
pub fn new(fd: RawFd, buffer: T::Inner, addr: SockAddr) -> Self {
Self {
fd,
buffer: T::new(buffer),
addr,
slices: OneOrVec::One(IoSlice::new(&[])),
msg: unsafe { std::mem::zeroed() },
}
}
}

impl<T: AsIoSlices> IntoInner for SendToImpl<T> {
type Inner = T;

fn into_inner(self) -> Self::Inner {
self.buffer
}
}

impl<T: AsIoSlices> OpCode for SendToImpl<T> {
#[allow(clippy::no_effect)]
fn create_entry(&mut self) -> Entry {
self.slices = unsafe { self.buffer.as_io_slices() };
self.msg = libc::msghdr {
msg_name: self.addr.as_ptr() as _,
msg_namelen: self.addr.len(),
msg_iov: self.slices.as_mut_ptr() as _,
msg_iovlen: self.slices.len(),
msg_control: std::ptr::null_mut(),
msg_controllen: 0,
msg_flags: 0,
};
self.set_msg();
opcode::SendMsg::new(Fd(self.fd), &self.msg).build()
}
}
Loading