Skip to content

Commit bcfb4b7

Browse files
authored
hook more syscall (#371)
2 parents 4301874 + a626efe commit bcfb4b7

File tree

17 files changed

+406
-59
lines changed

17 files changed

+406
-59
lines changed

core/docs/en/coroutine.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,38 @@ author: loongs-zhang
66

77
# Coroutine Overview
88

9+
## Usage
10+
11+
```rust
12+
use open_coroutine_core::common::constants::CoroutineState;
13+
use open_coroutine_core::coroutine::Coroutine;
14+
15+
fn main() -> std::io::Result<()> {
16+
let mut co = Coroutine::new(
17+
// optional coroutine name
18+
None,
19+
|suspender, input| {
20+
assert_eq!(1, input);
21+
assert_eq!(3, suspender.suspend_with(2));
22+
4
23+
},
24+
// optional stack size
25+
None,
26+
// optional coroutine priority
27+
None,
28+
)?;
29+
// Macro `co!` is equivalent to the code above
30+
// let mut co = open_coroutine_core::co!(|suspender, input| {
31+
// assert_eq!(1, input);
32+
// assert_eq!(3, suspender.suspend_with(2));
33+
// 4
34+
// })?;
35+
assert_eq!(CoroutineState::Suspend(2, 0), co.resume_with(1)?);
36+
assert_eq!(CoroutineState::Complete(4), co.resume_with(3)?);
37+
Ok(())
38+
}
39+
```
40+
941
## What is coroutine?
1042

1143
A [coroutine](https://en.wikipedia.org/wiki/Coroutine) is a function that can be paused and resumed, yielding values to
@@ -15,6 +47,26 @@ resumed.
1547

1648
The above is excerpted from [corosensei](https://github.com/Amanieu/corosensei).
1749

50+
## Coroutine VS Thread
51+
52+
| | coroutine | thread |
53+
|-------------------|-----------|---------|
54+
| switch efficiency | ✅ Higher | ❌ High |
55+
| memory efficiency | KB/MB | KB/MB |
56+
| scheduled by OS |||
57+
| stack grow |||
58+
59+
## Stackfull VS Stackless
60+
61+
| | stackfull | stackless |
62+
|-------------------|-----------|-----------|
63+
| switch efficiency | ❌ High | ✅ Higher |
64+
| memory efficiency | ❌ KB/MB | ✅ Bytes |
65+
| limitations | ✅ Few | ❌ Many |
66+
67+
In general, if the requirements for resource utilization and switching performance are not very strict, using a
68+
stackfull approach would be more convenient and the code would be easier to maintain.
69+
1870
## State in open-coroutine
1971

2072
```text

core/docs/en/monitor.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,37 @@ The `preemptive` feature currently supports the following targets:
2121

2222
✅ Tested and stable; ⚠️ Tested but unstable; ❌ Not supported.
2323

24+
## Usage
25+
26+
```rust
27+
use open_coroutine_core::co;
28+
use open_coroutine_core::common::constants::CoroutineState;
29+
use open_coroutine_core::coroutine::Coroutine;
30+
31+
fn main() -> std::io::Result<()> {
32+
// Simulate the most extreme dead loop, if the preemptive feature
33+
// is not enabled, it will remain stuck in a dead loop after resume.
34+
let mut coroutine: Coroutine<(), (), ()> = co!(|_, ()| { loop {} })?;
35+
assert_eq!(CoroutineState::Suspend((), 0), coroutine.resume()?);
36+
assert_eq!(CoroutineState::Suspend((), 0), coroutine.state());
37+
Ok(())
38+
}
39+
```
40+
41+
## What is monitor?
42+
43+
The `monitor` mod implements the `preemptive` feature for open-coroutine, which allows the coroutine to be preempted
44+
when it is running for a long time.
45+
46+
## Why preempt
47+
48+
After a `Coroutine::resume_with`, a coroutine may occupy the scheduling thread for a long time, thereby slowing down
49+
other coroutines scheduled by that scheduling thread. To solve this problem, we introduce preemptive scheduling, which
50+
automatically suspends coroutines that are stuck in long-term execution and allows other coroutines to execute.
51+
52+
The coroutine occupies scheduling threads for a long time in two scenarios: getting stuck in heavy computing or syscall.
53+
The following only solves the problem of getting stuck in heavy computing.
54+
2455
## How it works
2556

2657
```mermaid

core/src/coroutine/korosensei.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,20 +381,23 @@ where
381381
///# Errors
382382
/// if stack allocate failed.
383383
pub fn new<F>(
384-
name: String,
384+
name: Option<String>,
385385
f: F,
386-
stack_size: usize,
386+
stack_size: Option<usize>,
387387
priority: Option<c_longlong>,
388388
) -> std::io::Result<Self>
389389
where
390390
F: FnOnce(&Suspender<Param, Yield>, Param) -> Return + 'static,
391391
{
392-
let stack_size = stack_size.max(crate::common::page_size());
392+
let stack_size = stack_size
393+
.unwrap_or(crate::common::constants::DEFAULT_STACK_SIZE)
394+
.max(crate::common::page_size());
393395
let stack = DefaultStack::new(stack_size)?;
394396
let stack_infos = UnsafeCell::new(VecDeque::from([StackInfo {
395397
stack_top: stack.base().get(),
396398
stack_bottom: stack.limit().get(),
397399
}]));
400+
let name = name.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
398401
let co_name = name.clone().leak();
399402
let inner = corosensei::Coroutine::with_stack(stack, move |y, p| {
400403
catch!(

core/src/coroutine/mod.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,34 +29,19 @@ macro_rules! co {
2929
$crate::coroutine::Coroutine::new($name, $f, $size, $priority)
3030
};
3131
($f:expr, $size:literal, $priority:literal $(,)?) => {
32-
$crate::coroutine::Coroutine::new(
33-
uuid::Uuid::new_v4().to_string(),
34-
$f,
35-
$size,
36-
Some($priority),
37-
)
32+
$crate::coroutine::Coroutine::new(None, $f, $size, Some($priority))
3833
};
3934
($name:expr, $f:expr, $size:expr $(,)?) => {
4035
$crate::coroutine::Coroutine::new($name, $f, $size, None)
4136
};
4237
($f:expr, $size:literal $(,)?) => {
43-
$crate::coroutine::Coroutine::new(uuid::Uuid::new_v4().to_string(), $f, $size, None)
38+
$crate::coroutine::Coroutine::new(None, $f, $size, None)
4439
};
4540
($name:expr, $f:expr $(,)?) => {
46-
$crate::coroutine::Coroutine::new(
47-
$name,
48-
$f,
49-
$crate::common::constants::DEFAULT_STACK_SIZE,
50-
None,
51-
)
41+
$crate::coroutine::Coroutine::new($name, $f, None, None)
5242
};
5343
($f:expr $(,)?) => {
54-
$crate::coroutine::Coroutine::new(
55-
uuid::Uuid::new_v4().to_string(),
56-
$f,
57-
$crate::common::constants::DEFAULT_STACK_SIZE,
58-
None,
59-
)
44+
$crate::coroutine::Coroutine::new(None, $f, None, None)
6045
};
6146
}
6247

core/src/net/event_loop.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use std::time::Duration;
1818

1919
cfg_if::cfg_if! {
2020
if #[cfg(all(target_os = "linux", feature = "io_uring"))] {
21-
use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t};
2221
use dashmap::DashMap;
23-
use std::ffi::c_longlong;
22+
use libc::{epoll_event, iovec, mode_t, msghdr, off_t, size_t, sockaddr, socklen_t};
23+
use std::ffi::{c_longlong, c_uint};
2424
}
2525
}
2626

@@ -441,6 +441,10 @@ impl_io_uring!(pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_
441441
impl_io_uring!(writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t);
442442
impl_io_uring!(pwritev(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off_t) -> ssize_t);
443443
impl_io_uring!(sendmsg(fd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t);
444+
impl_io_uring!(fsync(fd: c_int) -> c_int);
445+
impl_io_uring!(mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int);
446+
impl_io_uring!(renameat(olddirfd: c_int, oldpath: *const c_char, newdirfd: c_int, newpath: *const c_char) -> c_int);
447+
impl_io_uring!(renameat2(olddirfd: c_int, oldpath: *const c_char, newdirfd: c_int, newpath: *const c_char, flags: c_uint) -> c_int);
444448

445449
#[cfg(all(test, not(all(unix, feature = "preemptive"))))]
446450
mod tests {

core/src/net/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::time::Duration;
1313

1414
cfg_if::cfg_if! {
1515
if #[cfg(all(target_os = "linux", feature = "io_uring"))] {
16-
use libc::{epoll_event, iovec, msghdr, off_t, size_t, sockaddr, socklen_t};
17-
use std::ffi::c_void;
16+
use libc::{epoll_event, iovec, mode_t, msghdr, off_t, size_t, sockaddr, socklen_t};
17+
use std::ffi::{c_char, c_uint, c_void};
1818
}
1919
}
2020

@@ -276,3 +276,7 @@ impl_io_uring!(pwrite(fd: c_int, buf: *const c_void, count: size_t, offset: off_
276276
impl_io_uring!(writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t);
277277
impl_io_uring!(pwritev(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off_t) -> ssize_t);
278278
impl_io_uring!(sendmsg(fd: c_int, msg: *const msghdr, flags: c_int) -> ssize_t);
279+
impl_io_uring!(fsync(fd: c_int) -> c_int);
280+
impl_io_uring!(mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int);
281+
impl_io_uring!(renameat(olddirfd: c_int, oldpath: *const c_char, newdirfd: c_int, newpath: *const c_char) -> c_int);
282+
impl_io_uring!(renameat2(olddirfd: c_int, oldpath: *const c_char, newdirfd: c_int, newpath: *const c_char, flags: c_uint) -> c_int);

core/src/scheduler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,9 @@ impl<'s> Scheduler<'s> {
177177
priority: Option<c_longlong>,
178178
) -> std::io::Result<()> {
179179
self.submit_raw_co(co!(
180-
format!("{}@{}", self.name(), uuid::Uuid::new_v4()),
180+
Some(format!("{}@{}", self.name(), uuid::Uuid::new_v4())),
181181
f,
182-
stack_size.unwrap_or(self.stack_size()),
182+
Some(stack_size.unwrap_or(self.stack_size())),
183183
priority
184184
)?)
185185
}

core/src/syscall/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
macro_rules! syscall_mod {
2-
($($mod_name: ident);*) => {
2+
($($mod_name: ident);*$(;)?) => {
33
$(
44
pub use $mod_name::$mod_name;
55
mod $mod_name;

core/src/syscall/unix/fsync.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use once_cell::sync::Lazy;
2+
use std::ffi::c_int;
3+
4+
#[must_use]
5+
pub extern "C" fn fsync(
6+
fn_ptr: Option<&extern "C" fn(c_int) -> c_int>,
7+
fd: c_int,
8+
) -> c_int {
9+
cfg_if::cfg_if! {
10+
if #[cfg(all(target_os = "linux", feature = "io_uring"))] {
11+
static CHAIN: Lazy<FsyncSyscallFacade<IoUringFsyncSyscall<RawFsyncSyscall>>> =
12+
Lazy::new(Default::default);
13+
} else {
14+
static CHAIN: Lazy<FsyncSyscallFacade<RawFsyncSyscall>> = Lazy::new(Default::default);
15+
}
16+
}
17+
CHAIN.fsync(fn_ptr, fd)
18+
}
19+
20+
trait FsyncSyscall {
21+
extern "C" fn fsync(
22+
&self,
23+
fn_ptr: Option<&extern "C" fn(c_int) -> c_int>,
24+
fd: c_int,
25+
) -> c_int;
26+
}
27+
28+
impl_facade!(FsyncSyscallFacade, FsyncSyscall, fsync(fd: c_int) -> c_int);
29+
30+
impl_io_uring!(IoUringFsyncSyscall, FsyncSyscall, fsync(fd: c_int) -> c_int);
31+
32+
impl_raw!(RawFsyncSyscall, FsyncSyscall, fsync(fd: c_int) -> c_int);

core/src/syscall/unix/mkdirat.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use libc::mode_t;
2+
use once_cell::sync::Lazy;
3+
use std::ffi::{c_char, c_int};
4+
5+
#[must_use]
6+
pub extern "C" fn mkdirat(
7+
fn_ptr: Option<&extern "C" fn(c_int, *const c_char, mode_t) -> c_int>,
8+
dirfd: c_int,
9+
pathname: *const c_char,
10+
mode: mode_t,
11+
) -> c_int {
12+
cfg_if::cfg_if! {
13+
if #[cfg(all(target_os = "linux", feature = "io_uring"))] {
14+
static CHAIN: Lazy<MkdiratSyscallFacade<IoUringMkdiratSyscall<RawMkdiratSyscall>>> =
15+
Lazy::new(Default::default);
16+
} else {
17+
static CHAIN: Lazy<MkdiratSyscallFacade<RawMkdiratSyscall>> = Lazy::new(Default::default);
18+
}
19+
}
20+
CHAIN.mkdirat(fn_ptr, dirfd, pathname, mode)
21+
}
22+
23+
trait MkdiratSyscall {
24+
extern "C" fn mkdirat(
25+
&self,
26+
fn_ptr: Option<&extern "C" fn(c_int, *const c_char, mode_t) -> c_int>,
27+
dirfd: c_int,
28+
pathname: *const c_char,
29+
mode: mode_t,
30+
) -> c_int;
31+
}
32+
33+
impl_facade!(MkdiratSyscallFacade, MkdiratSyscall,
34+
mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int
35+
);
36+
37+
impl_io_uring!(IoUringMkdiratSyscall, MkdiratSyscall,
38+
mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int
39+
);
40+
41+
impl_raw!(RawMkdiratSyscall, MkdiratSyscall,
42+
mkdirat(dirfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int
43+
);

0 commit comments

Comments
 (0)