mirror of https://github.com/smol-rs/smol
Lots of changes
This commit is contained in:
parent
7966853f12
commit
db73031707
|
@ -1,2 +1,3 @@
|
|||
target/
|
||||
Cargo.lock
|
||||
socket
|
||||
|
|
|
@ -11,7 +11,7 @@ async-task = "1.3.1"
|
|||
crossbeam-deque = "0.7.3"
|
||||
crossbeam-queue = "0.2.1"
|
||||
crossbeam-utils = "0.7.2"
|
||||
futures = "0.3.4"
|
||||
futures = { version = "0.3.4", default-features = false, features = ["std"] }
|
||||
libc = "0.2.68"
|
||||
once_cell = "1.3.1"
|
||||
parking_lot = "0.10.0"
|
||||
|
@ -27,12 +27,19 @@ nix = "0.17.0"
|
|||
[target.'cfg(windows)'.dependencies]
|
||||
wepoll-binding = "1.1.0"
|
||||
|
||||
[target.'cfg(windows)'.dev-dependencies]
|
||||
uds_windows = "0.1.4"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
||||
timerfd = "1.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.27"
|
||||
async-h1 = "1.0.1"
|
||||
async-native-tls = "0.3.3"
|
||||
async-tungstenite = { version = "0.4.2", features = ["async-native-tls"] }
|
||||
base64 = "0.12.0"
|
||||
futures = "0.3.4"
|
||||
http = "0.2.1"
|
||||
http-types = "1.0.1"
|
||||
hyper = { version = "0.13.4", default-features = false, features = ["stream"] }
|
||||
|
|
|
@ -54,7 +54,7 @@ fn main() -> Result<()> {
|
|||
async_h1::accept(&http_addr, SharedIo::new(stream), serve).await
|
||||
})
|
||||
.unwrap()
|
||||
.forget();
|
||||
.detach();
|
||||
}
|
||||
res = https.accept().fuse() => {
|
||||
let (stream, _) = res?;
|
||||
|
@ -64,7 +64,7 @@ fn main() -> Result<()> {
|
|||
async_h1::accept(&https_addr, SharedIo::new(stream), serve).await
|
||||
})
|
||||
.unwrap()
|
||||
.forget();
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use piper::Receiver;
|
||||
use signal_hook::iterator::Signals;
|
||||
use smol::Task;
|
||||
|
||||
async fn ctrl_c() {
|
||||
static RECEIVER: Lazy<Receiver<i32>> = Lazy::new(|| {
|
||||
let signals = Signals::new(&[signal_hook::SIGINT]).unwrap();
|
||||
smol::iter(100, Box::leak(Box::new(signals)).forever())
|
||||
});
|
||||
RECEIVER.recv().await;
|
||||
}
|
||||
static CTRL_C: Lazy<Receiver<()>> = Lazy::new(|| {
|
||||
let (s, r) = piper::chan(100);
|
||||
Task::blocking(async move {
|
||||
for _ in Signals::new(&[signal_hook::SIGINT]).unwrap().forever() {
|
||||
s.send(()).await;
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
r
|
||||
});
|
||||
|
||||
fn main() {
|
||||
smol::run(async {
|
||||
println!("Waiting for Ctrl-C");
|
||||
ctrl_c().await;
|
||||
CTRL_C.recv().await;
|
||||
println!("Done!");
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
use futures::prelude::*;
|
||||
use smol::Task;
|
||||
|
||||
fn unordered<T: Send + 'static>(
|
||||
iter: impl IntoIterator<Item = impl Future<Output = T> + Send + 'static>,
|
||||
) -> piper::Receiver<T> {
|
||||
let v = iter.into_iter().collect::<Vec<_>>();
|
||||
let (s, r) = piper::chan(v.len());
|
||||
for f in v {
|
||||
let s = s.clone();
|
||||
Task::spawn(async move { s.send(f.await).await }).detach();
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn main() {
|
||||
smol::run(async {
|
||||
// TODO
|
||||
})
|
||||
}
|
|
@ -44,7 +44,7 @@ struct SmolExecutor;
|
|||
|
||||
impl<F: Future + Send + 'static> hyper::rt::Executor<F> for SmolExecutor {
|
||||
fn execute(&self, fut: F) {
|
||||
Task::spawn(async { drop(fut.await) }).forget();
|
||||
Task::spawn(async { drop(fut.await) }).detach();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,11 +126,13 @@ impl tokio::io::AsyncWrite for SmolStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
match &mut *self {
|
||||
SmolStream::Plain(s) => s.get_ref().shutdown(std::net::Shutdown::Write)?,
|
||||
SmolStream::Tls(_) => {}
|
||||
SmolStream::Plain(s) => {
|
||||
s.get_ref().shutdown(std::net::Shutdown::Write)?;
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
SmolStream::Tls(s) => Pin::new(s).poll_close(cx),
|
||||
}
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ struct SmolExecutor;
|
|||
|
||||
impl<F: Future + Send + 'static> hyper::rt::Executor<F> for SmolExecutor {
|
||||
fn execute(&self, fut: F) {
|
||||
Task::spawn(async { drop(fut.await) }).forget();
|
||||
Task::spawn(async { drop(fut.await) }).detach();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,12 +163,14 @@ impl tokio::io::AsyncWrite for SmolStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
match &mut *self {
|
||||
SmolStream::Plain(s) => s.get_ref().shutdown(std::net::Shutdown::Write)?,
|
||||
SmolStream::Tls(_) => {}
|
||||
SmolStream::Handshake(_) => {}
|
||||
SmolStream::Plain(s) => {
|
||||
s.get_ref().shutdown(std::net::Shutdown::Write)?;
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
SmolStream::Tls(s) => Pin::new(s).poll_close(cx),
|
||||
SmolStream::Handshake(_) => Poll::Ready(Ok(())),
|
||||
}
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#[cfg(target_os = "linux")]
|
||||
fn main() -> std::io::Result<()> {
|
||||
use std::io;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use smol::Async;
|
||||
use timerfd::{SetTimeFlags, TimerFd, TimerState};
|
||||
|
||||
/// Converts a `nix::Error` into `std::io::Error`.
|
||||
fn io_err(err: nix::Error) -> io::Error {
|
||||
match err {
|
||||
nix::Error::Sys(code) => code.into(),
|
||||
err => io::Error::new(io::ErrorKind::Other, Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn sleep(dur: Duration) -> io::Result<()> {
|
||||
// Create a timer.
|
||||
let mut timer = TimerFd::new()?;
|
||||
timer.set_state(TimerState::Oneshot(dur), SetTimeFlags::Default);
|
||||
|
||||
// When the timer fires, a 64-bit integer can be read from it.
|
||||
Async::new(timer)?
|
||||
.read_with(|timer| nix::unistd::read(timer.as_raw_fd(), &mut [0u8; 8]).map_err(io_err))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
smol::run(async {
|
||||
let start = Instant::now();
|
||||
println!("Sleeping...");
|
||||
sleep(Duration::from_secs(1)).await?;
|
||||
println!("Woke up after {:?}", start.elapsed());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn main() {
|
||||
println!("This example works only on Linux!");
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
//! TODO
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
// TODO: lazy reader from a process
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ fn main() -> io::Result<()> {
|
|||
let path = env::args().nth(1).expect("missing path argument");
|
||||
|
||||
smol::run(async move {
|
||||
let mut dir = smol::iter(10_000, smol::blocking!(fs::read_dir(path))?);
|
||||
let mut dir = smol::iter(smol::blocking!(fs::read_dir(path))?);
|
||||
|
||||
while let Some(res) = dir.next().await {
|
||||
println!("{}", res?.file_name().to_string_lossy());
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
//! Prints a file given as an argument to stdout.
|
||||
|
||||
use std::{env, fs, io};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::env;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let path = env::args().nth(1).expect("missing path argument");
|
||||
|
||||
smol::run(async {
|
||||
let contents = smol::blocking!(fs::read_to_string(path))?;
|
||||
println!("{}", contents);
|
||||
let file = smol::reader(File::open(path)?);
|
||||
let mut stdout = smol::writer(io::stdout());
|
||||
|
||||
futures::io::copy(file, &mut stdout).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,17 +9,18 @@
|
|||
// 2. openssl pkcs12 -export -out identity.pfx -inkey localhost/key.pem -in localhost/cert.pem
|
||||
|
||||
use std::fs;
|
||||
use std::net::{Shutdown, TcpListener, TcpStream};
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use async_native_tls::TlsAcceptor;
|
||||
use futures::prelude::*;
|
||||
use smol::{Async, Task, blocking};
|
||||
use smol::{blocking, Async, Task};
|
||||
|
||||
const RESPONSE: &[u8] = br#"
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/html
|
||||
Content-Length: 47
|
||||
|
||||
<!DOCTYPE html><html><body>Hello!</body></html>
|
||||
"#;
|
||||
|
@ -29,7 +30,6 @@ async fn serve(mut stream: Async<TcpStream>, tls: Option<TlsAcceptor>) -> Result
|
|||
None => {
|
||||
println!("Serving http://{}", stream.get_ref().local_addr()?);
|
||||
stream.write_all(RESPONSE).await?;
|
||||
stream.get_ref().shutdown(Shutdown::Both)?;
|
||||
}
|
||||
Some(tls) => {
|
||||
println!("Serving https://{}", stream.get_ref().local_addr()?);
|
||||
|
@ -57,11 +57,11 @@ fn main() -> Result<()> {
|
|||
futures::select! {
|
||||
res = http.accept().fuse() => {
|
||||
let (stream, _) = res?;
|
||||
Task::spawn(serve(stream, None)).unwrap().forget();
|
||||
Task::spawn(serve(stream, None)).unwrap().detach();
|
||||
}
|
||||
res = https.accept().fuse() => {
|
||||
let (stream, _) = res?;
|
||||
Task::spawn(serve(stream, Some(tls.clone()))).unwrap().forget();
|
||||
Task::spawn(serve(stream, Some(tls.clone()))).unwrap().detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
use futures::io;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
smol::run(async {
|
||||
let stdin = smol::reader(std::io::stdin());
|
||||
let mut stdout = smol::writer(std::io::stdout());
|
||||
|
||||
io::copy(stdin, &mut stdout).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
use std::process::{Command, Stdio};
|
||||
|
||||
use futures::io;
|
||||
use futures::prelude::*;
|
||||
use smol::Task;
|
||||
|
||||
fn stdin() -> impl AsyncRead + Unpin + 'static {
|
||||
let mut child = Command::new("cat")
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to execute command");
|
||||
let mut out = child.stdout.take().unwrap();
|
||||
|
||||
let (reader, mut writer) = piper::pipe(2); // TODO
|
||||
Task::blocking(async move {
|
||||
io::copy(io::AllowStdIo::new(out), &mut writer).await;
|
||||
})
|
||||
.forget();
|
||||
|
||||
// TODO todo!("return a wrapped Reader that calls child.kill() on drop");
|
||||
reader
|
||||
}
|
||||
|
||||
// TODO: just pipe stdin to stdout
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
smol::run(async {
|
||||
let mut stdin = io::BufReader::new(stdin());
|
||||
|
||||
let mut line = String::new();
|
||||
stdin.read_line(&mut line).await?;
|
||||
dbg!(line);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
use std::env;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use futures::io;
|
||||
use smol::Async;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let mut args = env::args().skip(1);
|
||||
let addr = args.next().expect("missing address argument");
|
||||
let port = args.next().expect("missing port argument");
|
||||
|
||||
smol::run(async {
|
||||
let mut input = smol::reader(5 * 1024 * 1024, std::io::stdin());
|
||||
let mut stream = Async::<TcpStream>::connect(format!("{}:{}", addr, port)).await?;
|
||||
|
||||
io::copy(&mut input, &mut stream).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
use std::net::TcpStream;
|
||||
|
||||
use futures::io;
|
||||
use futures::prelude::*;
|
||||
use smol::Async;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
smol::run(async {
|
||||
let stdin = smol::reader(std::io::stdin());
|
||||
let mut stdout = smol::writer(std::io::stdout());
|
||||
let stream = Async::<TcpStream>::connect("localhost:7000").await?;
|
||||
println!("Connected to {}", stream.get_ref().peer_addr()?);
|
||||
|
||||
future::try_join(
|
||||
io::copy(stdin, &mut &stream),
|
||||
io::copy(&stream, &mut stdout),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
|
@ -8,23 +8,23 @@
|
|||
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
|
||||
use futures::prelude::*;
|
||||
use futures::io;
|
||||
use smol::{Async, Task};
|
||||
|
||||
async fn echo(stream: Async<TcpStream>) -> io::Result<()> {
|
||||
println!("Copying");
|
||||
io::copy(&stream, &mut &stream).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
smol::run(async {
|
||||
let listener = Async::<TcpListener>::bind("127.0.0.1:8080")?;
|
||||
let listener = Async::<TcpListener>::bind("127.0.0.1:7000")?;
|
||||
println!("Listening on http://{}", listener.get_ref().local_addr()?);
|
||||
|
||||
loop {
|
||||
let (stream, _) = listener.accept().await?;
|
||||
Task::spawn(echo(stream)).unwrap().forget();
|
||||
Task::spawn(echo(stream)).unwrap().detach();
|
||||
}
|
||||
})
|
||||
}
|
|
@ -9,7 +9,8 @@ async fn sleep(dur: Duration) {
|
|||
fn main() {
|
||||
smol::run(async {
|
||||
let start = Instant::now();
|
||||
println!("Sleeping...");
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
dbg!(start.elapsed());
|
||||
println!("Woke up after {:?}", start.elapsed());
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ async fn timeout<T>(dur: Duration, f: impl Future<Output = T>) -> Result<T> {
|
|||
|
||||
fn main() -> Result<()> {
|
||||
smol::run(async {
|
||||
let mut stdin = BufReader::new(smol::reader(16 * 1024, std::io::stdin()));
|
||||
let mut stdin = BufReader::new(smol::reader(std::io::stdin()));
|
||||
let mut line = String::new();
|
||||
|
||||
let dur = Duration::from_secs(5);
|
||||
|
|
|
@ -45,14 +45,14 @@ fn main() -> Result<()> {
|
|||
let (stream, _) = res?;
|
||||
let stream = WsStream::Plain(async_tungstenite::accept_async(stream).await?);
|
||||
let ws_host = ws_host.clone();
|
||||
Task::spawn(serve(stream, ws_host)).unwrap().forget();
|
||||
Task::spawn(serve(stream, ws_host)).unwrap().detach();
|
||||
}
|
||||
res = wss.accept().fuse() => {
|
||||
let (stream, _) = res?;
|
||||
let stream = tls.accept(stream).await?;
|
||||
let stream = WsStream::Tls(async_tungstenite::accept_async(stream).await?);
|
||||
let wss_host = wss_host.clone();
|
||||
Task::spawn(serve(stream, wss_host)).unwrap().forget();
|
||||
Task::spawn(serve(stream, wss_host)).unwrap().detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#[cfg(windows)]
|
||||
fn main() -> std::io::Result<()> {
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use futures::io;
|
||||
use futures::prelude::*;
|
||||
use smol::{Async, Task};
|
||||
use uds_windows::{UnixListener, UnixStream};
|
||||
|
||||
async fn client(addr: PathBuf) -> io::Result<()> {
|
||||
let stream = Async::new(UnixStream::connect(addr)?)?;
|
||||
println!("Connected to {:?}", stream.get_ref().peer_addr()?);
|
||||
|
||||
let mut stdout = smol::writer(std::io::stdout());
|
||||
io::copy(&stream, &mut stdout).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("socket");
|
||||
let _ = fs::remove_file(&path);
|
||||
|
||||
smol::run(async {
|
||||
// Create a listener.
|
||||
let listener = Async::new(UnixListener::bind(&path)?)?;
|
||||
println!("Listening on {:?}", listener.get_ref().local_addr()?);
|
||||
|
||||
// Spawn a client task.
|
||||
let task = Task::spawn(client(path.clone()));
|
||||
|
||||
// Accept the client.
|
||||
let (stream, _) = listener.read_with(|l| l.accept()).await?;
|
||||
println!("Accepted a client");
|
||||
|
||||
// Send a message, drop the stream, and wait for the client.
|
||||
Async::new(stream)?.write_all(b"Hello!\n").await?;
|
||||
task.await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn main() {
|
||||
println!("This example works only on Windows!");
|
||||
}
|
|
@ -8,4 +8,4 @@ license = "MIT OR Apache-2.0"
|
|||
|
||||
[dependencies]
|
||||
crossbeam-utils = "0.7.0"
|
||||
futures = { version = "0.3.4", features = ["async-await"] }
|
||||
futures = { version = "0.3.4", default-features = false, features = ["std"] }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Asynchronous pipes, channels, and mutexes.
|
||||
|
||||
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
||||
|
||||
mod chan;
|
||||
|
@ -8,4 +10,3 @@ mod signal;
|
|||
pub use chan::{chan, Receiver, Sender};
|
||||
pub use mutex::{Mutex, MutexGuard};
|
||||
pub use pipe::{pipe, Reader, Writer};
|
||||
pub use signal::{Signal, SignalListener};
|
||||
|
|
|
@ -10,6 +10,7 @@ use std::task::{Context, Poll};
|
|||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use futures::task::AtomicWaker;
|
||||
|
||||
/// Creates a bounded single-producer single-consumer pipe.
|
||||
pub fn pipe(cap: usize) -> (Reader, Writer) {
|
||||
assert!(cap > 0, "capacity must be positive");
|
||||
|
||||
|
@ -44,12 +45,14 @@ pub fn pipe(cap: usize) -> (Reader, Writer) {
|
|||
|
||||
// NOTE: Reader and Writer are !Clone + !Sync
|
||||
|
||||
/// The reading side of a pipe.
|
||||
pub struct Reader {
|
||||
inner: Arc<Inner>,
|
||||
head: Cell<usize>,
|
||||
tail: Cell<usize>,
|
||||
}
|
||||
|
||||
/// The writing side of a pipe.
|
||||
pub struct Writer {
|
||||
inner: Arc<Inner>,
|
||||
head: Cell<usize>,
|
||||
|
|
|
@ -9,8 +9,6 @@ use std::ptr::NonNull;
|
|||
use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::task::{Context, Poll, Waker};
|
||||
use std::thread::{self, Thread};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// Set when there is at least one watcher that has already been notified.
|
||||
const NOTIFIED: usize = 1 << 0;
|
||||
|
@ -22,7 +20,7 @@ struct Inner {
|
|||
/// Holds three bits: `LOCKED`, `NOTIFIED`, and `NOTIFIABLE`.
|
||||
flags: AtomicUsize,
|
||||
|
||||
/// A linked list holding blocked tasks or threads.
|
||||
/// A linked list holding blocked tasks.
|
||||
list: Mutex<List>,
|
||||
}
|
||||
|
||||
|
@ -152,71 +150,6 @@ pub struct SignalListener {
|
|||
unsafe impl Send for SignalListener {}
|
||||
unsafe impl Sync for SignalListener {}
|
||||
|
||||
impl SignalListener {
|
||||
/// Blocks until a notification is received.
|
||||
pub fn wait(self) {
|
||||
self.wait_internal(None);
|
||||
}
|
||||
|
||||
/// Blocks until a notification is received or the timeout is reached.
|
||||
///
|
||||
/// Returns `true` if a notification was received.
|
||||
pub fn wait_timeout(self, timeout: Duration) -> bool {
|
||||
self.wait_internal(Some(timeout))
|
||||
}
|
||||
|
||||
/// Blocks the current thread with an optional timeout.
|
||||
///
|
||||
/// Returns `true` if a notification was received.
|
||||
fn wait_internal(mut self, mut timeout: Option<Duration>) -> bool {
|
||||
let entry = match self.entry.take() {
|
||||
None => unreachable!("cannot wait twice on a `SignalListener`"),
|
||||
Some(entry) => entry,
|
||||
};
|
||||
|
||||
{
|
||||
let mut inner = self.inner.lock();
|
||||
let e = unsafe { entry.as_ref() };
|
||||
|
||||
match e.state.replace(State::Notified) {
|
||||
State::Notified => return inner.remove(entry).is_notified(),
|
||||
_ => e.state.set(State::Waiting(thread::current())),
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match &mut timeout {
|
||||
None => thread::park(),
|
||||
Some(t) => {
|
||||
let now = Instant::now();
|
||||
thread::park_timeout(*t);
|
||||
|
||||
let elapsed = now.elapsed();
|
||||
if elapsed >= *t {
|
||||
*t = Duration::from_secs(0);
|
||||
} else {
|
||||
*t -= elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut inner = self.inner.lock();
|
||||
let e = unsafe { entry.as_ref() };
|
||||
|
||||
if let Some(t) = timeout {
|
||||
if t == Duration::from_secs(0) {
|
||||
return inner.remove(entry).is_notified();
|
||||
}
|
||||
}
|
||||
|
||||
match e.state.replace(State::Notified) {
|
||||
State::Notified => return inner.remove(entry).is_notified(),
|
||||
state => e.state.set(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for SignalListener {
|
||||
type Output = ();
|
||||
|
||||
|
@ -239,9 +172,6 @@ impl Future for SignalListener {
|
|||
}
|
||||
State::Created => state.set(State::Polling(cx.waker().clone())),
|
||||
State::Polling(w) => state.set(State::Polling(w)),
|
||||
State::Waiting(_) => {
|
||||
unreachable!("cannot poll and wait on `SignalListener` at the same time")
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
|
@ -312,16 +242,13 @@ enum State {
|
|||
|
||||
/// A task is polling it.
|
||||
Polling(Waker),
|
||||
|
||||
/// A thread is blocked on it.
|
||||
Waiting(Thread),
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn is_notified(&self) -> bool {
|
||||
match self {
|
||||
State::Notified => true,
|
||||
State::Created | State::Polling(_) | State::Waiting(_) => false,
|
||||
State::Created | State::Polling(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +345,6 @@ impl List {
|
|||
State::Notified => {}
|
||||
State::Created => {}
|
||||
State::Polling(w) => w.wake(),
|
||||
State::Waiting(t) => t.unpark(),
|
||||
}
|
||||
|
||||
if !is_notified {
|
||||
|
|
309
src/lib.rs
309
src/lib.rs
|
@ -1,6 +1,5 @@
|
|||
//! A very smol and fast async runtime.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
||||
|
||||
#[cfg(not(any(
|
||||
|
@ -33,10 +32,16 @@ use std::time::{Duration, Instant};
|
|||
|
||||
#[cfg(unix)]
|
||||
use std::{
|
||||
os::unix::net::{SocketAddr as UnixSocketAddr, UnixDatagram, UnixListener, UnixStream},
|
||||
os::unix::{
|
||||
io::{AsRawFd, RawFd},
|
||||
net::{SocketAddr as UnixSocketAddr, UnixDatagram, UnixListener, UnixStream},
|
||||
},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::{AsRawSocket, FromRawSocket, RawSocket};
|
||||
|
||||
use crossbeam_deque::{Injector, Steal, Stealer, Worker};
|
||||
use crossbeam_queue::SegQueue;
|
||||
use crossbeam_utils::sync::{Parker, ShardedLock};
|
||||
|
@ -53,7 +58,7 @@ use socket2::{Domain, Protocol, Socket, Type};
|
|||
type Runnable = async_task::Task<()>;
|
||||
|
||||
/// A spawned future.
|
||||
#[must_use = "tasks are canceled when dropped, use `.forget()` to run in the background"]
|
||||
#[must_use = "tasks are canceled when dropped, use `.detach()` to run in the background"]
|
||||
#[derive(Debug)]
|
||||
pub struct Task<T>(Option<async_task::JoinHandle<T, ()>>);
|
||||
|
||||
|
@ -84,8 +89,8 @@ impl<T: 'static> Task<T> {
|
|||
}
|
||||
|
||||
impl Task<()> {
|
||||
/// Moves the task into the background.
|
||||
pub fn forget(mut self) {
|
||||
/// Detaches the task to keep running in the background.
|
||||
pub fn detach(mut self) {
|
||||
self.0.take().unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +163,7 @@ pub fn run<T>(future: impl Future<Output = T>) -> T {
|
|||
EXECUTOR.processor(|proc| {
|
||||
let flag = Arc::new(
|
||||
IoFlag::create()
|
||||
.and_then(Async::nonblocking)
|
||||
.and_then(Async::new)
|
||||
.expect("cannot create waker flag"),
|
||||
);
|
||||
|
||||
|
@ -440,18 +445,23 @@ static THREAD_POOL: Lazy<ThreadPool> = Lazy::new(|| ThreadPool {
|
|||
cvar: Condvar::new(),
|
||||
});
|
||||
|
||||
/// A thread pool for blocking tasks.
|
||||
struct ThreadPool {
|
||||
state: Mutex<State>,
|
||||
cvar: Condvar,
|
||||
}
|
||||
|
||||
struct State {
|
||||
/// Number of sleeping threads in the pool.
|
||||
idle_count: usize,
|
||||
/// Total number of thread in the pool.
|
||||
thread_count: usize,
|
||||
/// Runnable blocking tasks.
|
||||
queue: VecDeque<Runnable>,
|
||||
}
|
||||
|
||||
impl ThreadPool {
|
||||
/// Spawns a blocking task onto the thread pool.
|
||||
fn spawn<T: Send + 'static>(
|
||||
&'static self,
|
||||
future: impl Future<Output = T> + Send + 'static,
|
||||
|
@ -461,36 +471,44 @@ impl ThreadPool {
|
|||
Task(Some(handle))
|
||||
}
|
||||
|
||||
/// Runs the main loop on the current thread.
|
||||
fn run(&'static self) {
|
||||
let mut state = self.state.lock();
|
||||
loop {
|
||||
state.idle_count -= 1;
|
||||
|
||||
// Run tasks in the queue.
|
||||
while let Some(runnable) = state.queue.pop_front() {
|
||||
self.spawn_more(state);
|
||||
let _ = catch_unwind(|| runnable.run());
|
||||
state = self.state.lock();
|
||||
}
|
||||
|
||||
// Put the thread to sleep until another task is scheduled.
|
||||
state.idle_count += 1;
|
||||
let timeout = Duration::from_millis(500);
|
||||
|
||||
if self.cvar.wait_for(&mut state, timeout).timed_out() {
|
||||
state.idle_count -= 1;
|
||||
state.thread_count -= 1;
|
||||
self.spawn_more(state);
|
||||
break;
|
||||
if state.queue.is_empty() {
|
||||
// If there are no tasks after a while, stop this thread.
|
||||
state.idle_count -= 1;
|
||||
state.thread_count -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedules a runnable task for execution.
|
||||
fn schedule(&'static self, runnable: Runnable) {
|
||||
let mut state = self.state.lock();
|
||||
state.queue.push_back(runnable);
|
||||
// Notify a sleeping thread and spawn more threads if needed.
|
||||
self.cvar.notify_one();
|
||||
self.spawn_more(state);
|
||||
}
|
||||
|
||||
/// Spawns more blocking threads if the pool is overloaded with work.
|
||||
fn spawn_more(&'static self, mut state: MutexGuard<'static, State>) {
|
||||
// If runnable tasks greatly outnumber idle threads and there aren't too many threads
|
||||
// already, then be aggressive: wake all idle threads and spawn one more thread.
|
||||
|
@ -511,42 +529,163 @@ macro_rules! blocking {
|
|||
};
|
||||
}
|
||||
|
||||
/// Spawns a blocking iterator onto a thread.
|
||||
pub fn iter<I>(cap: usize, iter: I) -> piper::Receiver<I::Item>
|
||||
where
|
||||
I: Iterator + Send + 'static,
|
||||
I::Item: Send,
|
||||
{
|
||||
let (s, r) = piper::chan(cap);
|
||||
Task::blocking(async move {
|
||||
for item in iter {
|
||||
s.send(item).await;
|
||||
/// Creates an iterator that runs on a thread.
|
||||
pub fn iter<T: Send + 'static>(
|
||||
iter: impl Iterator<Item = T> + Send + 'static,
|
||||
) -> impl Stream<Item = T> + Send + Unpin + 'static {
|
||||
enum State<T, I> {
|
||||
Idle(Option<I>),
|
||||
Busy(piper::Receiver<T>, Task<I>),
|
||||
}
|
||||
|
||||
impl<T, I> Unpin for State<T, I> {}
|
||||
|
||||
impl<T: Send + 'static, I: Iterator<Item = T> + Send + 'static> Stream for State<T, I> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||
match &mut *self {
|
||||
State::Idle(iter) => {
|
||||
let mut iter = iter.take().unwrap();
|
||||
let (sender, receiver) = piper::chan(8 * 1024);
|
||||
let task = Task::blocking(async move {
|
||||
for item in &mut iter {
|
||||
sender.send(item).await;
|
||||
}
|
||||
iter
|
||||
});
|
||||
*self = State::Busy(receiver, task);
|
||||
self.poll_next(cx)
|
||||
}
|
||||
State::Busy(receiver, task) => {
|
||||
let opt = futures::ready!(Pin::new(receiver).poll_next(cx));
|
||||
if opt.is_none() {
|
||||
// At the end of stream, retrieve the iterator back.
|
||||
let iter = futures::ready!(Pin::new(task).poll(cx));
|
||||
*self = State::Idle(Some(iter));
|
||||
}
|
||||
Poll::Ready(opt)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.forget();
|
||||
r
|
||||
}
|
||||
|
||||
State::Idle(Some(iter))
|
||||
}
|
||||
|
||||
/// Spawns a blocking reader onto a thread.
|
||||
pub fn reader<R>(cap: usize, reader: R) -> piper::Reader
|
||||
where
|
||||
R: Read + Send + 'static,
|
||||
{
|
||||
let io = AllowStdIo::new(reader);
|
||||
let (r, mut w) = piper::pipe(cap);
|
||||
Task::blocking(async move { drop(futures::io::copy(io, &mut w).await) }).forget();
|
||||
r
|
||||
/// Creates a reader that runs on a thread.
|
||||
pub fn reader(reader: impl Read + Send + 'static) -> impl AsyncRead + Send + Unpin + 'static {
|
||||
enum State<T> {
|
||||
Idle(Option<T>),
|
||||
Busy(piper::Reader, Task<(io::Result<()>, T)>),
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Send + Unpin + 'static> AsyncRead for State<T> {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
match &mut *self {
|
||||
State::Idle(io) => {
|
||||
let mut io = io.take().unwrap();
|
||||
let (reader, mut writer) = piper::pipe(8 * 1024 * 1024); // 8 MB
|
||||
let task = Task::blocking(async move {
|
||||
let res = futures::io::copy(&mut io, &mut writer).await;
|
||||
(res.map(drop), io)
|
||||
});
|
||||
*self = State::Busy(reader, task);
|
||||
self.poll_read(cx, buf)
|
||||
}
|
||||
State::Busy(reader, task) => {
|
||||
let n = futures::ready!(Pin::new(reader).poll_read(cx, buf))?;
|
||||
if n == 0 {
|
||||
// At the end of stream, retrieve the reader back.
|
||||
let (res, io) = futures::ready!(Pin::new(task).poll(cx));
|
||||
*self = State::Idle(Some(io));
|
||||
res?;
|
||||
}
|
||||
Poll::Ready(Ok(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let io = Box::pin(AllowStdIo::new(reader));
|
||||
State::Idle(Some(io))
|
||||
}
|
||||
|
||||
/// Spawns a blocking writer onto a thread.
|
||||
pub fn writer<W>(cap: usize, writer: W) -> piper::Writer
|
||||
where
|
||||
W: Write + Send + 'static,
|
||||
{
|
||||
let mut io = AllowStdIo::new(writer);
|
||||
let (r, w) = piper::pipe(cap);
|
||||
Task::blocking(async move { drop(futures::io::copy(r, &mut io).await) }).forget();
|
||||
w
|
||||
/// Creates a writer that runs on a thread.
|
||||
pub fn writer(writer: impl Write + Send + 'static) -> impl AsyncWrite + Send + Unpin + 'static {
|
||||
enum State<T> {
|
||||
Idle(Option<T>),
|
||||
Busy(Option<piper::Writer>, Task<(io::Result<()>, T)>),
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Send + Unpin + 'static> State<T> {
|
||||
fn start(&mut self) {
|
||||
if let State::Idle(io) = self {
|
||||
if let Some(mut io) = io.take() {
|
||||
let (reader, writer) = piper::pipe(8 * 1024 * 1024); // 8 MB
|
||||
let task = Task::blocking(async move {
|
||||
match futures::io::copy(reader, &mut io).await {
|
||||
Ok(_) => (io.flush().await, io),
|
||||
Err(err) => (Err(err), io),
|
||||
}
|
||||
});
|
||||
*self = State::Busy(Some(writer), task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Send + Unpin + 'static> AsyncWrite for State<T> {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
match &mut *self {
|
||||
State::Idle(None) => return Poll::Ready(Ok(0)),
|
||||
State::Idle(Some(_)) => self.start(),
|
||||
State::Busy(None, task) => {
|
||||
// The writing end of the pipe is closed, so await the task.
|
||||
let (res, io) = futures::ready!(Pin::new(task).poll(cx));
|
||||
*self = State::Idle(Some(io));
|
||||
res?;
|
||||
}
|
||||
State::Busy(Some(writer), _) => return Pin::new(writer).poll_write(cx, buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
match &mut *self {
|
||||
State::Idle(None) => return Poll::Ready(Ok(())),
|
||||
State::Idle(Some(_)) => self.start(),
|
||||
State::Busy(writer, task) => {
|
||||
// Close the writing end of the pipe and await the task.
|
||||
writer.take();
|
||||
let (res, io) = futures::ready!(Pin::new(task).poll(cx));
|
||||
*self = State::Idle(Some(io));
|
||||
return Poll::Ready(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
// Flush and then drop the I/O handle.
|
||||
futures::ready!(Pin::new(&mut *self).poll_flush(cx))?;
|
||||
*self = State::Idle(None);
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
let io = AllowStdIo::new(writer);
|
||||
State::Idle(Some(io))
|
||||
}
|
||||
|
||||
// ----- Reactor -----
|
||||
|
@ -555,10 +694,11 @@ static REACTOR: Lazy<Reactor> = Lazy::new(|| Reactor::create().expect("cannot cr
|
|||
|
||||
static INTERRUPT: Lazy<Async<IoFlag>> = Lazy::new(|| {
|
||||
IoFlag::create()
|
||||
.and_then(Async::nonblocking)
|
||||
.and_then(Async::new)
|
||||
.expect("cannot create interrupt flag")
|
||||
});
|
||||
|
||||
/// A source of I/O events.
|
||||
#[derive(Debug)]
|
||||
struct Source {
|
||||
raw: sys::Raw,
|
||||
|
@ -567,6 +707,7 @@ struct Source {
|
|||
writers: Mutex<Vec<Waker>>,
|
||||
}
|
||||
|
||||
/// The async I/O and timers driver.
|
||||
struct Reactor {
|
||||
sys: sys::Reactor,
|
||||
sources: Mutex<Slab<Arc<Source>>>,
|
||||
|
@ -589,18 +730,14 @@ impl Reactor {
|
|||
fn register(&self, raw: sys::Raw) -> io::Result<Arc<Source>> {
|
||||
let mut sources = self.sources.lock();
|
||||
let vacant = sources.vacant_entry();
|
||||
let index = vacant.key();
|
||||
self.sys.register(raw, index)?;
|
||||
|
||||
let source = Arc::new(Source {
|
||||
raw,
|
||||
index,
|
||||
index: vacant.key(),
|
||||
readers: Mutex::new(Vec::new()),
|
||||
writers: Mutex::new(Vec::new()),
|
||||
});
|
||||
vacant.insert(source.clone());
|
||||
|
||||
Ok(source)
|
||||
self.sys.register(raw, source.index)?;
|
||||
Ok(vacant.insert(source).clone())
|
||||
}
|
||||
|
||||
/// Deregisters an I/O source from the reactor.
|
||||
|
@ -816,9 +953,14 @@ pub struct Async<T> {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl<T: std::os::unix::io::AsRawFd> Async<T> {
|
||||
impl<T: AsRawFd> Async<T> {
|
||||
/// Converts a non-blocking I/O handle into an async I/O handle.
|
||||
pub fn nonblocking(inner: T) -> io::Result<Async<T>> {
|
||||
pub fn new(inner: T) -> io::Result<Async<T>> {
|
||||
nix::fcntl::fcntl(
|
||||
inner.as_raw_fd(),
|
||||
nix::fcntl::FcntlArg::F_SETFL(nix::fcntl::OFlag::O_NONBLOCK),
|
||||
)
|
||||
.unwrap(); // TODO unwrap and windows
|
||||
Ok(Async {
|
||||
source: REACTOR.register(sys::Raw::new(&inner))?,
|
||||
inner: Some(Box::new(inner)),
|
||||
|
@ -827,9 +969,12 @@ impl<T: std::os::unix::io::AsRawFd> Async<T> {
|
|||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl<T: std::os::windows::io::AsRawSocket> Async<T> {
|
||||
impl<T: AsRawSocket> Async<T> {
|
||||
/// Converts a non-blocking I/O handle into an async I/O handle.
|
||||
pub fn nonblocking(inner: T) -> io::Result<Async<T>> {
|
||||
pub fn new(inner: T) -> io::Result<Async<T>> {
|
||||
let socket = unsafe { Socket::from_raw_socket(inner.as_raw_socket()) };
|
||||
mem::ManuallyDrop::new(socket).set_nonblocking(true)?;
|
||||
|
||||
Ok(Async {
|
||||
source: REACTOR.register(sys::Raw::new(&inner))?,
|
||||
inner: Some(Box::new(inner)),
|
||||
|
@ -977,8 +1122,8 @@ impl<T: Write> AsyncWrite for Async<T> {
|
|||
fut.poll(cx)
|
||||
}
|
||||
|
||||
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
self.poll_flush(cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1002,24 +1147,22 @@ where
|
|||
fut.poll(cx)
|
||||
}
|
||||
|
||||
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
self.poll_flush(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Async<TcpListener> {
|
||||
/// Creates a listener bound to the specified address.
|
||||
pub fn bind<A: ToString>(addr: A) -> io::Result<Async<TcpListener>> {
|
||||
let listener = TcpListener::bind(addr.to_string().parse::<SocketAddr>().unwrap())?;
|
||||
listener.set_nonblocking(true)?;
|
||||
Ok(Async::nonblocking(listener)?)
|
||||
// TODO: unwrap
|
||||
TcpListener::bind(addr.to_string().parse::<SocketAddr>().unwrap()).and_then(Async::new)
|
||||
}
|
||||
|
||||
/// Accepts a new incoming connection.
|
||||
pub async fn accept(&self) -> io::Result<(Async<TcpStream>, SocketAddr)> {
|
||||
let (stream, addr) = self.read_with(|inner| inner.accept()).await?;
|
||||
stream.set_nonblocking(true)?;
|
||||
Ok((Async::nonblocking(stream)?, addr))
|
||||
Ok((Async::new(stream)?, addr))
|
||||
}
|
||||
|
||||
/// Returns a stream over incoming connections.
|
||||
|
@ -1053,7 +1196,7 @@ impl Async<TcpStream> {
|
|||
// Begin async connect and ignore the inevitable "not yet connected" error.
|
||||
socket.set_nonblocking(true)?;
|
||||
let _ = socket.connect(&addr.into());
|
||||
let stream = Async::nonblocking(socket.into_tcp_stream())?;
|
||||
let stream = Async::new(socket.into_tcp_stream())?;
|
||||
|
||||
// Wait for connect to complete.
|
||||
let wait_connect = |mut stream: &TcpStream| match stream.write(&[]) {
|
||||
|
@ -1077,9 +1220,8 @@ impl Async<TcpStream> {
|
|||
impl Async<UdpSocket> {
|
||||
/// Creates a socket bound to the specified address.
|
||||
pub fn bind<A: ToString>(addr: A) -> io::Result<Async<UdpSocket>> {
|
||||
let socket = UdpSocket::bind(addr.to_string().parse::<SocketAddr>().unwrap())?;
|
||||
socket.set_nonblocking(true)?;
|
||||
Ok(Async::nonblocking(socket)?)
|
||||
// TODO unwrap()
|
||||
UdpSocket::bind(addr.to_string().parse::<SocketAddr>().unwrap()).and_then(Async::new)
|
||||
}
|
||||
|
||||
/// Sends data to the specified address.
|
||||
|
@ -1118,16 +1260,13 @@ impl Async<UdpSocket> {
|
|||
impl Async<UnixListener> {
|
||||
/// Creates a listener bound to the specified path.
|
||||
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Async<UnixListener>> {
|
||||
let listener = UnixListener::bind(path)?;
|
||||
listener.set_nonblocking(true)?;
|
||||
Ok(Async::nonblocking(listener)?)
|
||||
UnixListener::bind(path).and_then(Async::new)
|
||||
}
|
||||
|
||||
/// Accepts a new incoming connection.
|
||||
pub async fn accept(&self) -> io::Result<(Async<UnixStream>, UnixSocketAddr)> {
|
||||
let (stream, addr) = self.read_with(|inner| inner.accept()).await?;
|
||||
stream.set_nonblocking(true)?;
|
||||
Ok((Async::nonblocking(stream)?, addr))
|
||||
Ok((Async::new(stream)?, addr))
|
||||
}
|
||||
|
||||
/// Returns a stream over incoming connections.
|
||||
|
@ -1145,17 +1284,13 @@ impl Async<UnixListener> {
|
|||
impl Async<UnixStream> {
|
||||
/// Connects to the specified path.
|
||||
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<Async<UnixStream>> {
|
||||
let stream = UnixStream::connect(path)?;
|
||||
stream.set_nonblocking(true)?;
|
||||
Ok(Async::nonblocking(stream)?)
|
||||
UnixStream::connect(path).and_then(Async::new)
|
||||
}
|
||||
|
||||
/// Creates an unnamed pair of connected streams.
|
||||
pub fn pair() -> io::Result<(Async<UnixStream>, Async<UnixStream>)> {
|
||||
let (stream1, stream2) = UnixStream::pair()?;
|
||||
stream1.set_nonblocking(true)?;
|
||||
stream2.set_nonblocking(true)?;
|
||||
Ok((Async::nonblocking(stream1)?, Async::nonblocking(stream2)?))
|
||||
Ok((Async::new(stream1)?, Async::new(stream2)?))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1163,24 +1298,18 @@ impl Async<UnixStream> {
|
|||
impl Async<UnixDatagram> {
|
||||
/// Creates a socket bound to the specified path.
|
||||
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Async<UnixDatagram>> {
|
||||
let socket = UnixDatagram::bind(path)?;
|
||||
socket.set_nonblocking(true)?;
|
||||
Ok(Async::nonblocking(socket)?)
|
||||
UnixDatagram::bind(path).and_then(Async::new)
|
||||
}
|
||||
|
||||
/// Creates a socket not bound to any address.
|
||||
pub fn unbound() -> io::Result<Async<UnixDatagram>> {
|
||||
let socket = UnixDatagram::unbound()?;
|
||||
socket.set_nonblocking(true)?;
|
||||
Ok(Async::nonblocking(socket)?)
|
||||
UnixDatagram::unbound().and_then(Async::new)
|
||||
}
|
||||
|
||||
/// Creates an unnamed pair of connected sockets.
|
||||
pub fn pair() -> io::Result<(Async<UnixDatagram>, Async<UnixDatagram>)> {
|
||||
let (socket1, socket2) = UnixDatagram::pair()?;
|
||||
socket1.set_nonblocking(true)?;
|
||||
socket2.set_nonblocking(true)?;
|
||||
Ok((Async::nonblocking(socket1)?, Async::nonblocking(socket2)?))
|
||||
Ok((Async::new(socket1)?, Async::new(socket2)?))
|
||||
}
|
||||
|
||||
/// Sends data to the specified address.
|
||||
|
@ -1300,15 +1429,15 @@ impl IoFlag {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl std::os::unix::io::AsRawFd for IoFlag {
|
||||
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
|
||||
impl AsRawFd for IoFlag {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.socket_wakeup.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl std::os::windows::io::AsRawSocket for IoFlag {
|
||||
fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
|
||||
impl AsRawSocket for IoFlag {
|
||||
fn as_raw_socket(&self) -> RawSocket {
|
||||
self.socket_wakeup.as_raw_socket()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue