Initial combined runtime
This commit is contained in:
commit
930bf80b21
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
Cargo.lock
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "jive"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
foxtrot = { git = "https://git.asonix.dog/safe-async/foxtrot" }
|
||||
jitterbug = { git = "https://git.asonix.dog/safe-async/jitterbug" }
|
||||
|
||||
[dev-dependencies]
|
||||
read-write-buf = { git = "https://git.asonix.dog/asonix/read-write-buf" }
|
83
examples/echo.rs
Normal file
83
examples/echo.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use jive::io::{Async, Nonblocking, ReadBytes, Readiness};
|
||||
use read_write_buf::ReadWriteBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() -> Result<(), jive::task::JoinError> {
|
||||
jive::block_on(async move {
|
||||
jive::spawn(async move {
|
||||
let listener = match Async::bind(([127, 0, 0, 1], 3456)).await {
|
||||
Ok(listener) => listener,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
println!("Listening on port 3456");
|
||||
|
||||
loop {
|
||||
let (stream, _addr) = match listener.accept().await {
|
||||
Ok(tup) => tup,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
jive::spawn(async move {
|
||||
println!("Accepted stream");
|
||||
|
||||
let mut ring_buf = ReadWriteBuf::<10>::new();
|
||||
let mut interests = Readiness::read();
|
||||
|
||||
'l2: loop {
|
||||
let readiness = stream.ready(interests).await?;
|
||||
|
||||
if readiness.is_hangup() {
|
||||
break;
|
||||
}
|
||||
|
||||
if readiness.is_read() {
|
||||
while let Some(buf) = ring_buf.for_reading() {
|
||||
match stream.read_nonblocking(buf)? {
|
||||
Nonblocking::Ready(ReadBytes::Read(n)) => {
|
||||
let n: usize = n.into();
|
||||
let should_break = n < buf.len();
|
||||
ring_buf.advance_read(n);
|
||||
if should_break {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Nonblocking::Ready(ReadBytes::EOF) if ring_buf.is_empty() => {
|
||||
break 'l2
|
||||
}
|
||||
Nonblocking::Ready(ReadBytes::EOF)
|
||||
| Nonblocking::WouldBlock => break,
|
||||
}
|
||||
}
|
||||
|
||||
if !ring_buf.is_empty() {
|
||||
interests = Readiness::read() | Readiness::write();
|
||||
}
|
||||
}
|
||||
|
||||
if readiness.is_write() {
|
||||
while let Some(buf) = ring_buf.for_writing() {
|
||||
match stream.write_nonblocking(buf)? {
|
||||
Nonblocking::Ready(n) => {
|
||||
ring_buf.advance_write(n);
|
||||
if ring_buf.is_empty() {
|
||||
interests = Readiness::read();
|
||||
}
|
||||
}
|
||||
Nonblocking::WouldBlock => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Stream closed");
|
||||
|
||||
Ok(()) as jive::io::Result<()>
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
jive::time::sleep(Duration::from_secs(60 * 2)).await;
|
||||
println!("Stopping");
|
||||
})
|
||||
}
|
80
src/lib.rs
Normal file
80
src/lib.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
#![feature(once_cell)]
|
||||
|
||||
use jitterbug::Executor;
|
||||
use std::{
|
||||
future::{pending, Future},
|
||||
lazy::SyncOnceCell,
|
||||
};
|
||||
|
||||
pub use foxtrot::{io, net, time};
|
||||
|
||||
pub mod sync {
|
||||
pub use jitterbug::{oneshot, Dropped as OneshotError, Receiver, Sender};
|
||||
}
|
||||
|
||||
pub mod task {
|
||||
pub use jitterbug::{JoinError, JoinHandle};
|
||||
use std::future::Future;
|
||||
|
||||
pub fn spawn<T: Send + 'static>(
|
||||
future: impl Future<Output = T> + Send + 'static,
|
||||
) -> JoinHandle<T> {
|
||||
super::Runtime::get_or_init().executor.spawn(future)
|
||||
}
|
||||
|
||||
pub fn spawn_blocking<T: Send + 'static>(
|
||||
callback: impl FnOnce() -> T + Send + 'static,
|
||||
) -> JoinHandle<T> {
|
||||
super::Runtime::get_or_init()
|
||||
.blocking
|
||||
.spawn(async move { (callback)() })
|
||||
}
|
||||
}
|
||||
|
||||
pub use task::{spawn, spawn_blocking};
|
||||
|
||||
pub fn block_on<T: Send + 'static>(
|
||||
future: impl Future<Output = T> + Send + 'static,
|
||||
) -> Result<T, jitterbug::JoinError> {
|
||||
foxtrot::block_on(Runtime::get_or_init().executor.run_with(future)).unwrap()
|
||||
}
|
||||
|
||||
static RUNTIME: SyncOnceCell<Runtime> = SyncOnceCell::new();
|
||||
|
||||
struct Runtime {
|
||||
executor: Executor,
|
||||
blocking: Executor,
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
fn get_or_init() -> &'static Self {
|
||||
RUNTIME.get_or_init(Self::new)
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
let executor = Executor::new();
|
||||
let blocking = Executor::new();
|
||||
|
||||
let base_threads = std::thread::available_parallelism()
|
||||
.map(usize::from)
|
||||
.unwrap_or(1);
|
||||
|
||||
let blocking_threads = base_threads * 5;
|
||||
|
||||
for _ in 0..base_threads {
|
||||
let executor = executor.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let _ = foxtrot::block_on(executor.into_runner());
|
||||
});
|
||||
}
|
||||
|
||||
for _ in 0..blocking_threads {
|
||||
let blocking = blocking.clone();
|
||||
|
||||
std::thread::spawn(move || blocking.block_on(pending::<()>()));
|
||||
}
|
||||
|
||||
Runtime { executor, blocking }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue