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
82 changes: 82 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
### 0.6.x

- [x] support custom task and coroutine priority.
- [x] support scalable stack

### 0.5.x

- [x] refactor syscall state, distinguish between state and innerState

### 0.4.x

- [x] Supports and is compatible with io_uring in terms of local file IO
- [x] elegant shutdown
- [x] use log instead of println
- [x] enhance `#[open_coroutine::main]` macro
- [x] refactor hook impl, no need to publish dylibs now
- [x] `Monitor` follow the `thread-per-core` guideline
- [x] `EventLoop` follow the `thread-per-core` guideline

### 0.3.x

- [x] ~~support `genawaiter` as low_level stackless coroutine (can't support it due to hook)~~
- [x] use `corosensei` as low_level coroutine
- [x] support backtrace
- [x] support `#[open_coroutine::co]` macro
- [x] refactor `WorkStealQueue`

### 0.2.x

- [x] use correct `epoll_event` struct
- [x] use `rayon` for parallel computing
- [x] support `#[open_coroutine::main]` macro
- [x] hook almost all `read` syscall
<details>
<summary>read syscalls</summary>

- [x] recv
- [x] readv
- [x] pread
- [x] preadv
- [x] recvfrom
- [x] recvmsg

</details>

- [x] hook almost all `write` syscall
<details>
<summary>write syscalls</summary>

- [x] send
- [x] writev
- [x] sendto
- [x] sendmsg
- [x] pwrite
- [x] pwritev

</details>

- [x] hook other syscall
<details>
<summary>other syscalls</summary>

- [x] sleep
- [x] usleep
- [x] nanosleep
- [x] connect
- [x] listen
- [x] accept
- [x] shutdown
- [x] poll
- [x] select

</details>

### 0.1.x

- [x] basic suspend/resume supported
- [x] use jemalloc as memory pool
- [x] higher level coroutine abstraction supported
- [x] preemptive scheduling supported
- [x] work stealing supported
- [x] sleep system call hooks supported
281 changes: 38 additions & 243 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@

The `open-coroutine` is a simple, efficient and generic stackful-coroutine library.

<div style="text-align: center;">
<img src="https://github.com/acl-dev/open-coroutine-docs/blob/master/img/architecture.png" width="100%">
</div>
## 🚀 Features

[我有故事,你有酒吗?](https://github.com/acl-dev/open-coroutine-docs)
- [x] Preemptive(`not supported in windows`): even if the coroutine enters a dead loop, it can still be seized, see [example](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/preemptive.rs);
- [x] Hook: you are free to use most of the slow system calls in coroutine;
- [x] Scalable: the size of the coroutine stack supports unlimited expansion, and immediately shrinks to the original size after use, see [example](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/scalable_stack.rs);
- [x] io_uring(`only in linux`): supports and is compatible with io_uring in terms of local file IO and network IO. If it's not supported on your system, it will fall back to non-blocking IO;
- [x] Priority: support custom task and coroutine priority;
- [x] Work Stealing: internally using a lock free work steel queue;
- [x] Compatibility: the implementation of open-coroutine is no async, but it is compatible with async, which means you can use this crate in tokeno/sync-std/smol/...;
- [x] Platforms: running on Linux, MacOS and Windows;

## Status
## 🕊 Roadmap

Still under development, please `do not` use this library in the `production` environment !
- [ ] support `#[open_coroutine::all_join]` and `#[open_coroutine::any_join]` macro to wait coroutines;
- [ ] add synchronization toolkit;
- [ ] support and compatibility for AF_XDP socket;

## How to use this library ?
## 📖 Quick Start

### step1: add dependency to your Cargo.toml

Expand All @@ -39,253 +46,41 @@ fn main() {
}
```

### step3: enjoy the performance improvement brought by open-coroutine !

## Examples

### Amazing preemptive schedule

Note: not supported for windows
### step3: create a task

```rust
#[open_coroutine::main]
fn main() -> std::io::Result<()> {
cfg_if::cfg_if! {
if #[cfg(all(unix, feature = "preemptive-schedule"))] {
use open_coroutine_core::scheduler::Scheduler;
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;

static mut TEST_FLAG1: bool = true;
static mut TEST_FLAG2: bool = true;
let pair = Arc::new((Mutex::new(true), Condvar::new()));
let pair2 = Arc::clone(&pair);
let handler = std::thread::Builder::new()
.name("preemptive".to_string())
.spawn(move || {
let scheduler = Scheduler::new();
_ = scheduler.submit(
|_, _| {
println!("coroutine1 launched");
while unsafe { TEST_FLAG1 } {
println!("loop1");
_ = unsafe { libc::usleep(10_000) };
}
println!("loop1 end");
1
},
None,
);
_ = scheduler.submit(
|_, _| {
println!("coroutine2 launched");
while unsafe { TEST_FLAG2 } {
println!("loop2");
_ = unsafe { libc::usleep(10_000) };
}
println!("loop2 end");
unsafe { TEST_FLAG1 = false };
2
},
None,
);
_ = scheduler.submit(
|_, _| {
println!("coroutine3 launched");
unsafe { TEST_FLAG2 = false };
3
},
None,
);
scheduler.try_schedule();

let (lock, cvar) = &*pair2;
let mut pending = lock.lock().unwrap();
*pending = false;
// notify the condvar that the value has changed.
cvar.notify_one();
})
.expect("failed to spawn thread");

// wait for the thread to start up
let (lock, cvar) = &*pair;
let result = cvar
.wait_timeout_while(
lock.lock().unwrap(),
Duration::from_millis(3000),
|&mut pending| pending,
)
.unwrap();
if result.1.timed_out() {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"preemptive schedule failed",
))
} else {
unsafe {
handler.join().unwrap();
assert!(!TEST_FLAG1);
}
Ok(())
}
} else {
println!("please enable preemptive-schedule feature");
Ok(())
}
}
fn main() {
let task = open_coroutine::task!(|param| {
assert_eq!(param, 1);
}, 1);
task.timeout_join(std::time::Duration::from_secs(1)).expect("timeout");
}
```

outputs

```text
coroutine1 launched
loop1
coroutine2 launched
loop2
coroutine3 launched
loop1
loop2 end
loop1 end
```

### Arbitrary use of blocking syscalls
### step4: scalable stack(optional)

```rust
#[open_coroutine::main]
fn main() {
std::thread::sleep(std::time::Duration::from_secs(1));
_ = open_coroutine::task!(|_| {
fn recurse(i: u32, p: &mut [u8; 10240]) {
open_coroutine::maybe_grow!(|| {
// Ensure the stack allocation isn't optimized away.
unsafe { _ = std::ptr::read_volatile(&p) };
if i > 0 {
recurse(i - 1, &mut [0; 10240]);
}
})
.expect("allocate stack failed")
}
println!("[coroutine] launched");
// Use ~500KB of stack.
recurse(50, &mut [0; 10240]);
}, ());
}
```

outputs

```text
nanosleep hooked
```

## Features

### todo

- [ ] support and compatibility for AF_XDP socket
- [ ] hook other syscall maybe interrupt by signal
<details>
<summary>syscalls</summary>

- [ ] open
- [ ] chdir
- [ ] chroot
- [ ] readlink
- [ ] stat
- [ ] dup
- [ ] dup2
- [ ] umask
- [ ] mount
- [ ] umount
- [ ] mknod
- [ ] fcntl
- [ ] truncate
- [ ] ftruncate
- [ ] setjmp
- [ ] longjmp
- [ ] chown
- [ ] lchown
- [ ] fchown
- [ ] chmod
- [ ] fchmod
- [ ] fchmodat
- [ ] semop
- [ ] ppoll
- [ ] pselect
- [ ] io_getevents
- [ ] semop
- [ ] semtimedop
- [ ] msgrcv
- [ ] msgsnd
## ⚓ Learn

</details>
- [ ] support `#[open_coroutine::join]` macro to wait coroutines

### 0.6.x

- [x] support custom task and coroutine priority.
- [x] support scalable stack

### 0.5.x

- [x] refactor syscall state, distinguish between state and innerState

### 0.4.x

- [x] Supports and is compatible with io_uring in terms of local file IO
- [x] elegant shutdown
- [x] use log instead of println
- [x] enhance `#[open_coroutine::main]` macro
- [x] refactor hook impl, no need to publish dylibs now
- [x] `Monitor` follow the `thread-per-core` guideline
- [x] `EventLoop` follow the `thread-per-core` guideline

### 0.3.x

- [x] ~~support `genawaiter` as low_level stackless coroutine (can't support it due to hook)~~
- [x] use `corosensei` as low_level coroutine
- [x] support backtrace
- [x] support `#[open_coroutine::co]` macro
- [x] refactor `WorkStealQueue`

### 0.2.x

- [x] use correct `epoll_event` struct
- [x] use `rayon` for parallel computing
- [x] support `#[open_coroutine::main]` macro
- [x] hook almost all `read` syscall
<details>
<summary>read syscalls</summary>

- [x] recv
- [x] readv
- [x] pread
- [x] preadv
- [x] recvfrom
- [x] recvmsg

</details>

- [x] hook almost all `write` syscall
<details>
<summary>write syscalls</summary>

- [x] send
- [x] writev
- [x] sendto
- [x] sendmsg
- [x] pwrite
- [x] pwritev

</details>

- [x] hook other syscall
<details>
<summary>other syscalls</summary>

- [x] sleep
- [x] usleep
- [x] nanosleep
- [x] connect
- [x] listen
- [x] accept
- [x] shutdown
- [x] poll
- [x] select

</details>

### 0.1.x

- [x] basic suspend/resume supported
- [x] use jemalloc as memory pool
- [x] higher level coroutine abstraction supported
- [x] preemptive scheduling supported
- [x] work stealing supported
- [x] sleep system call hooks supported
[我有故事,你有酒吗?](https://github.com/acl-dev/open-coroutine-docs)
Loading
Loading