mirror of
https://github.com/openharmony/commonlibrary_rust_ylong_runtime.git
synced 2026-06-30 21:57:57 -04:00
@@ -0,0 +1,6 @@
|
||||
edition = "2021"
|
||||
wrap_comments = true
|
||||
imports_granularity = "Module"
|
||||
group_imports = "StdExternalCrate"
|
||||
format_code_in_doc_comments = true
|
||||
normalize_comments = true
|
||||
@@ -13,8 +13,8 @@
|
||||
|
||||
//! build.rs file for ylong_ffrt
|
||||
|
||||
use std::fs;
|
||||
use std::{env, path::PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let library_name = "ffrt";
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::mutex::MutexGuard;
|
||||
use libc::{c_int, c_void, timespec};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ffi::c_long;
|
||||
use std::time::Duration;
|
||||
|
||||
use libc::{c_int, c_void, timespec};
|
||||
|
||||
use crate::mutex::MutexGuard;
|
||||
|
||||
#[repr(C)]
|
||||
struct FfrtCondvar {
|
||||
storage: [u8; 512],
|
||||
@@ -32,7 +34,8 @@ impl Condvar {
|
||||
pub fn new() -> Condvar {
|
||||
let mut inner = FfrtCondvar { storage: [0; 512] };
|
||||
unsafe {
|
||||
let _ = ffrt_cnd_init(&mut inner as _); // how to handle return value?
|
||||
// how to handle return value?
|
||||
let _ = ffrt_cnd_init(&mut inner as _);
|
||||
}
|
||||
Condvar {
|
||||
inner: UnsafeCell::new(inner),
|
||||
@@ -42,14 +45,16 @@ impl Condvar {
|
||||
/// Notifies all tasks that wait on this condvar.
|
||||
pub fn notify_all(&self) {
|
||||
unsafe {
|
||||
let _ = ffrt_cnd_broadcast(self.inner.get()); // ignore return result
|
||||
// ignore return result
|
||||
let _ = ffrt_cnd_broadcast(self.inner.get());
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies one task that waits on this condvar.
|
||||
pub fn notify_one(&self) {
|
||||
unsafe {
|
||||
let _ = ffrt_cnd_signal(self.inner.get()); // ignore return result
|
||||
// ignore return result
|
||||
let _ = ffrt_cnd_signal(self.inner.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ impl Config {
|
||||
pub fn new() -> Config {
|
||||
unsafe {
|
||||
let p = ffrt_config_create();
|
||||
ffrt_config_init(p); // should check return value
|
||||
// should check return value
|
||||
ffrt_config_init(p);
|
||||
Config(p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::Qos;
|
||||
use libc::c_void;
|
||||
|
||||
use super::Qos;
|
||||
|
||||
#[must_use]
|
||||
/// Qos Interval.
|
||||
pub struct QosInterval(*mut c_void);
|
||||
|
||||
@@ -25,16 +25,13 @@ mod thread;
|
||||
pub use condition_variable::*;
|
||||
pub use config::*;
|
||||
pub use deadline::*;
|
||||
pub use ffrt_set_wake_flag;
|
||||
pub use ffrt_submit_h_coroutine;
|
||||
pub use ffrt_task_get;
|
||||
use libc::{c_int, c_void};
|
||||
pub use mutex::*;
|
||||
pub use sleep::*;
|
||||
pub use sys_event::*;
|
||||
pub use task::*;
|
||||
pub use thread::*;
|
||||
|
||||
use libc::{c_int, c_void};
|
||||
pub use {ffrt_set_wake_flag, ffrt_submit_h_coroutine, ffrt_task_get};
|
||||
|
||||
#[repr(C)]
|
||||
/// Qos levels.
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use libc::c_int;
|
||||
|
||||
@@ -35,7 +33,8 @@ pub struct Mutex<T: ?Sized> {
|
||||
/// Mutexguard used for operating the value inside the mutex.
|
||||
pub struct MutexGuard<'a, T: ?Sized + 'a> {
|
||||
pub(crate) lock: &'a Mutex<T>,
|
||||
_phantom: PhantomData<Cell<()>>, // Not Send, Not Sync
|
||||
// Not Send, Not Sync
|
||||
_phantom: PhantomData<Cell<()>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@@ -104,7 +103,8 @@ impl<T> Mutex<T> {
|
||||
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = ffrt_mtx_unlock(self.lock.inner.get()); // ignore result
|
||||
// ignore result
|
||||
let _ = ffrt_mtx_unlock(self.lock.inner.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,8 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
|
||||
impl<T: ?Sized> Drop for Mutex<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = ffrt_mtx_destroy(self.inner.get()); // ignore result
|
||||
// ignore result
|
||||
let _ = ffrt_mtx_destroy(self.inner.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use libc::timespec;
|
||||
use std::ffi::{c_int, c_long};
|
||||
use std::time::Duration;
|
||||
|
||||
use libc::timespec;
|
||||
|
||||
/// Yields the current task.
|
||||
pub fn task_yield() {
|
||||
unsafe {
|
||||
|
||||
@@ -27,7 +27,8 @@ extern "C" {
|
||||
fn ffrt_sys_event_wait(event: FfrtSysEventHandleT, sec: i64) -> c_int;
|
||||
fn ffrt_sys_event_destroy(event: FfrtSysEventHandleT, func: DestroyFunc, arg: *mut c_void);
|
||||
|
||||
/// Registers the fd to ffrt's epoll. Callback will be called when io events arrived.
|
||||
/// Registers the fd to ffrt's epoll. Callback will be called when io events
|
||||
/// arrived.
|
||||
pub fn ffrt_poller_register(
|
||||
fd: c_int,
|
||||
events: c_uint,
|
||||
|
||||
+16
-8
@@ -11,10 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::*;
|
||||
use libc::{c_char, c_void};
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use libc::{c_char, c_void};
|
||||
|
||||
use super::*;
|
||||
|
||||
type FfrtHook = extern "C" fn(*mut c_void);
|
||||
|
||||
type FfrtExecHook = extern "C" fn(*mut c_void) -> FfrtRet;
|
||||
@@ -167,12 +169,18 @@ extern "C" {
|
||||
|
||||
/// Submits a task.
|
||||
pub fn ffrt_submit_h_coroutine(
|
||||
data: *mut c_void, // void* callable,
|
||||
fp: FfrtExecHook, // ffrt_function_t exec,
|
||||
destroy_fp: FfrtHook, // ffrt_function_t destroy,
|
||||
in_deps: *const FfrtDeps, //const ffrt_deps_t* in_deps,
|
||||
out_deps: *const FfrtDeps, //const ffrt_deps_t* out_deps,
|
||||
attr: *const FfrtTaskAttr, //const ffrt_task_attr_t* attr
|
||||
// void* callable
|
||||
data: *mut c_void,
|
||||
// ffrt_function_tdd exec
|
||||
fp: FfrtExecHook,
|
||||
// ffrt_function_t destroy
|
||||
destroy_fp: FfrtHook,
|
||||
// const ffrt_deps_t* out_deps,
|
||||
in_deps: *const FfrtDeps,
|
||||
// const ffrt_deps_t* out_deps,
|
||||
out_deps: *const FfrtDeps,
|
||||
// const ffrt_task_attr_t* att
|
||||
attr: *const FfrtTaskAttr,
|
||||
) -> RawTaskHandle;
|
||||
|
||||
// release handle
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::FfrtResult;
|
||||
use libc::{c_int, c_void};
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
use super::FfrtResult;
|
||||
|
||||
/// A handle for thread.
|
||||
pub struct ThreadHandle(FfrtThrd);
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! cargo build --example ylong_io_tcp_client --no-default-features --features="ylong_tcp"
|
||||
//! Uses with ylong_io_tcp_server, start ylong_io_tcp_server first, then start ylong_io_tcp_client
|
||||
//! cargo build --example ylong_io_tcp_client --no-default-features
|
||||
//! --features="ylong_tcp" Uses with ylong_io_tcp_server, start
|
||||
//! ylong_io_tcp_server first, then start ylong_io_tcp_client
|
||||
|
||||
use std::io::{Read, Write};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use ylong_io::TcpStream;
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -11,13 +11,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! cargo build --example ylong_io_tcp_server --no-default-features --features="ylong_tcp"
|
||||
//! Uses with ylong_io_tcp_server, start ylong_io_tcp_server first, then start ylong_io_tcp_client
|
||||
//! cargo build --example ylong_io_tcp_server --no-default-features
|
||||
//! --features="ylong_tcp" Uses with ylong_io_tcp_server, start
|
||||
//! ylong_io_tcp_server first, then start ylong_io_tcp_client
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::str::from_utf8;
|
||||
|
||||
use ylong_io::{EventTrait, Events, Interest, Poll, TcpListener, Token};
|
||||
|
||||
const SERVER: Token = Token(0);
|
||||
@@ -53,7 +55,7 @@ fn main() -> io::Result<()> {
|
||||
match connections.get_mut(&event.token()) {
|
||||
Some(connection) => {
|
||||
if event.is_writable() {
|
||||
//println!("server writable\n");
|
||||
// println!("server writable\n");
|
||||
match connection.write(b"Hello client_from writable") {
|
||||
Err(err) => {
|
||||
println!("1.Send failed {err}");
|
||||
|
||||
+1
-2
@@ -20,10 +20,9 @@ mod token;
|
||||
pub use token::Token;
|
||||
|
||||
pub mod sys;
|
||||
pub use sys::Selector;
|
||||
#[cfg(feature = "udp")]
|
||||
pub use sys::{ConnectedUdpSocket, UdpSocket};
|
||||
pub use sys::{Event, EventTrait, Events};
|
||||
pub use sys::{Event, EventTrait, Events, Selector};
|
||||
#[cfg(feature = "tcp")]
|
||||
pub use sys::{TcpListener, TcpStream};
|
||||
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{Events, Interest, Selector, Source, Token};
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{Events, Interest, Selector, Source, Token};
|
||||
|
||||
/// Registers and deregisters an io's fd
|
||||
pub struct Poll {
|
||||
selector: Selector,
|
||||
@@ -28,9 +29,11 @@ impl Poll {
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets all interested io events within a time limit and writes them into `event`.
|
||||
/// Gets all interested io events within a time limit and writes them into
|
||||
/// `event`.
|
||||
///
|
||||
/// If `timeout` is none, then it will block the current thread until an event arrives.
|
||||
/// If `timeout` is none, then it will block the current thread until an
|
||||
/// event arrives.
|
||||
pub fn poll(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
|
||||
self.selector.select(events, timeout)
|
||||
}
|
||||
@@ -51,7 +54,8 @@ impl Poll {
|
||||
source.reregister(&self.selector, token, interests)
|
||||
}
|
||||
|
||||
/// De-registers the I/O source's fd so the Poll will no longer monitor its io events.
|
||||
/// De-registers the I/O source's fd so the Poll will no longer monitor its
|
||||
/// io events.
|
||||
pub fn deregister<S>(&self, source: &mut S) -> io::Result<()>
|
||||
where
|
||||
S: Source + ?Sized,
|
||||
|
||||
@@ -11,17 +11,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{Interest, Selector, Token};
|
||||
use std::io;
|
||||
|
||||
use crate::{Interest, Selector, Token};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) type Fd = i32;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) type Fd = std::os::windows::io::RawSocket;
|
||||
|
||||
/// Source Trait that every connection requires async polling in [`crate::Poll`] needs to implement.
|
||||
/// [`crate::Poll`] will asynchronously poll out connections, and handle it.
|
||||
/// Source Trait that every connection requires async polling in [`crate::Poll`]
|
||||
/// needs to implement. [`crate::Poll`] will asynchronously poll out
|
||||
/// connections, and handle it.
|
||||
pub trait Source {
|
||||
/// Registers the connection into [`crate::Poll`]
|
||||
fn register(
|
||||
@@ -31,7 +33,8 @@ pub trait Source {
|
||||
interests: Interest,
|
||||
) -> io::Result<()>;
|
||||
|
||||
/// Reregisters the connection into [`crate::Poll`], this can change [`Interest`].
|
||||
/// Reregisters the connection into [`crate::Poll`], this can change
|
||||
/// [`Interest`].
|
||||
fn reregister(
|
||||
&mut self,
|
||||
selector: &Selector,
|
||||
|
||||
@@ -11,20 +11,23 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{Events, Interest, Token};
|
||||
use std::io;
|
||||
use std::os::raw::{c_int, c_uint};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{Events, Interest, Token};
|
||||
|
||||
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
|
||||
|
||||
/// An wrapper to block different OS polling system.
|
||||
/// Linux: epoll
|
||||
/// Windows: iocp
|
||||
pub struct Selector {
|
||||
id: usize, //selector id
|
||||
ep: i32, //epoll fd
|
||||
// selector id
|
||||
id: usize,
|
||||
// epoll fd
|
||||
ep: i32,
|
||||
}
|
||||
|
||||
impl Selector {
|
||||
@@ -48,7 +51,8 @@ impl Selector {
|
||||
|
||||
/// Waits for io events to come within a time limit.
|
||||
pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
|
||||
// Convert to milliseconds, if input time is none, it means the timeout is -1 and wait permanently.
|
||||
// Convert to milliseconds, if input time is none, it means the timeout is -1
|
||||
// and wait permanently.
|
||||
let timeout = timeout.map(|time| time.as_millis() as c_int).unwrap_or(-1);
|
||||
|
||||
events.clear();
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use libc::{sockaddr, socklen_t};
|
||||
use std::mem::size_of;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use libc::{sockaddr, socklen_t};
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) union SocketAddrLibC {
|
||||
v4: libc::sockaddr_in,
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::{TcpSocket, TcpStream};
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
use libc::{
|
||||
c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, SOCK_CLOEXEC, SOCK_NONBLOCK,
|
||||
};
|
||||
use std::io;
|
||||
use std::mem::{size_of, MaybeUninit};
|
||||
use std::net::{self, SocketAddr};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
|
||||
use libc::{
|
||||
c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, SOCK_CLOEXEC, SOCK_NONBLOCK,
|
||||
};
|
||||
|
||||
use super::{TcpSocket, TcpStream};
|
||||
use crate::source::Fd;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
|
||||
/// A socket server.
|
||||
pub struct TcpListener {
|
||||
@@ -28,7 +30,8 @@ pub struct TcpListener {
|
||||
}
|
||||
|
||||
impl TcpListener {
|
||||
/// Binds a new tcp Listener to the specific address to receive connection requests.
|
||||
/// Binds a new tcp Listener to the specific address to receive connection
|
||||
/// requests.
|
||||
///
|
||||
/// The socket will be set to `SO_REUSEADDR`.
|
||||
pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> {
|
||||
@@ -38,12 +41,14 @@ impl TcpListener {
|
||||
socket.listen(1024)
|
||||
}
|
||||
|
||||
/// Accepts connections and returns the `TcpStream` and the remote peer address.
|
||||
/// Accepts connections and returns the `TcpStream` and the remote peer
|
||||
/// address.
|
||||
///
|
||||
/// # Error
|
||||
/// This may return an `Err(e)` where `e.kind()` is `io::ErrorKind::WouldBlock`.
|
||||
/// This means a stream may be ready at a later point and one should wait for an event
|
||||
/// before calling `accept` again.
|
||||
/// This may return an `Err(e)` where `e.kind()` is
|
||||
/// `io::ErrorKind::WouldBlock`. This means a stream may be ready at a
|
||||
/// later point and one should wait for an event before calling `accept`
|
||||
/// again.
|
||||
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
|
||||
let mut addr: MaybeUninit<sockaddr_storage> = MaybeUninit::uninit();
|
||||
let mut length = size_of::<sockaddr_storage>() as socklen_t;
|
||||
|
||||
@@ -11,17 +11,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::super::socket_addr::socket_addr_trans;
|
||||
use super::{TcpListener, TcpStream};
|
||||
use libc::{
|
||||
c_int, c_void, socklen_t, AF_INET, AF_INET6, SOCK_CLOEXEC, SOCK_NONBLOCK, SOCK_STREAM,
|
||||
SOL_SOCKET, SO_REUSEADDR,
|
||||
};
|
||||
use std::io;
|
||||
use std::mem::{self, size_of};
|
||||
use std::net::{self, SocketAddr};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
|
||||
use libc::{
|
||||
c_int, c_void, socklen_t, AF_INET, AF_INET6, SOCK_CLOEXEC, SOCK_NONBLOCK, SOCK_STREAM,
|
||||
SOL_SOCKET, SO_REUSEADDR,
|
||||
};
|
||||
|
||||
use super::super::socket_addr::socket_addr_trans;
|
||||
use super::{TcpListener, TcpStream};
|
||||
|
||||
pub(crate) struct TcpSocket {
|
||||
socket: c_int,
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::TcpSocket;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
|
||||
use std::net::{self, Shutdown, SocketAddr};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use super::TcpSocket;
|
||||
use crate::source::Fd;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
|
||||
/// A non-blocking TCP Stream between a local socket and a remote socket.
|
||||
pub struct TcpStream {
|
||||
|
||||
@@ -11,13 +11,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::super::socket_addr::socket_addr_trans;
|
||||
use crate::UdpSocket;
|
||||
use libc::{c_int, AF_INET, AF_INET6, SOCK_CLOEXEC, SOCK_DGRAM, SOCK_NONBLOCK};
|
||||
use std::net::SocketAddr;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::{io, mem, net};
|
||||
|
||||
use libc::{c_int, AF_INET, AF_INET6, SOCK_CLOEXEC, SOCK_DGRAM, SOCK_NONBLOCK};
|
||||
|
||||
use super::super::socket_addr::socket_addr_trans;
|
||||
use crate::UdpSocket;
|
||||
|
||||
pub(crate) struct UdpSock {
|
||||
socket: c_int,
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::UdpSock;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
use crate::source::Fd;
|
||||
use std::fmt::Formatter;
|
||||
use std::net::SocketAddr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::{fmt, io, net};
|
||||
|
||||
use super::UdpSock;
|
||||
use crate::source::Fd;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
|
||||
/// UdpSocket. The bottom layer uses std::net::UdpSocket。
|
||||
/// UdpSocket supports bind\connect\send\recv\send_to\recv_from\broadcast.
|
||||
///
|
||||
@@ -26,6 +27,7 @@ use std::{fmt, io, net};
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -72,6 +74,7 @@ impl UdpSocket {
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -106,6 +109,7 @@ impl UdpSocket {
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -119,7 +123,8 @@ impl UdpSocket {
|
||||
self.inner.local_addr()
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the given address. On success, returns the number of bytes written.
|
||||
/// Sends data on the socket to the given address. On success, returns the
|
||||
/// number of bytes written.
|
||||
///
|
||||
/// # Return value
|
||||
/// The function returns:
|
||||
@@ -130,6 +135,7 @@ impl UdpSocket {
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -146,19 +152,23 @@ impl UdpSocket {
|
||||
inner.send_to(buf, target)
|
||||
}
|
||||
|
||||
/// Receives a single datagram message on the socket. On success, returns the number of bytes read and the origin.
|
||||
/// The function must be called with valid byte array buf of sufficient size to hold the message bytes.
|
||||
/// If a message is too long to fit in the supplied buffer, excess bytes may be discarded.
|
||||
/// Receives a single datagram message on the socket. On success, returns
|
||||
/// the number of bytes read and the origin. The function must be called
|
||||
/// with valid byte array buf of sufficient size to hold the message bytes.
|
||||
/// If a message is too long to fit in the supplied buffer, excess bytes may
|
||||
/// be discarded.
|
||||
///
|
||||
/// # Return value
|
||||
/// The function returns:
|
||||
/// * `Ok((n, addr))` n is the number of bytes received, addr is the address of sender.
|
||||
/// * `Ok((n, addr))` n is the number of bytes received, addr is the address
|
||||
/// of sender.
|
||||
/// * `Err(e)` if an error is encountered.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -176,13 +186,14 @@ impl UdpSocket {
|
||||
}
|
||||
|
||||
/// Connects the UDP socket setting the default destination for send()
|
||||
/// and limiting packets that are read via recv from the address specified in addr.
|
||||
/// return io::Error if errors happen.
|
||||
/// and limiting packets that are read via recv from the address specified
|
||||
/// in addr. return io::Error if errors happen.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -205,12 +216,14 @@ impl UdpSocket {
|
||||
}
|
||||
|
||||
/// Sets the value of the `SO_BROADCAST` option for this socket.
|
||||
/// When enabled, this socket is allowed to send packets to a broadcast address.
|
||||
/// When enabled, this socket is allowed to send packets to a broadcast
|
||||
/// address.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -233,6 +246,7 @@ impl UdpSocket {
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -269,6 +283,7 @@ impl ConnectedUdpSocket {
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -289,12 +304,14 @@ impl ConnectedUdpSocket {
|
||||
self.inner.local_addr()
|
||||
}
|
||||
|
||||
/// Returns the socket address of the remote peer this socket was connected to.
|
||||
/// Returns the socket address of the remote peer this socket was connected
|
||||
/// to.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -315,17 +332,20 @@ impl ConnectedUdpSocket {
|
||||
self.inner.peer_addr()
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the remote address that the socket is connected to.
|
||||
/// The connect method will connect this socket to a remote address.
|
||||
/// This method will fail if the socket is not connected.
|
||||
/// Sends data on the socket to the remote address that the socket is
|
||||
/// connected to. The connect method will connect this socket to a
|
||||
/// remote address. This method will fail if the socket is not
|
||||
/// connected.
|
||||
///
|
||||
/// # Return
|
||||
/// On success, the number of bytes sent is returned, otherwise, the encountered error is returned.
|
||||
/// On success, the number of bytes sent is returned, otherwise, the
|
||||
/// encountered error is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -347,11 +367,13 @@ impl ConnectedUdpSocket {
|
||||
inner.send(buf)
|
||||
}
|
||||
|
||||
/// Receives a single datagram message on the socket from the remote address to which it is connected. On success, returns the number of bytes read.
|
||||
/// The function must be called with valid byte array buf of sufficient size to hold the message bytes.
|
||||
/// If a message is too long to fit in the supplied buffer, excess bytes may be discarded.
|
||||
/// The connect method will connect this socket to a remote address.
|
||||
/// This method will fail if the socket is not connected.
|
||||
/// Receives a single datagram message on the socket from the remote address
|
||||
/// to which it is connected. On success, returns the number of bytes read.
|
||||
/// The function must be called with valid byte array buf of sufficient size
|
||||
/// to hold the message bytes. If a message is too long to fit in the
|
||||
/// supplied buffer, excess bytes may be discarded. The connect method
|
||||
/// will connect this socket to a remote address. This method will fail
|
||||
/// if the socket is not connected.
|
||||
///
|
||||
/// # Return value
|
||||
/// The function returns:
|
||||
@@ -362,6 +384,7 @@ impl ConnectedUdpSocket {
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// async fn io_func() -> io::Result<()> {
|
||||
@@ -399,11 +422,21 @@ impl fmt::Debug for ConnectedUdpSocket {
|
||||
}
|
||||
|
||||
impl Source for UdpSocket {
|
||||
fn register(&mut self, selector: &Selector, token: Token, interests: Interest) -> io::Result<()> {
|
||||
fn register(
|
||||
&mut self,
|
||||
selector: &Selector,
|
||||
token: Token,
|
||||
interests: Interest,
|
||||
) -> io::Result<()> {
|
||||
selector.register(self.as_raw_fd(), token, interests)
|
||||
}
|
||||
|
||||
fn reregister(&mut self, selector: &Selector, token: Token, interests: Interest) -> io::Result<()> {
|
||||
fn reregister(
|
||||
&mut self,
|
||||
selector: &Selector,
|
||||
token: Token,
|
||||
interests: Interest,
|
||||
) -> io::Result<()> {
|
||||
selector.reregister(self.as_raw_fd(), token, interests)
|
||||
}
|
||||
|
||||
@@ -417,11 +450,21 @@ impl Source for UdpSocket {
|
||||
}
|
||||
|
||||
impl Source for ConnectedUdpSocket {
|
||||
fn register(&mut self, selector: &Selector, token: Token, interests: Interest) -> io::Result<()> {
|
||||
fn register(
|
||||
&mut self,
|
||||
selector: &Selector,
|
||||
token: Token,
|
||||
interests: Interest,
|
||||
) -> io::Result<()> {
|
||||
selector.register(self.as_raw_fd(), token, interests)
|
||||
}
|
||||
|
||||
fn reregister(&mut self, selector: &Selector, token: Token, interests: Interest) -> io::Result<()> {
|
||||
fn reregister(
|
||||
&mut self,
|
||||
selector: &Selector,
|
||||
token: Token,
|
||||
interests: Interest,
|
||||
) -> io::Result<()> {
|
||||
selector.reregister(self.as_raw_fd(), token, interests)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{Interest, Selector, Token};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::FromRawFd;
|
||||
|
||||
/// In Linux, `eventfd` is used to implement asynchronous wake-up. It is a 64-bit counter.
|
||||
/// A fixed 8-byte (64-bit) unsigned integer is written to ensure wake-up reliability.
|
||||
use crate::{Interest, Selector, Token};
|
||||
|
||||
/// In Linux, `eventfd` is used to implement asynchronous wake-up. It is a
|
||||
/// 64-bit counter. A fixed 8-byte (64-bit) unsigned integer is written to
|
||||
/// ensure wake-up reliability.
|
||||
#[derive(Debug)]
|
||||
pub struct WakerInner {
|
||||
fd: File,
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::iocp::CompletionPort;
|
||||
use std::ffi::c_void;
|
||||
use std::fs::File;
|
||||
use std::mem::{size_of, zeroed};
|
||||
@@ -20,6 +19,7 @@ use std::ptr::null_mut;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{fmt, io};
|
||||
|
||||
use windows_sys::Win32::Foundation::{
|
||||
RtlNtStatusToDosError, HANDLE, INVALID_HANDLE_VALUE, NTSTATUS, STATUS_NOT_FOUND,
|
||||
STATUS_PENDING, STATUS_SUCCESS, UNICODE_STRING,
|
||||
@@ -33,6 +33,8 @@ use windows_sys::Win32::System::WindowsProgramming::{
|
||||
OBJECT_ATTRIBUTES,
|
||||
};
|
||||
|
||||
use crate::sys::windows::iocp::CompletionPort;
|
||||
|
||||
pub const POLL_RECEIVE: u32 = 0x0001;
|
||||
pub const POLL_RECEIVE_EXPEDITED: u32 = 0x0002;
|
||||
pub const POLL_SEND: u32 = 0x0004;
|
||||
@@ -82,7 +84,8 @@ extern "system" {
|
||||
}
|
||||
|
||||
/// Asynchronous file descriptor
|
||||
/// Implementing a single file handle to monitor multiple Io operations using the IO multiplexing model.
|
||||
/// Implementing a single file handle to monitor multiple Io operations using
|
||||
/// the IO multiplexing model.
|
||||
#[derive(Debug)]
|
||||
pub struct Afd {
|
||||
fd: File,
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::sys::windows::afd::{
|
||||
POLL_ABORT, POLL_ACCEPT, POLL_CONNECT_FAIL, POLL_DISCONNECT, POLL_RECEIVE, POLL_SEND,
|
||||
};
|
||||
use crate::sys::windows::iocp::CompletionStatus;
|
||||
use crate::{EventTrait, Token};
|
||||
use std::fmt;
|
||||
|
||||
/// An io event
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use std::os::windows::io::RawHandle;
|
||||
|
||||
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
|
||||
|
||||
/// Ensures that the handle can be closed correctly when it is not needed
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use windows_sys::Win32::System::WindowsProgramming::{IO_STATUS_BLOCK, IO_STATUS_BLOCK_0};
|
||||
|
||||
pub(crate) struct IoStatusBlock(IO_STATUS_BLOCK);
|
||||
|
||||
@@ -11,17 +11,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::Handle;
|
||||
use crate::sys::Overlapped;
|
||||
use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
|
||||
use std::time::Duration;
|
||||
use std::{cmp, io};
|
||||
|
||||
use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};
|
||||
use windows_sys::Win32::System::IO::{
|
||||
CreateIoCompletionPort, GetQueuedCompletionStatusEx, PostQueuedCompletionStatus, OVERLAPPED,
|
||||
OVERLAPPED_ENTRY,
|
||||
};
|
||||
|
||||
use super::Handle;
|
||||
use crate::sys::Overlapped;
|
||||
|
||||
/// IOCP's HANDLE.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CompletionPort {
|
||||
@@ -52,8 +54,8 @@ impl CompletionPort {
|
||||
)
|
||||
}
|
||||
|
||||
/// Gets the completed events in the IOCP, and can get multiple events at the same time.
|
||||
/// Return the set of completed events
|
||||
/// Gets the completed events in the IOCP, and can get multiple events at
|
||||
/// the same time. Return the set of completed events
|
||||
pub(crate) fn get_results<'a>(
|
||||
&self,
|
||||
list: &'a mut [CompletionStatus],
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::selector::{SelectorInner, SockState};
|
||||
use crate::{Interest, Selector, Token};
|
||||
use std::os::windows::io::RawSocket;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex, Once};
|
||||
use std::{io, net};
|
||||
|
||||
use crate::sys::windows::selector::{SelectorInner, SockState};
|
||||
use crate::{Interest, Selector, Token};
|
||||
|
||||
/// Initialise the network stack for Windows.
|
||||
pub(crate) fn init() {
|
||||
static INIT: Once = Once::new();
|
||||
@@ -89,8 +90,8 @@ impl NetState {
|
||||
}
|
||||
}
|
||||
|
||||
/// The IO operation does not really report an error when Err(WouldBlock) occurs.
|
||||
/// We need to re-register the current IO operation.
|
||||
/// The IO operation does not really report an error when Err(WouldBlock)
|
||||
/// occurs. We need to re-register the current IO operation.
|
||||
pub(crate) fn try_io<T, F, R>(&self, task: F, io: &T) -> io::Result<R>
|
||||
where
|
||||
F: FnOnce(&T) -> io::Result<R>,
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::Event;
|
||||
use std::fmt;
|
||||
|
||||
use windows_sys::Win32::System::IO::OVERLAPPED_ENTRY;
|
||||
|
||||
use crate::Event;
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) struct Overlapped {
|
||||
// TODO: use in pipe
|
||||
|
||||
@@ -11,15 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::afd;
|
||||
use crate::sys::windows::afd::{Afd, AfdGroup, AfdPollInfo};
|
||||
use crate::sys::windows::events::{
|
||||
Events, ERROR_FLAGS, READABLE_FLAGS, READ_CLOSED_FLAGS, WRITABLE_FLAGS, WRITE_CLOSED_FLAGS,
|
||||
};
|
||||
use crate::sys::windows::io_status_block::IoStatusBlock;
|
||||
use crate::sys::windows::iocp::{CompletionPort, CompletionStatus};
|
||||
use crate::sys::NetInner;
|
||||
use crate::{Event, Interest, Token};
|
||||
use std::collections::VecDeque;
|
||||
use std::ffi::c_void;
|
||||
use std::io;
|
||||
@@ -31,6 +22,7 @@ use std::ptr::null_mut;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use windows_sys::Win32::Foundation::{
|
||||
ERROR_INVALID_HANDLE, ERROR_IO_PENDING, HANDLE, STATUS_CANCELLED, WAIT_TIMEOUT,
|
||||
};
|
||||
@@ -40,6 +32,16 @@ use windows_sys::Win32::Networking::WinSock::{
|
||||
};
|
||||
use windows_sys::Win32::System::IO::OVERLAPPED;
|
||||
|
||||
use crate::sys::windows::afd;
|
||||
use crate::sys::windows::afd::{Afd, AfdGroup, AfdPollInfo};
|
||||
use crate::sys::windows::events::{
|
||||
Events, ERROR_FLAGS, READABLE_FLAGS, READ_CLOSED_FLAGS, WRITABLE_FLAGS, WRITE_CLOSED_FLAGS,
|
||||
};
|
||||
use crate::sys::windows::io_status_block::IoStatusBlock;
|
||||
use crate::sys::windows::iocp::{CompletionPort, CompletionStatus};
|
||||
use crate::sys::NetInner;
|
||||
use crate::{Event, Interest, Token};
|
||||
|
||||
/// An wrapper to block different OS polling system.
|
||||
/// Linux: epoll
|
||||
/// Windows: iocp
|
||||
@@ -149,7 +151,8 @@ impl SelectorInner {
|
||||
}
|
||||
}
|
||||
|
||||
/// Process completed operation and put them into events; regular AFD events are put back into VecDeque
|
||||
/// Process completed operation and put them into events; regular AFD events
|
||||
/// are put back into VecDeque
|
||||
unsafe fn feed_events(
|
||||
&self,
|
||||
events: &mut Vec<Event>,
|
||||
@@ -190,7 +193,8 @@ impl SelectorInner {
|
||||
epoll_event_count
|
||||
}
|
||||
|
||||
/// Updates each SockState in the Deque, started only when Poll::poll() is called externally
|
||||
/// Updates each SockState in the Deque, started only when Poll::poll() is
|
||||
/// called externally
|
||||
unsafe fn update_sockets_events(&self) -> io::Result<()> {
|
||||
let mut update_queue = self.update_queue.lock().unwrap();
|
||||
for sock in update_queue.iter_mut() {
|
||||
@@ -206,8 +210,9 @@ impl SelectorInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// No actual system call is made at register, it only starts at Poll::poll().
|
||||
/// Return Arc<NetInternal> and put it in the asynchronous IO structure
|
||||
/// No actual system call is made at register, it only starts at
|
||||
/// Poll::poll(). Return Arc<NetInternal> and put it in the asynchronous
|
||||
/// IO structure
|
||||
pub(crate) fn register(
|
||||
this: &Arc<Self>,
|
||||
raw_socket: RawSocket,
|
||||
@@ -311,8 +316,9 @@ impl Drop for SelectorInner {
|
||||
enum SockPollStatus {
|
||||
/// Initial Value.
|
||||
Idle,
|
||||
/// System function called when updating sockets_events, set from Idle to Pending. Update only when polling.
|
||||
/// Only the socket of Pending can be cancelled.
|
||||
/// System function called when updating sockets_events, set from Idle to
|
||||
/// Pending. Update only when polling. Only the socket of Pending can be
|
||||
/// cancelled.
|
||||
Pending,
|
||||
/// After calling the system api to cancel the sock, set it to Cancelled.
|
||||
Cancelled,
|
||||
@@ -331,7 +337,8 @@ pub struct SockState {
|
||||
user_token: u64,
|
||||
/// user Interest
|
||||
user_interests_flags: u32,
|
||||
/// When this socket is polled, save user_interests_flags in polling_interests_flags. Used for comparison during re-registration.
|
||||
/// When this socket is polled, save user_interests_flags in
|
||||
/// polling_interests_flags. Used for comparison during re-registration.
|
||||
polling_interests_flags: u32,
|
||||
/// Current Status. When this is Pending, System API calls must be made.
|
||||
poll_status: SockPollStatus,
|
||||
@@ -416,10 +423,12 @@ impl SockState {
|
||||
if (self.user_interests_flags & afd::ALL_EVENTS & !self.polling_interests_flags)
|
||||
== 0
|
||||
{
|
||||
// All the events the user is interested in are already being monitored by
|
||||
// the pending poll operation. It might spuriously complete because of an
|
||||
// event that we're no longer interested in; when that happens we'll submit
|
||||
// a new poll operation with the updated event mask.
|
||||
// All the events the user is interested in are already
|
||||
// being monitored by the pending poll
|
||||
// operation. It might spuriously complete because of an
|
||||
// event that we're no longer interested in; when that
|
||||
// happens we'll submit a new poll
|
||||
// operation with the updated event mask.
|
||||
} else {
|
||||
// A poll operation is already pending, but it's not monitoring for all the
|
||||
// events that the user is interested in. Therefore, cancel the pending
|
||||
@@ -438,7 +447,8 @@ impl SockState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns true if user_interests_flags is inconsistent with polling_interests_flags.
|
||||
/// Returns true if user_interests_flags is inconsistent with
|
||||
/// polling_interests_flags.
|
||||
fn set_event(&mut self, flags: u32, token_data: u64) -> bool {
|
||||
self.user_interests_flags = flags | afd::POLL_CONNECT_FAIL | afd::POLL_ABORT;
|
||||
self.user_token = token_data;
|
||||
@@ -452,7 +462,8 @@ impl SockState {
|
||||
self.polling_interests_flags = 0;
|
||||
|
||||
let mut afd_events = 0;
|
||||
// Uses the status info in IO_STATUS_BLOCK to determine the socket poll status. It is unsafe to use a pointer of IO_STATUS_BLOCK.
|
||||
// Uses the status info in IO_STATUS_BLOCK to determine the socket poll status.
|
||||
// It is unsafe to use a pointer of IO_STATUS_BLOCK.
|
||||
unsafe {
|
||||
if self.delete_pending {
|
||||
return None;
|
||||
@@ -462,7 +473,8 @@ impl SockState {
|
||||
// The overlapped request itself failed in an unexpected way.
|
||||
afd_events = afd::POLL_CONNECT_FAIL;
|
||||
} else if self.poll_info.number_of_handles < 1 {
|
||||
// This poll operation succeeded but didn't report any socket events.
|
||||
// This poll operation succeeded but didn't report any socket
|
||||
// events.
|
||||
} else if self.poll_info.handles[0].events & afd::POLL_LOCAL_CLOSE != 0 {
|
||||
// The poll operation reported that the socket was closed.
|
||||
self.start_drop();
|
||||
@@ -502,7 +514,8 @@ impl SockState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Only can cancel SockState of SockPollStatus::Pending, Set to SockPollStatus::Cancelled.
|
||||
/// Only can cancel SockState of SockPollStatus::Pending, Set to
|
||||
/// SockPollStatus::Cancelled.
|
||||
fn cancel(&mut self) -> io::Result<()> {
|
||||
// Checks poll_status again.
|
||||
if self.poll_status != SockPollStatus::Pending {
|
||||
@@ -513,7 +526,8 @@ impl SockState {
|
||||
self.afd.cancel(&mut *self.iosb)?;
|
||||
}
|
||||
|
||||
// Only here set SockPollStatus::Cancelled, SockStates has been system called to cancel
|
||||
// Only here set SockPollStatus::Cancelled, SockStates has been system called to
|
||||
// cancel
|
||||
self.poll_status = SockPollStatus::Cancelled;
|
||||
self.polling_interests_flags = 0;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
use std::mem;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use windows_sys::Win32::Networking::WinSock::{
|
||||
AF_INET, AF_INET6, IN6_ADDR, IN6_ADDR_0, IN_ADDR, IN_ADDR_0, SOCKADDR, SOCKADDR_IN,
|
||||
SOCKADDR_IN6, SOCKADDR_IN6_0,
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::tcp::TcpSocket;
|
||||
use crate::sys::NetState;
|
||||
use crate::{Interest, Selector, Source, TcpStream, Token};
|
||||
use crate::source::Fd;
|
||||
use std::fmt::Formatter;
|
||||
use std::net::SocketAddr;
|
||||
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
|
||||
use std::{fmt, io, net};
|
||||
|
||||
use crate::source::Fd;
|
||||
use crate::sys::windows::tcp::TcpSocket;
|
||||
use crate::sys::NetState;
|
||||
use crate::{Interest, Selector, Source, TcpStream, Token};
|
||||
|
||||
/// A TCP socket server, listening for connections.
|
||||
pub struct TcpListener {
|
||||
pub(crate) inner: net::TcpListener,
|
||||
@@ -28,7 +29,8 @@ pub struct TcpListener {
|
||||
}
|
||||
|
||||
impl TcpListener {
|
||||
/// Binds a new tcp Listener to the specific address to receive connection requests.
|
||||
/// Binds a new tcp Listener to the specific address to receive connection
|
||||
/// requests.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -55,7 +57,8 @@ impl TcpListener {
|
||||
}
|
||||
}
|
||||
|
||||
/// Accepts connections and returns the `TcpStream` and the remote peer address.
|
||||
/// Accepts connections and returns the `TcpStream` and the remote peer
|
||||
/// address.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -74,8 +77,14 @@ impl TcpListener {
|
||||
}
|
||||
|
||||
impl Source for TcpListener {
|
||||
fn register(&mut self, selector: &Selector, token: Token, interests: Interest) -> io::Result<()> {
|
||||
self.state.register(selector, token, interests, self.as_raw_socket())
|
||||
fn register(
|
||||
&mut self,
|
||||
selector: &Selector,
|
||||
token: Token,
|
||||
interests: Interest,
|
||||
) -> io::Result<()> {
|
||||
self.state
|
||||
.register(selector, token, interests, self.as_raw_socket())
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::net::init;
|
||||
use crate::sys::windows::socket_addr::socket_addr_trans;
|
||||
use std::net::SocketAddr;
|
||||
use std::os::windows::io::{AsRawSocket, FromRawSocket, RawSocket};
|
||||
use std::{io, mem, net};
|
||||
|
||||
use windows_sys::Win32::Networking::WinSock::{
|
||||
self, closesocket, ioctlsocket, socket, ADDRESS_FAMILY, AF_INET, AF_INET6, FIONBIO,
|
||||
INVALID_SOCKET, SOCKET, SOCKET_ERROR, SOCK_STREAM,
|
||||
};
|
||||
|
||||
use crate::sys::windows::net::init;
|
||||
use crate::sys::windows::socket_addr::socket_addr_trans;
|
||||
|
||||
pub(crate) struct TcpSocket {
|
||||
socket: SOCKET,
|
||||
}
|
||||
@@ -71,6 +73,7 @@ impl TcpSocket {
|
||||
/// System call to listen.
|
||||
pub(crate) fn listen(self, backlog: u32) -> io::Result<()> {
|
||||
use std::convert::TryInto;
|
||||
|
||||
use WinSock::listen;
|
||||
|
||||
let backlog = backlog.try_into().unwrap_or(i32::MAX);
|
||||
|
||||
@@ -11,16 +11,17 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::tcp::TcpSocket;
|
||||
use crate::sys::NetState;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
use crate::source::Fd;
|
||||
use std::fmt::Formatter;
|
||||
use std::io::{IoSlice, IoSliceMut, Read, Write};
|
||||
use std::net::{Shutdown, SocketAddr};
|
||||
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
|
||||
use std::{fmt, io, net};
|
||||
|
||||
use crate::source::Fd;
|
||||
use crate::sys::windows::tcp::TcpSocket;
|
||||
use crate::sys::NetState;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
|
||||
/// A non-blocking TCP Stream between a local socket and a remote socket.
|
||||
pub struct TcpStream {
|
||||
/// Raw TCP socket
|
||||
@@ -68,13 +69,15 @@ impl TcpStream {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::{IpAddr, Ipv4Addr};
|
||||
///
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// assert_eq!(stream.local_addr().unwrap().ip(),
|
||||
/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// assert_eq!(
|
||||
/// stream.local_addr().unwrap().ip(),
|
||||
/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.inner.local_addr()
|
||||
@@ -86,13 +89,15 @@ impl TcpStream {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
///
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// assert_eq!(stream.peer_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234)));
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// assert_eq!(
|
||||
/// stream.peer_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.inner.peer_addr()
|
||||
@@ -103,13 +108,15 @@ impl TcpStream {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::{Shutdown};
|
||||
/// use std::net::Shutdown;
|
||||
///
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// stream.shutdown(Shutdown::Both).expect("shutdown call failed");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// stream
|
||||
/// .shutdown(Shutdown::Both)
|
||||
/// .expect("shutdown call failed");
|
||||
/// ```
|
||||
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
||||
self.inner.shutdown(how)
|
||||
@@ -123,8 +130,7 @@ impl TcpStream {
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// stream.set_nodelay(true).expect("set_nodelay call failed");
|
||||
/// ```
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
@@ -139,8 +145,7 @@ impl TcpStream {
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// stream.set_nodelay(true).expect("set_nodelay call failed");
|
||||
/// assert_eq!(stream.nodelay().unwrap_or(false), true);
|
||||
/// ```
|
||||
@@ -156,8 +161,7 @@ impl TcpStream {
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// stream.set_ttl(100).expect("set_ttl call failed");
|
||||
/// ```
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
@@ -172,8 +176,7 @@ impl TcpStream {
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// stream.set_ttl(100).expect("set_ttl call failed");
|
||||
/// assert_eq!(stream.ttl().unwrap_or(0), 100);
|
||||
/// ```
|
||||
@@ -189,8 +192,7 @@ impl TcpStream {
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// stream.take_error().expect("No error was expected...");
|
||||
/// ```
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
@@ -209,8 +211,7 @@ impl TcpStream {
|
||||
/// use ylong_io::TcpStream;
|
||||
///
|
||||
/// let addr = "127.0.0.1:1234".parse().unwrap();
|
||||
/// let stream = TcpStream::connect(addr)
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// let stream = TcpStream::connect(addr).expect("Couldn't connect to the server...");
|
||||
/// let mut buf = [0; 10];
|
||||
/// let len = stream.peek(&mut buf).expect("peek failed");
|
||||
/// ```
|
||||
|
||||
@@ -11,17 +11,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::net::init;
|
||||
use crate::sys::windows::socket_addr::socket_addr_trans;
|
||||
use std::net::SocketAddr;
|
||||
use std::os::windows::io::{FromRawSocket, RawSocket};
|
||||
use std::os::windows::raw;
|
||||
use std::{io, mem, net};
|
||||
|
||||
use windows_sys::Win32::Networking::WinSock::{
|
||||
bind as win_bind, closesocket, ioctlsocket, socket, ADDRESS_FAMILY, AF_INET, AF_INET6, FIONBIO,
|
||||
INVALID_SOCKET, SOCKET, SOCKET_ERROR, SOCK_DGRAM,
|
||||
};
|
||||
|
||||
use crate::sys::windows::net::init;
|
||||
use crate::sys::windows::socket_addr::socket_addr_trans;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UdpSock {
|
||||
socket: SOCKET,
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::udp::UdpSock;
|
||||
use crate::sys::NetState;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
use crate::source::Fd;
|
||||
use std::fmt::Formatter;
|
||||
use std::net::SocketAddr;
|
||||
use std::os::windows::io::AsRawSocket;
|
||||
use std::{fmt, io, net};
|
||||
|
||||
use crate::source::Fd;
|
||||
use crate::sys::windows::udp::UdpSock;
|
||||
use crate::sys::NetState;
|
||||
use crate::{Interest, Selector, Source, Token};
|
||||
|
||||
/// A UDP socket.
|
||||
pub struct UdpSocket {
|
||||
pub(crate) inner: net::UdpSocket,
|
||||
@@ -54,7 +55,9 @@ impl UdpSocket {
|
||||
/// let receiver_addr = "127.0.0.1:8082".parse().unwrap();
|
||||
///
|
||||
/// let sender = UdpSocket::bind(sender_addr).expect("Bind Socket Failed!");
|
||||
/// let connected_sender = sender.connect(receiver_addr).expect("Connect Socket Failed!");
|
||||
/// let connected_sender = sender
|
||||
/// .connect(receiver_addr)
|
||||
/// .expect("Connect Socket Failed!");
|
||||
/// ```
|
||||
pub fn connect(self, addr: SocketAddr) -> io::Result<ConnectedUdpSocket> {
|
||||
let socket = ConnectedUdpSocket::from_std(self);
|
||||
@@ -76,18 +79,22 @@ impl UdpSocket {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// let sender_addr = "127.0.0.1:8081".parse().unwrap();
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("Bind Socket Failed!");
|
||||
/// assert_eq!(socket.local_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8081)));
|
||||
/// assert_eq!(
|
||||
/// socket.local_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8081))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.inner.local_addr()
|
||||
}
|
||||
|
||||
/// Sends data on the socket to the given address. On success, returns the number of bytes written.
|
||||
/// Sends data on the socket to the given address. On success, returns the
|
||||
/// number of bytes written.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -98,14 +105,17 @@ impl UdpSocket {
|
||||
/// let receiver_addr = "127.0.0.1:8082".parse().unwrap();
|
||||
///
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("Bind Socket Failed!");
|
||||
/// socket.send_to(&[0; 10], receiver_addr).expect("Send Socket Failed!");
|
||||
/// socket
|
||||
/// .send_to(&[0; 10], receiver_addr)
|
||||
/// .expect("Send Socket Failed!");
|
||||
/// ```
|
||||
pub fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
|
||||
self.state
|
||||
.try_io(|inner| inner.send_to(buf, target), &self.inner)
|
||||
}
|
||||
|
||||
/// Receives a single datagram message on the socket. On success, returns the number of bytes read and the origin.
|
||||
/// Receives a single datagram message on the socket. On success, returns
|
||||
/// the number of bytes read and the origin.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -116,8 +126,7 @@ impl UdpSocket {
|
||||
///
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("Bind Socket Failed!");
|
||||
/// let mut buf = [0; 10];
|
||||
/// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf)
|
||||
/// .expect("Didn't receive data");
|
||||
/// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf).expect("Didn't receive data");
|
||||
/// let filled_buf = &mut buf[..number_of_bytes];
|
||||
/// ```
|
||||
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
@@ -134,7 +143,9 @@ impl UdpSocket {
|
||||
/// let sender_addr = "127.0.0.1:8081".parse().unwrap();
|
||||
///
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("couldn't bind to address");
|
||||
/// socket.set_broadcast(false).expect("set_broadcast call failed");
|
||||
/// socket
|
||||
/// .set_broadcast(false)
|
||||
/// .expect("set_broadcast call failed");
|
||||
/// ```
|
||||
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
|
||||
self.inner.set_broadcast(on)
|
||||
@@ -150,7 +161,9 @@ impl UdpSocket {
|
||||
/// let sender_addr = "127.0.0.1:8081".parse().unwrap();
|
||||
///
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("couldn't bind to address");
|
||||
/// socket.set_broadcast(false).expect("set_broadcast call failed");
|
||||
/// socket
|
||||
/// .set_broadcast(false)
|
||||
/// .expect("set_broadcast call failed");
|
||||
/// assert_eq!(socket.broadcast().unwrap(), false);
|
||||
/// ```
|
||||
pub fn broadcast(&self) -> io::Result<bool> {
|
||||
@@ -180,37 +193,48 @@ impl ConnectedUdpSocket {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// let sender_addr = "127.0.0.1:8081".parse().unwrap();
|
||||
/// let receiver_addr = "127.0.0.1:8082".parse().unwrap();
|
||||
///
|
||||
/// let sender = UdpSocket::bind(sender_addr).expect("Bind Socket Failed!");
|
||||
/// let connected_sender = sender.connect(receiver_addr).expect("Connect Socket Failed!");
|
||||
/// let connected_sender = sender
|
||||
/// .connect(receiver_addr)
|
||||
/// .expect("Connect Socket Failed!");
|
||||
///
|
||||
/// assert_eq!(connected_sender.local_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8081)));
|
||||
/// assert_eq!(
|
||||
/// connected_sender.local_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8081))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.inner.local_addr()
|
||||
}
|
||||
|
||||
/// Returns the socket address of the remote peer to which the socket is connected.
|
||||
/// Returns the socket address of the remote peer to which the socket is
|
||||
/// connected.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
///
|
||||
/// use ylong_io::UdpSocket;
|
||||
///
|
||||
/// let sender_addr = "127.0.0.1:8081".parse().unwrap();
|
||||
/// let receiver_addr = "127.0.0.1:8082".parse().unwrap();
|
||||
///
|
||||
/// let sender = UdpSocket::bind(sender_addr).expect("Bind Socket Failed!");
|
||||
/// let connected_sender = sender.connect(receiver_addr).expect("Connect Socket Failed!");
|
||||
/// let connected_sender = sender
|
||||
/// .connect(receiver_addr)
|
||||
/// .expect("Connect Socket Failed!");
|
||||
///
|
||||
/// assert_eq!(connected_sender.peer_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8082)));
|
||||
/// assert_eq!(
|
||||
/// connected_sender.peer_addr().unwrap(),
|
||||
/// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8082))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.inner.peer_addr()
|
||||
@@ -227,14 +251,19 @@ impl ConnectedUdpSocket {
|
||||
/// let receiver_addr = "127.0.0.1:8082".parse().unwrap();
|
||||
///
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("couldn't bind to address");
|
||||
/// let connected_sender = socket.connect(receiver_addr).expect("connect function failed");
|
||||
/// connected_sender.send(&[0, 1, 2]).expect("couldn't send message");
|
||||
/// let connected_sender = socket
|
||||
/// .connect(receiver_addr)
|
||||
/// .expect("connect function failed");
|
||||
/// connected_sender
|
||||
/// .send(&[0, 1, 2])
|
||||
/// .expect("couldn't send message");
|
||||
/// ```
|
||||
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.state.try_io(|inner| inner.send(buf), &self.inner)
|
||||
}
|
||||
|
||||
/// Receives a single datagram message on the socket from the remote address to which it is connected. On success, returns the number of bytes read.
|
||||
/// Receives a single datagram message on the socket from the remote address
|
||||
/// to which it is connected. On success, returns the number of bytes read.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -245,7 +274,9 @@ impl ConnectedUdpSocket {
|
||||
/// let receiver_addr = "127.0.0.1:8082".parse().unwrap();
|
||||
///
|
||||
/// let socket = UdpSocket::bind(sender_addr).expect("couldn't bind to address");
|
||||
/// let connected_sender = socket.connect(receiver_addr).expect("connect function failed");
|
||||
/// let connected_sender = socket
|
||||
/// .connect(receiver_addr)
|
||||
/// .expect("connect function failed");
|
||||
/// let mut buf = [0; 10];
|
||||
/// match connected_sender.recv(&mut buf) {
|
||||
/// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::sys::windows::iocp::CompletionPort;
|
||||
use crate::{Event, Selector, Token};
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::sys::windows::iocp::CompletionPort;
|
||||
use crate::{Event, Selector, Token};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WakerInner {
|
||||
token: Token,
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::io;
|
||||
|
||||
use crate::sys::WakerInner;
|
||||
use crate::{Poll, Token};
|
||||
use std::io;
|
||||
|
||||
/// Waker allows cross-thread waking of Poll.
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -13,16 +13,13 @@
|
||||
|
||||
use ylong_io::UdpSocket;
|
||||
|
||||
/// SDV test for `send()` and `recv()`.
|
||||
///
|
||||
/// # Title
|
||||
/// test_send_recv
|
||||
/// SDV test cases for `send()` and `recv()`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create UdpSocket and connect to the remote address.
|
||||
/// 2.Sender sends message first.
|
||||
/// 3.Receiver receives message.
|
||||
/// 4.Check if the test results are correct.
|
||||
/// 1. Create UdpSocket and connect to the remote address.
|
||||
/// 2. Sender sends message first.
|
||||
/// 3. Receiver receives message.
|
||||
/// 4. Check if the test results are correct.
|
||||
#[test]
|
||||
fn test_send_recv() {
|
||||
let sender_addr = "127.0.0.1:8081".parse().unwrap();
|
||||
@@ -70,16 +67,13 @@ fn test_send_recv() {
|
||||
assert_eq!(&recv_buf[..len], b"Hello");
|
||||
}
|
||||
|
||||
/// SDV test for `send_to()` and `recv_from()`.
|
||||
///
|
||||
/// # Title
|
||||
/// test_send_to_recv_from
|
||||
/// SDV test cases for `send_to()` and `recv_from()`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create UdpSocket.
|
||||
/// 2.Sender sends message to the specified address.
|
||||
/// 3.Receiver receives message and return the address the message from.
|
||||
/// 4.Check if the test results are correct.
|
||||
/// 1. Create UdpSocket.
|
||||
/// 2. Sender sends message to the specified address.
|
||||
/// 3. Receiver receives message and return the address the message from.
|
||||
/// 4. Check if the test results are correct.
|
||||
#[test]
|
||||
fn test_send_to_recv_from() {
|
||||
let sender_addr = "127.0.0.1:8085".parse().unwrap();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::time::Instant;
|
||||
|
||||
use ylong_runtime::builder::RuntimeBuilder;
|
||||
use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use ylong_runtime::net::{TcpListener, TcpStream};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
use std::io;
|
||||
use std::time::Instant;
|
||||
|
||||
use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use ylong_runtime::net::TcpStream;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
use std::io;
|
||||
use std::time::Instant;
|
||||
|
||||
use ylong_runtime::builder::RuntimeBuilder;
|
||||
use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use ylong_runtime::net::TcpListener;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use ylong_runtime::sync::Mutex;
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use ylong_runtime::sync::rwlock::RwLock;
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarks for memory usage, computed by difference between virtual rss printed.
|
||||
//! Benchmarks for memory usage, computed by difference between virtual rss
|
||||
//! printed.
|
||||
#[cfg(unix)]
|
||||
fn get_memory_info() {
|
||||
use std::process;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarks for task memory usage, computed by difference between virtual rss printed.
|
||||
//! Benchmarks for task memory usage, computed by difference between virtual rss
|
||||
//! printed.
|
||||
use std::thread::{sleep, spawn};
|
||||
use std::time::Duration;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
|
||||
use tokio::io::{AsyncReadExt as tokioAsyncReadExt, AsyncWriteExt as tokioAsyncWriteExt};
|
||||
use tokio::net::{TcpListener as tokioTcpListener, TcpStream as tokioTcpStream};
|
||||
use ylong_runtime::builder::RuntimeBuilder;
|
||||
|
||||
@@ -20,15 +20,17 @@ pub mod task_helpers;
|
||||
#[cfg(test)]
|
||||
mod sync_benchmarks {
|
||||
extern crate test;
|
||||
use crate::task_helpers::*;
|
||||
#[cfg(unix)]
|
||||
use std::fs::File;
|
||||
use std::hint::black_box;
|
||||
#[cfg(unix)]
|
||||
use std::io::prelude::*;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
use crate::task_helpers::*;
|
||||
|
||||
#[bench]
|
||||
fn single_thread_run_1000_fibbo(b: &mut Bencher) {
|
||||
b.iter(black_box(|| {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#![allow(dead_code)]
|
||||
use std::hint::black_box;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
#[cfg(feature = "multi_instance_runtime")]
|
||||
use ylong_runtime::builder::RuntimeBuilder;
|
||||
|
||||
@@ -103,14 +103,14 @@ macro_rules! async_write {
|
||||
#[cfg(test)]
|
||||
mod ylong_async_file {
|
||||
extern crate test;
|
||||
use crate::task_helpers::*;
|
||||
use test::Bencher;
|
||||
|
||||
use std::hint::black_box;
|
||||
|
||||
use test::Bencher;
|
||||
use ylong_runtime::fs::File;
|
||||
use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
use crate::task_helpers::*;
|
||||
|
||||
async_read!(ylong_runtime);
|
||||
async_write!(ylong_runtime);
|
||||
async_read_by_chars!(ylong_runtime);
|
||||
@@ -122,16 +122,18 @@ mod tokio_async_file {
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
extern crate test;
|
||||
use std::hint::black_box;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
use crate::task_helpers::*;
|
||||
use std::hint::black_box;
|
||||
|
||||
async_read!(tokio_runtime);
|
||||
async_write!(tokio_runtime);
|
||||
|
||||
// For codec benchmarks, tokio has `async_read_codec` in `fs.rs`. That's the correct
|
||||
// ways to use tokio's codec features. However, here, use the same benchmark to apply
|
||||
// the same method to test ylong, tokio, swift, and avoid new packages imported.
|
||||
// For codec benchmarks, tokio has `async_read_codec` in `fs.rs`. That's the
|
||||
// correct ways to use tokio's codec features. However, here, use the same
|
||||
// benchmark to apply the same method to test ylong, tokio, swift, and avoid
|
||||
// new packages imported.
|
||||
async_read_by_chars!(tokio_runtime);
|
||||
}
|
||||
|
||||
@@ -75,15 +75,15 @@ macro_rules! spawn_yield_many {
|
||||
#[cfg(test)]
|
||||
mod ylong_multi_threaded {
|
||||
extern crate test;
|
||||
use crate::task_helpers::*;
|
||||
use test::Bencher;
|
||||
|
||||
use std::hint::black_box;
|
||||
use std::sync::{mpsc, Arc};
|
||||
|
||||
use test::Bencher;
|
||||
use ylong_runtime::executor::Runtime;
|
||||
use ylong_runtime::task::yield_now;
|
||||
|
||||
use crate::task_helpers::*;
|
||||
|
||||
runtime_spawn_function!();
|
||||
|
||||
spawn_yield_many!(ylong_runtime, spawn_many, runtime_spawn_many);
|
||||
@@ -119,16 +119,15 @@ mod ylong_multi_threaded {
|
||||
#[cfg(test)]
|
||||
mod tokio_multi_threaded {
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
use crate::task_helpers::*;
|
||||
|
||||
use std::hint::black_box;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use test::Bencher;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::task::yield_now;
|
||||
|
||||
use crate::task_helpers::*;
|
||||
|
||||
runtime_spawn_function!();
|
||||
|
||||
spawn_yield_many!(tokio_runtime, spawn_many, runtime_spawn_many);
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
//! Benchmarks for mutex.
|
||||
//!
|
||||
//! Designs of ylong_runtime benchmarks:
|
||||
//! - Multiple threads are mutually exclusive to obtain the mutex and then rewrite the contents of the mutex for 10 times.
|
||||
//! - Multiple threads are mutually exclusive to obtain the mutex and then rewrite the contents of the mutex for 100 times.
|
||||
//! - Multiple threads are mutually exclusive to obtain the mutex and then rewrite the contents of the mutex for 1000 times.
|
||||
//! - Multiple threads are mutually exclusive to obtain the mutex and then
|
||||
//! rewrite the contents of the mutex for 10 times.
|
||||
//! - Multiple threads are mutually exclusive to obtain the mutex and then
|
||||
//! rewrite the contents of the mutex for 100 times.
|
||||
//! - Multiple threads are mutually exclusive to obtain the mutex and then
|
||||
//! rewrite the contents of the mutex for 1000 times.
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
@@ -84,14 +87,15 @@ macro_rules! ylong_mutex_task {
|
||||
mod mutex_bench {
|
||||
extern crate test;
|
||||
|
||||
pub use crate::task_helpers::tokio_runtime;
|
||||
use std::hint::black_box;
|
||||
use std::sync::Arc;
|
||||
use test::Bencher;
|
||||
|
||||
use test::Bencher;
|
||||
use tokio::sync::Mutex;
|
||||
use ylong_runtime::sync::Mutex as YlongMutex;
|
||||
|
||||
pub use crate::task_helpers::tokio_runtime;
|
||||
|
||||
ylong_mutex_task!(ylong_mutex_10, YlongMutex, 10);
|
||||
ylong_mutex_task!(ylong_mutex_100, YlongMutex, 100);
|
||||
ylong_mutex_task!(ylong_mutex_1000, YlongMutex, 1000);
|
||||
|
||||
@@ -27,26 +27,24 @@ pub mod task_helpers;
|
||||
mod rwlock_bench {
|
||||
extern crate test;
|
||||
|
||||
use std::hint::black_box;
|
||||
use std::sync::Arc;
|
||||
|
||||
use test::Bencher;
|
||||
use tokio::sync::RwLock;
|
||||
use ylong_runtime::sync::rwlock::RwLock as YlongRwlock;
|
||||
|
||||
pub use crate::task_helpers::{
|
||||
tokio_runtime, tokio_rwlock_task, tokio_rwlock_write_task, ylong_rwlock_task,
|
||||
ylong_rwlock_write_task,
|
||||
};
|
||||
use std::hint::black_box;
|
||||
use std::sync::Arc;
|
||||
use test::Bencher;
|
||||
|
||||
use tokio::sync::RwLock;
|
||||
use ylong_runtime::sync::rwlock::RwLock as YlongRwlock;
|
||||
|
||||
/// Benchmark test for tokio rwlock.
|
||||
///
|
||||
/// # Title
|
||||
/// Tokio_rwlock_read_concurrent_uncontended_multi
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create a runtime with 6 threads.
|
||||
/// 2.Create a rwLock variable.
|
||||
/// 3.Concurrently read data for 6 times.
|
||||
/// 1. Create a runtime with 6 threads.
|
||||
/// 2. Create a rwLock variable.
|
||||
/// 3. Concurrently read data for 6 times.
|
||||
#[bench]
|
||||
fn tokio_rwlock_read(b: &mut Bencher) {
|
||||
let rt = tokio_runtime();
|
||||
@@ -67,13 +65,10 @@ mod rwlock_bench {
|
||||
|
||||
/// Benchmark test for ylong rwlock.
|
||||
///
|
||||
/// # Title
|
||||
/// Ylong_rwlock_read_concurrent_uncontended_multi
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create a runtime with 6 threads.
|
||||
/// 2.Create a rwLock variable.
|
||||
/// 3.Concurrently read data for 6 times.
|
||||
/// 1. Create a runtime with 6 threads.
|
||||
/// 2. Create a rwLock variable.
|
||||
/// 3. Concurrently read data for 6 times.
|
||||
#[bench]
|
||||
fn ylong_rwlock_read(b: &mut Bencher) {
|
||||
let handle = ylong_runtime::spawn(async move {});
|
||||
@@ -95,13 +90,10 @@ mod rwlock_bench {
|
||||
|
||||
/// Benchmark test for tokio rwlock.
|
||||
///
|
||||
/// # Title
|
||||
/// Tokio_rwlock_read_concurrent_uncontended_multi
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create a runtime with 6 threads.
|
||||
/// 2.Create a rwLock variable.
|
||||
/// 3.Concurrently read data for 6 times.
|
||||
/// 1. Create a runtime with 6 threads.
|
||||
/// 2. Create a rwLock variable.
|
||||
/// 3. Concurrently read data for 6 times.
|
||||
#[bench]
|
||||
fn tokio_rwlock_write(b: &mut Bencher) {
|
||||
let rt = tokio_runtime();
|
||||
@@ -122,13 +114,10 @@ mod rwlock_bench {
|
||||
|
||||
/// Benchmark test for ylong rwlock.
|
||||
///
|
||||
/// # Title
|
||||
/// Ylong_rwlock_read_concurrent_uncontended_multi
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create a runtime with 6 threads.
|
||||
/// 2.Create a rwLock variable.
|
||||
/// 3.Concurrently read data for 6 times.
|
||||
/// 1. Create a runtime with 6 threads.
|
||||
/// 2. Create a rwLock variable.
|
||||
/// 3. Concurrently read data for 6 times.
|
||||
#[bench]
|
||||
fn ylong_rwlock_write(b: &mut Bencher) {
|
||||
let handle = ylong_runtime::spawn(async move {});
|
||||
@@ -150,14 +139,11 @@ mod rwlock_bench {
|
||||
|
||||
/// Benchmark test for tokio rwlock.
|
||||
///
|
||||
/// # Title
|
||||
/// Tokio_rwlock_read_concurrent_contended_multi
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create a runtime with 6 threads.
|
||||
/// 2.Create a rwLock variable.
|
||||
/// 3.Write the rwlock
|
||||
/// 4.Concurrently read data for 5 times.
|
||||
/// 1. Create a runtime with 6 threads.
|
||||
/// 2. Create a rwLock variable.
|
||||
/// 3. Write the rwlock
|
||||
/// 4. Concurrently read data for 5 times.
|
||||
#[bench]
|
||||
fn tokio_rwlock_write_read(b: &mut Bencher) {
|
||||
let rt = tokio_runtime();
|
||||
@@ -184,14 +170,11 @@ mod rwlock_bench {
|
||||
|
||||
/// Benchmark test for ylong rwlock.
|
||||
///
|
||||
/// # Title
|
||||
/// Ylong_rwlock_read_concurrent_contended_multi
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create a runtime with 6 threads.
|
||||
/// 2.Create a rwLock variable.
|
||||
/// 3.Write the rwlock
|
||||
/// 4.Concurrently read data for 5 times.
|
||||
/// 1. Create a runtime with 6 threads.
|
||||
/// 2. Create a rwLock variable.
|
||||
/// 3. Write the rwlock
|
||||
/// 4. Concurrently read data for 5 times.
|
||||
#[bench]
|
||||
fn ylong_rwlock_write_read(b: &mut Bencher) {
|
||||
let handle = ylong_runtime::spawn(async move {});
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarks for task scheduling.
|
||||
//!
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
@@ -67,12 +66,13 @@ macro_rules! ylong_schedule_task {
|
||||
mod tokio_schedule_bench {
|
||||
extern crate test;
|
||||
|
||||
pub use crate::task_helpers::{fibbo, tokio_runtime};
|
||||
use std::hint::black_box;
|
||||
use test::Bencher;
|
||||
|
||||
use test::Bencher;
|
||||
use ylong_runtime::task::yield_now;
|
||||
|
||||
pub use crate::task_helpers::{fibbo, tokio_runtime};
|
||||
|
||||
tokio_schedule_task!(tokio_runtime(), tokio_task_10_15, 10, 15);
|
||||
tokio_schedule_task!(tokio_runtime(), tokio_task_120_15, 120, 15);
|
||||
tokio_schedule_task!(tokio_runtime(), tokio_task_10_30, 10, 30);
|
||||
@@ -83,12 +83,13 @@ mod tokio_schedule_bench {
|
||||
mod ylong_schedule_bench {
|
||||
extern crate test;
|
||||
|
||||
pub use crate::task_helpers::{fibbo, tokio_runtime};
|
||||
use std::hint::black_box;
|
||||
use test::Bencher;
|
||||
|
||||
use test::Bencher;
|
||||
use ylong_runtime::task::yield_now;
|
||||
|
||||
pub use crate::task_helpers::{fibbo, tokio_runtime};
|
||||
|
||||
ylong_schedule_task!(ylong_task_10_15, 10, 15);
|
||||
ylong_schedule_task!(ylong_task_120_15, 120, 15);
|
||||
ylong_schedule_task!(ylong_task_10_30, 10, 30);
|
||||
|
||||
@@ -128,17 +128,17 @@ macro_rules! ylong_tcp_task {
|
||||
mod tcp_bench {
|
||||
extern crate test;
|
||||
|
||||
pub use crate::task_helpers::tokio_runtime;
|
||||
use std::hint::black_box;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use test::Bencher;
|
||||
use tokio::io::AsyncReadExt as tokioAsyncReadExt;
|
||||
use tokio::io::AsyncWriteExt as tokioAsyncWriteExt;
|
||||
use tokio::net::TcpListener as tokioTcpListener;
|
||||
use tokio::net::TcpStream as tokioTcpStream;
|
||||
use tokio::io::{AsyncReadExt as tokioAsyncReadExt, AsyncWriteExt as tokioAsyncWriteExt};
|
||||
use tokio::net::{TcpListener as tokioTcpListener, TcpStream as tokioTcpStream};
|
||||
use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use ylong_runtime::net::{TcpListener, TcpStream};
|
||||
|
||||
pub use crate::task_helpers::tokio_runtime;
|
||||
|
||||
ylong_tcp_task!(
|
||||
ylong_tcp_10_1000_10000,
|
||||
ylong_server1,
|
||||
|
||||
@@ -23,21 +23,17 @@ pub mod task_helpers;
|
||||
mod udp_bench {
|
||||
extern crate test;
|
||||
|
||||
use crate::task_helpers::tokio_runtime;
|
||||
use test::Bencher;
|
||||
|
||||
use tokio::net::UdpSocket as tokioUdpSocket;
|
||||
use ylong_runtime::net::UdpSocket;
|
||||
|
||||
use tokio::net::UdpSocket as tokioUdpSocket;
|
||||
use crate::task_helpers::tokio_runtime;
|
||||
|
||||
/// benchmark test for ylong udp connect.
|
||||
///
|
||||
/// # Title
|
||||
/// ylong_udp_connect
|
||||
/// Benchmark test for ylong udp connect.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create sender.
|
||||
/// 2.Bind and Connect.
|
||||
/// 1. Create sender.
|
||||
/// 2. Bind and Connect.
|
||||
#[bench]
|
||||
fn ylong_udp_connect(b: &mut Bencher) {
|
||||
let sender_addr = "127.0.0.1:8093".parse().unwrap();
|
||||
@@ -52,14 +48,11 @@ mod udp_bench {
|
||||
});
|
||||
}
|
||||
|
||||
/// benchmark test for tokio udp connect.
|
||||
///
|
||||
/// # Title
|
||||
/// tokio_udp_connect
|
||||
/// Benchmark test for tokio udp connect.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create sender.
|
||||
/// 2.Bind and Connect.
|
||||
/// 1. Create sender.
|
||||
/// 2. Bind and Connect.
|
||||
#[bench]
|
||||
fn tokio_udp_connect(b: &mut Bencher) {
|
||||
let sender_addr = "127.0.0.1:8095";
|
||||
@@ -75,16 +68,14 @@ mod udp_bench {
|
||||
});
|
||||
}
|
||||
|
||||
/// benchmark test for ylong udp function send() and recv().
|
||||
///
|
||||
/// # Title
|
||||
/// ylong_udp_send_recv
|
||||
/// Benchmark test for ylong udp function send() and recv().
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create sender and receiver, bind their new UdpSockets and connect to each other.
|
||||
/// 2.Sender use send() to send message.
|
||||
/// 3.Receiver use recv() to receives message.
|
||||
/// 4.Check if the test results are correct.
|
||||
/// 1. Create sender and receiver, bind their new UdpSockets and connect to
|
||||
/// each other.
|
||||
/// 2. Sender use send() to send message.
|
||||
/// 3. Receiver use recv() to receives message.
|
||||
/// 4. Check if the test results are correct.
|
||||
#[bench]
|
||||
fn ylong_udp_send_recv(b: &mut Bencher) {
|
||||
let basic_addr = "127.0.0.1:";
|
||||
@@ -121,16 +112,14 @@ mod udp_bench {
|
||||
});
|
||||
}
|
||||
|
||||
/// benchmark test for tokio udp function send() and recv().
|
||||
///
|
||||
/// # Title
|
||||
/// tokio_udp_send_recv
|
||||
/// Benchmark test for tokio udp function send() and recv().
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create sender and receiver, bind their new UdpSockets and connect to each other.
|
||||
/// 2.Sender use send() to send message.
|
||||
/// 3.Receiver use recv() to receives message.
|
||||
/// 4.Check if the test results are correct.
|
||||
/// 1. Create sender and receiver, bind their new UdpSockets and connect to
|
||||
/// each other.
|
||||
/// 2. Sender use send() to send message.
|
||||
/// 3. Receiver use recv() to receives message.
|
||||
/// 4. Check if the test results are correct.
|
||||
#[bench]
|
||||
fn tokio_udp_send_recv(b: &mut Bencher) {
|
||||
let basic_addr = "127.0.0.1:";
|
||||
@@ -164,16 +153,13 @@ mod udp_bench {
|
||||
});
|
||||
}
|
||||
|
||||
/// benchmark test for ylong udp function send_to() and recv_from().
|
||||
///
|
||||
/// # Title
|
||||
/// ylong_udp_send_to_recv_from
|
||||
/// Benchmark test for ylong udp function send_to() and recv_from().
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create sender and receiver.
|
||||
/// 2.Sender use send_to() to send message.
|
||||
/// 3.Receiver use recv_from() to receives message.
|
||||
/// 4.Check if the test results are correct.
|
||||
/// 1. Create sender and receiver.
|
||||
/// 2. Sender use send_to() to send message.
|
||||
/// 3. Receiver use recv_from() to receives message.
|
||||
/// 4. Check if the test results are correct.
|
||||
#[bench]
|
||||
fn ylong_udp_send_to_recv_from(b: &mut Bencher) {
|
||||
let basic_addr = "127.0.0.1:";
|
||||
@@ -207,16 +193,13 @@ mod udp_bench {
|
||||
});
|
||||
}
|
||||
|
||||
/// benchmark test for tokio udp function send_to() and recv_from().
|
||||
///
|
||||
/// # Title
|
||||
/// tokio_udp_send_to_recv_from
|
||||
/// Benchmark test for tokio udp function send_to() and recv_from().
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Create sender and receiver.
|
||||
/// 2.Sender use send_to() to send message.
|
||||
/// 3.Receiver use recv_from() to receives message.
|
||||
/// 4.Check if the test results are correct.
|
||||
/// 1. Create sender and receiver.
|
||||
/// 2. Sender use send_to() to send message.
|
||||
/// 3. Receiver use recv_from() to receives message.
|
||||
/// 4. Check if the test results are correct.
|
||||
#[bench]
|
||||
fn tokio_udp_send_to_recv_from(b: &mut Bencher) {
|
||||
let basic_addr = "127.0.0.1:";
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarks for memory usage, computed by difference between virtual rss printed.
|
||||
//! Benchmarks for memory usage, computed by difference between virtual rss
|
||||
//! printed.
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::process;
|
||||
#[cfg(unix)]
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(unix)]
|
||||
use ylong_runtime::builder::RuntimeBuilder;
|
||||
#[cfg(unix)]
|
||||
|
||||
@@ -37,7 +37,8 @@ fn main() {
|
||||
let core_pool_size = 4;
|
||||
// Sets whether the asynchronous thread pool is tied for core processing
|
||||
let is_affinity = true;
|
||||
// Creates runtime environment second time (only asynchronous thread pools are supported)
|
||||
// Creates runtime environment second time (only asynchronous thread pools are
|
||||
// supported)
|
||||
let runtime_two = RuntimeBuilder::new_multi_thread()
|
||||
.is_affinity(is_affinity)
|
||||
.worker_num(core_pool_size)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
//! An example for `tcp`
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use ylong_runtime::net::{TcpListener, TcpStream};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
//! Sleep usage in ylong_runtime.
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use ylong_runtime::builder::RuntimeBuilder;
|
||||
#[cfg(feature = "time")]
|
||||
use ylong_runtime::time::sleep;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
//! Examples for task scheduling
|
||||
use std::hint::black_box;
|
||||
|
||||
use ylong_runtime::task::yield_now;
|
||||
|
||||
fn recur_fibbo(a: u64) -> u64 {
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::builder::CallbackHook;
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
use crate::builder::ScheduleAlgo;
|
||||
use crate::executor::blocking_pool::BLOCKING_MAX_THEAD_NUM;
|
||||
use std::time::Duration;
|
||||
|
||||
const BLOCKING_PERMANENT_THREAD_NUM: u8 = 0;
|
||||
|
||||
@@ -70,12 +71,13 @@ impl CommonBuilder {
|
||||
|
||||
macro_rules! impl_common {
|
||||
($self:ident) => {
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
use crate::builder::ScheduleAlgo;
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
use crate::builder::ScheduleAlgo;
|
||||
|
||||
impl $self {
|
||||
/// Sets the name prefix for all worker threads.
|
||||
pub fn worker_name(mut self, name: String) -> Self {
|
||||
@@ -104,8 +106,8 @@ macro_rules! impl_common {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the number of threads that the runtime could spawn additionally besides the core
|
||||
/// thread pool.
|
||||
/// Sets the number of threads that the runtime could spawn additionally
|
||||
/// besides the core thread pool.
|
||||
///
|
||||
/// The boundary is 1-64.
|
||||
pub fn max_blocking_pool_size(mut self, max_blocking_pool_size: u8) -> Self {
|
||||
@@ -126,8 +128,8 @@ macro_rules! impl_common {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the stack size for every worker thread that gets spawned by the runtime.
|
||||
/// The minimum stack size is 1.
|
||||
/// Sets the stack size for every worker thread that gets spawned by the
|
||||
/// runtime. The minimum stack size is 1.
|
||||
pub fn worker_stack_size(mut self, stack_size: usize) -> Self {
|
||||
if stack_size < 1 {
|
||||
self.common.stack_size = Some(1);
|
||||
@@ -137,8 +139,8 @@ macro_rules! impl_common {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets how long will the thread be kept alive inside the blocking pool after
|
||||
/// it becomes idle.
|
||||
/// Sets how long will the thread be kept alive inside the blocking pool
|
||||
/// after it becomes idle.
|
||||
pub fn keep_alive_time(mut self, keep_alive_time: Duration) -> Self {
|
||||
self.common.keep_alive_time = Some(keep_alive_time);
|
||||
self
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::io;
|
||||
|
||||
use crate::builder::common_builder::impl_common;
|
||||
use crate::builder::CommonBuilder;
|
||||
use crate::executor::current_thread::CurrentThreadSpawner;
|
||||
use crate::executor::{AsyncHandle, Runtime};
|
||||
use std::io;
|
||||
|
||||
/// RuntimeBuilder struct with current_thread settings.
|
||||
pub struct CurrentThreadBuilder {
|
||||
|
||||
+101
-154
@@ -17,11 +17,12 @@
|
||||
//! `CurrentThread`: Runtime which runs on the current thread.
|
||||
//! `MultiThread`: Runtime which runs on multiple threads.
|
||||
//!
|
||||
//! After configuring the builder, a call to `build` will return the actual runtime instance.
|
||||
//! [`MultiThreadBuilder`] could also be used for configuring the global singleton runtime.
|
||||
//! After configuring the builder, a call to `build` will return the actual
|
||||
//! runtime instance. [`MultiThreadBuilder`] could also be used for configuring
|
||||
//! the global singleton runtime.
|
||||
//!
|
||||
//! For thread pool, the builder allows the user to set the thread number, stack size and
|
||||
//! name prefix of each thread.
|
||||
//! For thread pool, the builder allows the user to set the thread number, stack
|
||||
//! size and name prefix of each thread.
|
||||
|
||||
pub(crate) mod common_builder;
|
||||
#[cfg(feature = "current_thread_runtime")]
|
||||
@@ -31,22 +32,24 @@ pub(crate) mod multi_thread_builder;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
#[cfg(any(feature = "net", feature = "time"))]
|
||||
use std::sync::Once;
|
||||
|
||||
#[cfg(feature = "current_thread_runtime")]
|
||||
pub use current_thread_builder::CurrentThreadBuilder;
|
||||
pub use multi_thread_builder::MultiThreadBuilder;
|
||||
|
||||
pub(crate) use crate::builder::common_builder::CommonBuilder;
|
||||
use crate::error::ScheduleError;
|
||||
use crate::executor::blocking_pool::BlockPoolSpawner;
|
||||
#[cfg(any(feature = "net", feature = "time"))]
|
||||
use crate::executor::netpoller::NetLooper;
|
||||
#[cfg(feature = "current_thread_runtime")]
|
||||
pub use current_thread_builder::CurrentThreadBuilder;
|
||||
pub use multi_thread_builder::MultiThreadBuilder;
|
||||
#[cfg(any(feature = "net", feature = "time"))]
|
||||
use std::sync::Once;
|
||||
crate::macros::cfg_not_ffrt!(
|
||||
use crate::executor::async_pool::AsyncPoolSpawner;
|
||||
);
|
||||
|
||||
/// A callback function to be executed in different stages of a thread's life-cycle
|
||||
/// A callback function to be executed in different stages of a thread's
|
||||
/// life-cycle
|
||||
pub type CallbackHook = Arc<dyn Fn() + Send + Sync + 'static>;
|
||||
|
||||
/// Schedule Policy.
|
||||
@@ -56,17 +59,18 @@ pub enum ScheduleAlgo {
|
||||
FifoBound,
|
||||
}
|
||||
|
||||
/// Builder to build the runtime. Provides methods to customize the runtime, such
|
||||
/// as setting thread pool size, worker thread stack size, work thread prefix and etc.
|
||||
/// Builder to build the runtime. Provides methods to customize the runtime,
|
||||
/// such as setting thread pool size, worker thread stack size, work thread
|
||||
/// prefix and etc.
|
||||
///
|
||||
/// If `multi_instance_runtime` or `current_thread_runtime` feature is turned on:
|
||||
/// After setting the RuntimeBuilder, a call to build will initialize the actual runtime
|
||||
/// and returns its instance. If there is an invalid parameter during the build, an error
|
||||
/// would be returned.
|
||||
/// If `multi_instance_runtime` or `current_thread_runtime` feature is turned
|
||||
/// on: After setting the RuntimeBuilder, a call to build will initialize the
|
||||
/// actual runtime and returns its instance. If there is an invalid parameter
|
||||
/// during the build, an error would be returned.
|
||||
///
|
||||
/// Otherwise:
|
||||
/// RuntimeBuilder will not have the `build()` method, instead, this builder should be
|
||||
/// passed to set the global executor.
|
||||
/// RuntimeBuilder will not have the `build()` method, instead, this builder
|
||||
/// should be passed to set the global executor.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -81,15 +85,14 @@ pub enum ScheduleAlgo {
|
||||
/// .worker_stack_size(1024 * 300)
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
///
|
||||
/// ```
|
||||
pub struct RuntimeBuilder;
|
||||
|
||||
impl RuntimeBuilder {
|
||||
/// Initializes a new RuntimeBuilder with current_thread settings.
|
||||
///
|
||||
/// All tasks will run on the current thread, which means it does not create any other
|
||||
/// worker threads.
|
||||
/// All tasks will run on the current thread, which means it does not create
|
||||
/// any other worker threads.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -107,8 +110,9 @@ impl RuntimeBuilder {
|
||||
|
||||
/// Initializes a new RuntimeBuilder with multi_thread settings.
|
||||
///
|
||||
/// When running, worker threads will be created according to the builder configuration,
|
||||
/// and tasks will be allocated and run in the newly created thread pool.
|
||||
/// When running, worker threads will be created according to the builder
|
||||
/// configuration, and tasks will be allocated and run in the newly
|
||||
/// created thread pool.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -163,31 +167,27 @@ pub(crate) fn initialize_reactor() -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::builder::RuntimeBuilder;
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
use crate::builder::ScheduleAlgo;
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::new_multi_thread() UT test
|
||||
* @design The function has no input, no exception branch, direct check function, return value
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Checks if the object name property is None
|
||||
* 2、Checks if the object core_pool_size property is None
|
||||
* 3、Checks if the object is_steal property is true
|
||||
* 4、Checks if the object is_affinity property is true
|
||||
* 5、Checks if the object permanent_blocking_thread_num property is 4
|
||||
* 6、Checks if the object max_pool_size property is Some(50)
|
||||
* 7、Checks if the object keep_alive_time property is None
|
||||
* 8、Checks if the object schedule_algo property is ScheduleAlgo::FifoBound
|
||||
* 9、Checks if the object stack_size property is None
|
||||
* 10、Checks if the object after_start property is None
|
||||
* 11、Checks if the object before_stop property is None
|
||||
* @expect The function has no entry, no exception branch, and the initialization parameters should correspond to each other
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::new_multi_thread()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Checks if the object name property is None
|
||||
/// 2. Checks if the object core_pool_size property is None
|
||||
/// 3. Checks if the object is_steal property is true
|
||||
/// 4. Checks if the object is_affinity property is true
|
||||
/// 5. Checks if the object permanent_blocking_thread_num property is 4
|
||||
/// 6. Checks if the object max_pool_size property is Some(50)
|
||||
/// 7. Checks if the object keep_alive_time property is None
|
||||
/// 8. Checks if the object schedule_algo property is
|
||||
/// ScheduleAlgo::FifoBound
|
||||
/// 9. Checks if the object stack_size property is None
|
||||
/// 10. Checks if the object after_start property is None
|
||||
/// 11. Checks if the object before_stop property is None
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_new() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread();
|
||||
@@ -204,15 +204,10 @@ mod test {
|
||||
assert_eq!(thread_pool_builder.common.stack_size, None);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::name() UT test
|
||||
* @design The function has no input, no exception branch, direct check function, return value
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Checks if the object name property is modified value
|
||||
* @expect The function entry has no invalid value, no exception branch, and the modified name property should be Some(worker_name)
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::name()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Checks if the object name property is modified value
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_name() {
|
||||
let name = String::from("worker_name");
|
||||
@@ -220,23 +215,13 @@ mod test {
|
||||
assert_eq!(thread_pool_builder.common.worker_name, Some(name));
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::core_pool_size() UT test
|
||||
* @design Input 1: core_pool_size
|
||||
* Valid value range: core_pool_size >= 1 && core_pool_size <= 64
|
||||
* Invalid value range: core_pool_size < 1 || core_pool_size > 64
|
||||
* No abnormal branches
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、core_pool_size set to 1, Check if the return value is Some(1)
|
||||
* 2、core_pool_size set to 64, Check if the return value is Some(64)
|
||||
* 3、core_pool_size set to 0, Check if the return value is Some(1)
|
||||
* 4、core_pool_size set to 65, Check if the return value is Some(64)
|
||||
* @expect Value of core_pool_size property after modification
|
||||
* Some(core_pool_size) in the valid range
|
||||
* Modified to a valid value close to the invalid value range
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::core_pool_size()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. core_pool_size set to 1, Check if the return value is Some(1)
|
||||
/// 2. core_pool_size set to 64, Check if the return value is Some(64)
|
||||
/// 3. core_pool_size set to 0, Check if the return value is Some(1)
|
||||
/// 4. core_pool_size set to 65, Check if the return value is Some(64)
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_core_pool_size() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread().worker_num(1);
|
||||
@@ -252,20 +237,11 @@ mod test {
|
||||
assert_eq!(thread_pool_builder.core_thread_size, Some(64));
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::stack_size() UT test
|
||||
* @design Input 1: stack_size
|
||||
* Valid value range: stack_size > 0
|
||||
* Invalid value range: stack_size = 0
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、stack_size set to 0, Check if the return value is Some(1)
|
||||
* 2、stack_size set to 1, Check if the return value is Some(1)
|
||||
* @expect Modified stack_size property value
|
||||
* Some(stack_size) in the range of valid values
|
||||
* Modified to a valid value close to the invalid value range
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::stack_size()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. stack_size set to 0, Check if the return value is Some(1)
|
||||
/// 2. stack_size set to 1, Check if the return value is Some(1)
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_stack_size() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread().worker_stack_size(0);
|
||||
@@ -276,20 +252,18 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "current_thread_runtime")]
|
||||
mod current_thread_test {
|
||||
use crate::builder::RuntimeBuilder;
|
||||
|
||||
/// UT test for new_current_thread.
|
||||
///
|
||||
/// # Title
|
||||
/// ut_thread_pool_builder_current_thread
|
||||
/// UT test cases for new_current_thread.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Verify the result when multiple tasks are inserted to the current thread at a time.
|
||||
/// 1. Verify the result when multiple tasks are inserted to the current
|
||||
/// thread at a time.
|
||||
/// 2. Insert the task for multiple times, wait until the task is complete,
|
||||
/// verify the result, and then perform the operation again.
|
||||
/// verify the result, and then perform the operation again.
|
||||
/// 3. Spawn nest thread.
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_current_thread() {
|
||||
@@ -325,20 +299,15 @@ mod current_thread_test {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod ylong_executor_test {
|
||||
use crate::builder::{RuntimeBuilder, ScheduleAlgo};
|
||||
|
||||
/*
|
||||
* @title ThreadPoolBuilder::is_affinity() UT test
|
||||
* @design The function has no input, no exception branch, direct check function, return value
|
||||
* @precon Use ThreadPoolBuilder::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、is_affinity set to true, check if it is a modified value
|
||||
* 2、is_affinity set to false, check if it is a modified value
|
||||
* @expect The function entry has no invalid values, no exception branches, and the value of the is_affinity property should be is_affinity after modification
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ThreadPoolBuilder::is_affinity()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. is_affinity set to true, check if it is a modified value
|
||||
/// 2. is_affinity set to false, check if it is a modified value
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_is_affinity() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread().is_affinity(true);
|
||||
@@ -348,22 +317,17 @@ mod ylong_executor_test {
|
||||
assert!(!thread_pool_builder.common.is_affinity);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::blocking_permanent_thread_num() UT test
|
||||
* @design Input 1: blocking_permanent_thread_num
|
||||
* Valid value range: blocking_permanent_thread_num >= 1 && blocking_permanent_thread_num <= max_blocking_pool_size
|
||||
* Invalid value range: blocking_permanent_thread_num < 1 || blocking_permanent_thread_num > max_blocking_pool_size
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、permanent_blocking_thread_num set to 1, check if the return value is 1
|
||||
* 2、permanent_blocking_thread_num set to max_thread_num, check if the return value is max_blocking_pool_size
|
||||
* 3、permanent_blocking_thread_num set to 0, check if the return value is 1
|
||||
* 4、permanent_blocking_thread_num set to max_thread_num + 1, Check if the return value O is max_blocking_pool_size
|
||||
* @expect Modified permanent_blocking_thread_num property value
|
||||
* In the valid range is permanent_blocking_thread_num
|
||||
* Modified to a valid value close to the invalid value range
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::blocking_permanent_thread_num()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. permanent_blocking_thread_num set to 1, check if the return value is
|
||||
/// 1.
|
||||
/// 2. permanent_blocking_thread_num set to max_thread_num, check if the
|
||||
/// return value is max_blocking_pool_size.
|
||||
/// 3. permanent_blocking_thread_num set to 0, check if the return value is
|
||||
/// 1.
|
||||
/// 4. permanent_blocking_thread_num set to max_thread_num + 1, Check if the
|
||||
/// return value O is max_blocking_pool_size.
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_permanent_blocking_thread_num() {
|
||||
let thread_pool_builder =
|
||||
@@ -393,22 +357,13 @@ mod ylong_executor_test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::max_pool_size() UT test
|
||||
* @design Input 1: max_pool_size
|
||||
* Valid value range: max_pool_size >= 1 && max_pool_size <= 64
|
||||
* Invalid value range: max_pool_size < 1 || max_pool_size > 64
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、max_pool_size set to 1, check if the return value is Some(1)
|
||||
* 2、max_pool_size set to 64, check if the return value is Some(64)
|
||||
* 3、max_pool_size set to 0, check if the return value is Some(1)
|
||||
* 4、max_pool_size set to 65, check if the return value is Some(64)
|
||||
* @expect Value of max_pool_size property after modification
|
||||
* max_pool_size within the valid values
|
||||
* Modified to a valid value close to the invalid value range
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::max_pool_size()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. max_pool_size set to 1, check if the return value is Some(1)
|
||||
/// 2. max_pool_size set to 64, check if the return value is Some(64)
|
||||
/// 3. max_pool_size set to 0, check if the return value is Some(1)
|
||||
/// 4. max_pool_size set to 65, check if the return value is Some(64)
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_max_pool_size() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread().max_blocking_pool_size(1);
|
||||
@@ -436,16 +391,13 @@ mod ylong_executor_test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::keep_alive_time() UT test
|
||||
* @design The function has no invalid values in the input, no exception branch, direct check function, return value
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、keep_alive_time set to 0, check if the return value is Some(Duration::from_secs(0))
|
||||
* 2、keep_alive_time set to 1, check if the return value is Some(Duration::from_secs(1))
|
||||
* @expect The function entry has no invalid value, no exception branch, and the value of the keep_alive_time property should be Some(keep_alive_time) after modification
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::keep_alive_time()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. keep_alive_time set to 0, check if the return value is
|
||||
/// Some(Duration::from_secs(0))
|
||||
/// 2. keep_alive_time set to 1, check if the return value is
|
||||
/// Some(Duration::from_secs(1))
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_keep_alive_time() {
|
||||
use std::time::Duration;
|
||||
@@ -467,17 +419,12 @@ mod ylong_executor_test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title RuntimeBuilder::schedule_algo() UT test
|
||||
* @design The function has no invalid values in the input, no exception branch, direct check function, return value
|
||||
* @precon Use RuntimeBuilder::new_multi_thread(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、schedule_algo set to FifoBound, check if it is the modified value
|
||||
* 2、schedule_algo set to FifoUnbound, check if it is the modified value
|
||||
* 3、schedule_algo set to Priority, check if it is the modified value
|
||||
* @expect The function entry has no invalid values, no exception branches, and the modified schedule_algo property should be schedule_algo
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for RuntimeBuilder::schedule_algo()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. schedule_algo set to FifoBound, check if it is the modified value
|
||||
/// 2. schedule_algo set to FifoUnbound, check if it is the modified value
|
||||
/// 3. schedule_algo set to Priority, check if it is the modified value
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
#[test]
|
||||
fn ut_thread_pool_builder_schedule_algo_test() {
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::io;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::builder::common_builder::impl_common;
|
||||
use crate::builder::CommonBuilder;
|
||||
#[cfg(feature = "multi_instance_runtime")]
|
||||
use crate::executor::{AsyncHandle, Runtime};
|
||||
use std::io;
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub(crate) static GLOBAL_BUILDER: Mutex<Option<MultiThreadBuilder>> = Mutex::new(None);
|
||||
|
||||
/// Runtime builder that configures a multi-threaded runtime, or the global runtime.
|
||||
/// Runtime builder that configures a multi-threaded runtime, or the global
|
||||
/// runtime.
|
||||
pub struct MultiThreadBuilder {
|
||||
pub(crate) common: CommonBuilder,
|
||||
|
||||
@@ -39,8 +41,8 @@ impl MultiThreadBuilder {
|
||||
/// Configures the global runtime.
|
||||
///
|
||||
/// # Error
|
||||
/// If the global runtime is already running or this method has been called before, then
|
||||
/// it will return an `AlreadyExists` error.
|
||||
/// If the global runtime is already running or this method has been called
|
||||
/// before, then it will return an `AlreadyExists` error.
|
||||
pub fn build_global(self) -> io::Result<()> {
|
||||
let mut builder = GLOBAL_BUILDER.lock().unwrap();
|
||||
match *builder {
|
||||
@@ -73,8 +75,7 @@ impl MultiThreadBuilder {
|
||||
/// ```
|
||||
/// use crate::ylong_runtime::builder::RuntimeBuilder;
|
||||
///
|
||||
/// let runtime = RuntimeBuilder::new_multi_thread()
|
||||
/// .worker_num(8);
|
||||
/// let runtime = RuntimeBuilder::new_multi_thread().worker_num(8);
|
||||
/// ```
|
||||
pub fn worker_num(mut self, core_pool_size: u8) -> Self {
|
||||
if core_pool_size < 1 {
|
||||
@@ -96,7 +97,8 @@ mod test {
|
||||
use crate::builder::RuntimeBuilder;
|
||||
use crate::executor::{global_default_async, AsyncHandle};
|
||||
|
||||
/// UT for blocking on a time sleep without initializing the runtime.
|
||||
/// UT test cases for blocking on a time sleep without initializing the
|
||||
/// runtime.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Configure the global runtime to make it have six core threads
|
||||
|
||||
+29
-56
@@ -114,7 +114,7 @@ impl ScheduleError {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ylong_runtime::error::{ScheduleError, ErrorKind};
|
||||
/// use ylong_runtime::error::{ErrorKind, ScheduleError};
|
||||
///
|
||||
/// // Able to create new error types directly from strings
|
||||
/// let custom_error = ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown");
|
||||
@@ -140,8 +140,7 @@ impl ScheduleError {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ylong_runtime::error::ScheduleError;
|
||||
/// use ylong_runtime::error::ErrorKind;
|
||||
/// use ylong_runtime::error::{ErrorKind, ScheduleError};
|
||||
///
|
||||
/// fn print_error(err: ScheduleError) {
|
||||
/// if let Some(inner_err) = err.into_inner() {
|
||||
@@ -167,8 +166,7 @@ impl ScheduleError {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ylong_runtime::error::ScheduleError;
|
||||
/// use ylong_runtime::error::ErrorKind;
|
||||
/// use ylong_runtime::error::{ErrorKind, ScheduleError};
|
||||
///
|
||||
/// fn print_error(err: ScheduleError) {
|
||||
/// println!("{:?}", err.kind());
|
||||
@@ -195,20 +193,15 @@ impl From<ScheduleError> for io::Error {
|
||||
|
||||
impl std::error::Error for ScheduleError {}
|
||||
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::error::{ErrorKind, ScheduleError};
|
||||
|
||||
/*
|
||||
* @title ScheduleError `Debug` UT test
|
||||
* @design The function has no input parameters, there is an exception branch, direct check function, return value
|
||||
* @precon None
|
||||
* @brief Describe test case execution
|
||||
* 1、Creating simple errors
|
||||
* 2、Creating complex errors
|
||||
* @expect Verify that `Debug` prints for different error cases, and that they correspond to each other
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ScheduleError `Debug`
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Creating simple errors
|
||||
/// 2. Creating complex errors
|
||||
#[test]
|
||||
fn ut_schedule_error_debug() {
|
||||
let simple_error: ScheduleError = ErrorKind::TaskShutdown.into();
|
||||
@@ -221,16 +214,11 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ScheduleError `Display` UT test
|
||||
* @design The function has no input parameters, there is an exception branch, direct check function, return value
|
||||
* @precon None
|
||||
* @brief Describe test case execution
|
||||
* 1、Creating simple errors
|
||||
* 2、Creating complex errors
|
||||
* @expect Verify that `Display` prints for different error cases, and that they correspond to each other
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ScheduleError `Display`
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Creating simple errors
|
||||
/// 2. Creating complex errors
|
||||
#[test]
|
||||
fn ut_schedule_error_display() {
|
||||
let simple_error: ScheduleError = ErrorKind::TaskShutdown.into();
|
||||
@@ -243,16 +231,11 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ScheduleError::new() UT test
|
||||
* @design The function has no invalid input, there is an exception branch, direct check function, return value
|
||||
* @precon None
|
||||
* @brief Describe test case execution
|
||||
* 1、Creating simple errors
|
||||
* 2、Creating complex errors
|
||||
* @expect Verify the error structure created
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ScheduleError::new()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Creating simple errors
|
||||
/// 2. Creating complex errors
|
||||
#[test]
|
||||
fn ut_schedule_error_new() {
|
||||
let custom_error_one =
|
||||
@@ -274,16 +257,11 @@ mod test {
|
||||
assert_eq!(format!("{custom_error_two}"), "TaskShutdown: task shutdown");
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ScheduleError::kind() UT test
|
||||
* @design The function has no input parameters, there is an exception branch, direct check function, return value
|
||||
* @precon None
|
||||
* @brief Describe test case execution
|
||||
* 1、Creating simple errors
|
||||
* 2、Creating complex errors
|
||||
* @expect Verify the `ErrorKind` condition in the created error structure
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ScheduleError::kind()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Creating simple errors
|
||||
/// 2. Creating complex errors
|
||||
#[test]
|
||||
fn ut_schedule_error_kind() {
|
||||
let simple_error: ScheduleError = ErrorKind::Other.into();
|
||||
@@ -293,16 +271,11 @@ mod test {
|
||||
assert_eq!(format!("{:?}", custom_error.kind()), "TaskShutdown");
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ScheduleError::into_inner() UT test
|
||||
* @design The function has no input parameters, there is an exception branch, direct check function, return value
|
||||
* @precon None
|
||||
* @brief Describe test case execution
|
||||
* 1、Creating simple errors
|
||||
* 2、Creating complex errors
|
||||
* @expect Checking the results according to the different cases of creation errors
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ScheduleError::into_inner()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Creating simple errors
|
||||
/// 2. Creating complex errors
|
||||
#[test]
|
||||
fn ut_schedule_error_into_inner() {
|
||||
let simple_error: ScheduleError = ErrorKind::Other.into();
|
||||
|
||||
@@ -11,30 +11,29 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::builder::CallbackHook;
|
||||
use crate::executor::sleeper::Sleepers;
|
||||
use crate::executor::worker::{get_current_ctx, run_worker, Worker, WorkerContext};
|
||||
use crate::executor::{worker, Schedule};
|
||||
use crate::task::{Task, TaskBuilder, VirtualTableType};
|
||||
use crate::util::num_cpus::get_cpu_num;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::LinkedList;
|
||||
use std::future::Future;
|
||||
use std::sync::atomic::Ordering::{Acquire, SeqCst};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
||||
use std::time::Duration;
|
||||
use std::{cmp, thread};
|
||||
|
||||
use crate::util::core_affinity::set_current_affinity;
|
||||
|
||||
use crate::builder::multi_thread_builder::MultiThreadBuilder;
|
||||
use crate::builder::CallbackHook;
|
||||
use crate::executor::parker::Parker;
|
||||
use crate::executor::queue::{GlobalQueue, LocalQueue, LOCAL_QUEUE_CAP};
|
||||
use crate::executor::sleeper::Sleepers;
|
||||
use crate::executor::worker::{get_current_ctx, run_worker, Worker, WorkerContext};
|
||||
use crate::executor::{worker, Schedule};
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::{Driver, Handle};
|
||||
use crate::task::{Task, TaskBuilder, VirtualTableType};
|
||||
use crate::util::core_affinity::set_current_affinity;
|
||||
use crate::util::fastrand::fast_random;
|
||||
use crate::util::num_cpus::get_cpu_num;
|
||||
use crate::JoinHandle;
|
||||
use std::future::Future;
|
||||
|
||||
const ASYNC_THREAD_QUIT_WAIT_TIME: Duration = Duration::from_secs(3);
|
||||
pub(crate) const GLOBAL_POLL_INTERVAL: u8 = 61;
|
||||
@@ -48,7 +47,8 @@ pub(crate) struct MultiThreadScheduler {
|
||||
pub(crate) num_workers: usize,
|
||||
/// Join Handles for all threads in the executor
|
||||
handles: RwLock<Vec<Parker>>,
|
||||
/// records the number of stealing workers and the number of working workers.
|
||||
/// records the number of stealing workers and the number of working
|
||||
/// workers.
|
||||
pub(crate) record: Record,
|
||||
/// The global queue of the executor
|
||||
global: GlobalQueue,
|
||||
@@ -71,7 +71,7 @@ impl Record {
|
||||
Self(AtomicUsize::new(num_unpark << ACTIVE_WORKER_SHIFT))
|
||||
}
|
||||
|
||||
//Return true if it is the last searching thread
|
||||
// Return true if it is the last searching thread
|
||||
pub(crate) fn dec_searching_num(&self) -> bool {
|
||||
let ret = self.0.fetch_sub(1, SeqCst);
|
||||
(ret & SEARCHING_MASK) == 1
|
||||
@@ -253,7 +253,8 @@ impl MultiThreadScheduler {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the local queue of the current worker is full, push the task into the global queue
|
||||
// If the local queue of the current worker is full, push the task into the
|
||||
// global queue
|
||||
self.global.push_back(task);
|
||||
true
|
||||
}
|
||||
@@ -293,7 +294,8 @@ impl MultiThreadScheduler {
|
||||
|
||||
// There is no task in the local queue or the global queue, so we try to steal
|
||||
// tasks from another worker's local queue.
|
||||
// The number of stealing worker should be less than half of the total worker number.
|
||||
// The number of stealing worker should be less than half of the total worker
|
||||
// number.
|
||||
if !worker_inner.is_searching {
|
||||
let (_, num_searching) = self.record.load_state();
|
||||
if num_searching * 2 < self.num_workers {
|
||||
@@ -513,17 +515,19 @@ impl AsyncPoolSpawner {
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// Users need to guarantee that the future will remember lifetime and thus compiler will capture
|
||||
/// lifetime issues, or the future will complete when its context remains valid. If not, currently
|
||||
/// Users need to guarantee that the future will remember lifetime and thus
|
||||
/// compiler will capture lifetime issues, or the future will complete
|
||||
/// when its context remains valid. If not, currently
|
||||
/// runtime initialization will cause memory error.
|
||||
///
|
||||
/// ## Memory issue example
|
||||
/// No matter using which type (current / multi thread) of runtime, the following code can compile.
|
||||
/// When the variable `slice` gets released when the function ends, any handles returned from
|
||||
/// this function rely on a dangled pointer.
|
||||
/// No matter using which type (current / multi thread) of runtime, the
|
||||
/// following code can compile. When the variable `slice` gets released
|
||||
/// when the function ends, any handles returned from this function rely
|
||||
/// on a dangled pointer.
|
||||
///
|
||||
/// ```no run
|
||||
/// fn err_example(runtime: &Runtime) -> JoinHandle<()> {
|
||||
/// fn err_example(runtime: &Runtime) -> JoinHandle<()> {
|
||||
/// let builder = TaskBuilder::default();
|
||||
/// let mut slice = [1, 2, 3, 4, 5];
|
||||
/// let borrow = &mut slice;
|
||||
@@ -566,7 +570,8 @@ impl AsyncPoolSpawner {
|
||||
}
|
||||
|
||||
/// Waits 3 seconds for threads to finish before releasing the async pool.
|
||||
/// If threads could not finish before releasing, there could be possible memory leak.
|
||||
/// If threads could not finish before releasing, there could be possible
|
||||
/// memory leak.
|
||||
fn release_wait(&self) -> Result<(), ()> {
|
||||
self.exe_mng_info.cancel();
|
||||
let pair = self.inner.shutdown_handle.clone();
|
||||
@@ -599,15 +604,8 @@ impl AsyncPoolSpawner {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::builder::RuntimeBuilder;
|
||||
use crate::executor::async_pool::{get_cpu_core, AsyncPoolSpawner, MultiThreadScheduler};
|
||||
|
||||
use crate::executor::parker::Parker;
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::Driver;
|
||||
use crate::task::{Task, TaskBuilder, VirtualTableType};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::Ordering::{Acquire, Release};
|
||||
@@ -616,6 +614,13 @@ mod test {
|
||||
use std::task::{Context, Poll};
|
||||
use std::thread::spawn;
|
||||
|
||||
use crate::builder::RuntimeBuilder;
|
||||
use crate::executor::async_pool::{get_cpu_core, AsyncPoolSpawner, MultiThreadScheduler};
|
||||
use crate::executor::parker::Parker;
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::Driver;
|
||||
use crate::task::{Task, TaskBuilder, VirtualTableType};
|
||||
|
||||
pub struct TestFuture {
|
||||
value: usize,
|
||||
total: usize,
|
||||
@@ -645,14 +650,11 @@ mod test {
|
||||
create_new().await
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::new()
|
||||
* @brief 描述测试用例执行
|
||||
* 1、Creates a ExecutorMsgInfo with thread number 1
|
||||
* 2、Creates a ExecutorMsgInfo with thread number 2
|
||||
* @expect 对比创建完成后的参数,应当与所期待值相同
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::new()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Creates a ExecutorMsgInfo with thread number 1
|
||||
/// 2. Creates a ExecutorMsgInfo with thread number 2
|
||||
#[test]
|
||||
fn ut_executor_mng_info_new_001() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -674,16 +676,11 @@ mod test {
|
||||
assert_eq!(executor_mng_info.handles.read().unwrap().capacity(), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::create_local_queues() UT test
|
||||
* @design No invalid value in the input, no exception branch, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、index set to 0, check the return value
|
||||
* 2、index set to ExecutorMngInfo.inner.total, check the return value
|
||||
* @expect Compare the parameters after creation, they should be the same as the expected value
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::create_local_queues()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. index set to 0, check the return value
|
||||
/// 2. index set to ExecutorMngInfo.inner.total, check the return value
|
||||
#[test]
|
||||
fn ut_executor_mng_info_create_local_queues() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -705,16 +702,11 @@ mod test {
|
||||
assert!(local_run_queue_info.is_empty());
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::enqueue() UT test
|
||||
* @design No invalid value in the input, no exception branch, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、index set to 0, check the return value
|
||||
* 2、index set to ExecutorMngInfo.inner.total, check the return value
|
||||
* @expect Compare the parameters after creation, they should be the same as the expected value
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::enqueue()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. index set to 0, check the return value
|
||||
/// 2. index set to ExecutorMngInfo.inner.total, check the return value
|
||||
#[test]
|
||||
fn ut_executor_mng_info_enqueue() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -742,16 +734,11 @@ mod test {
|
||||
assert!(!executor_mng_info.has_no_work());
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::is_cancel() UT test
|
||||
* @design No invalid value in the input, no exception branch, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、The is_cancel value is set to true to check the return value
|
||||
* 2、The is_cancel value is set to false to check the return value
|
||||
* @expect Compare the parameters after creation, they should be the same as the expected value
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::is_cancel()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. The is_cancel value is set to true to check the return value
|
||||
/// 2. The is_cancel value is set to false to check the return value
|
||||
#[test]
|
||||
fn ut_executor_mng_info_is_cancel() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -767,15 +754,10 @@ mod test {
|
||||
assert!(executor_mng_info.is_cancel());
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::set_cancel() UT test
|
||||
* @design No invalid value in the input, no exception branch, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Check if the is_cancel parameter becomes true after set_cancel
|
||||
* @expect Compare the parameters after creation, they should be the same as the expected value
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::set_cancel()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Check if the is_cancel parameter becomes true after set_cancel
|
||||
#[test]
|
||||
fn ut_executor_mng_info_set_cancel() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -790,15 +772,10 @@ mod test {
|
||||
assert!(executor_mng_info.is_cancel.load(Acquire));
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::cancel() UT test
|
||||
* @design No invalid values in the input, the existence of exception branches, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Check if the is_cancel parameter becomes true after set_cancel
|
||||
* @expect Compare the parameters after creation, they should be the same as the expected value
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::cancel()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Check if the is_cancel parameter becomes true after set_cancel
|
||||
#[test]
|
||||
fn ut_executor_mng_info_cancel() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -831,15 +808,11 @@ mod test {
|
||||
assert_eq!(*flag.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::wake_up_all() UT test
|
||||
* @design No invalid value in the input, no exception branch, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Constructs an environment to check if all threads are woken up and executed via thread hooks
|
||||
* @expect Here, if the function is not correct, the thread will stay parked, if the function is correct, it will execute normally
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::wake_up_all()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Constructs an environment to check if all threads are woken up and
|
||||
/// executed via thread hooks.
|
||||
#[test]
|
||||
fn ut_executor_mng_info_wake_up_all() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -874,15 +847,11 @@ mod test {
|
||||
assert_eq!(*flag.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::wake_up_rand_one() UT test
|
||||
* @design No invalid values in the input, the existence of exception branches, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Constructs an environment to check if a thread is woken up and executed by a thread hook
|
||||
* @expect Here, if the function is not correct, the thread will stay parked, if the function is correct, it will execute normally
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::wake_up_rand_one()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Constructs an environment to check if a thread is woken up and
|
||||
/// executed by a thread hook.
|
||||
#[test]
|
||||
fn ut_executor_mng_info_wake_up_rand_one() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -918,15 +887,11 @@ mod test {
|
||||
assert_eq!(*flag.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::wake_up_if_one_task_left() UT test
|
||||
* @design No invalid values in the input, the existence of exception branches, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Constructs the environment, checks if there are still tasks, and if so, wakes up a thread to continue working
|
||||
* @expect Here, if the function is not correct, the thread will stay parked, if the function is correct, it will execute normally
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::wake_up_if_one_task_left()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Constructs the environment, checks if there are still tasks, and if
|
||||
/// so, wakes up a thread to continue working.
|
||||
#[test]
|
||||
fn ut_executor_mng_info_wake_up_if_one_task_left() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -978,15 +943,12 @@ mod test {
|
||||
assert_eq!(*flag.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title ExecutorMngInfo::from_woken_to_sleep() UT test
|
||||
* @design No invalid values in the input, the existence of exception branches, direct check function, return value
|
||||
* @precon Use ExecutorMngInfo::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Construct the environment and set the state of the specified thread to park state. If the last thread is in park state, check whether there is a task, and if so, wake up this thread.
|
||||
* @expect Here, if the function is not correct, the thread will stay parked, if the function is correct, it will execute normally
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for ExecutorMngInfo::from_woken_to_sleep()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Construct the environment and set the state of the specified thread
|
||||
/// to park state. If the last thread is in park state, check whether
|
||||
/// there is a task, and if so, wake up this thread.
|
||||
#[test]
|
||||
fn ut_from_woken_to_sleep() {
|
||||
#[cfg(feature = "net")]
|
||||
@@ -1035,15 +997,10 @@ mod test {
|
||||
assert_eq!(*flag.lock().unwrap(), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title AsyncPoolSpawner::new() UT test
|
||||
* @design No invalid values in the input, the existence of exception branches, direct check function, return value
|
||||
* @precon Use AsyncPoolSpawner::new(), get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Verify the parameters of the initialization completion
|
||||
* @expect Here, if the function is not correct, the thread will stay parked, if the function is correct, it will execute normally
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for AsyncPoolSpawner::new()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Verify the parameters of the initialization completion
|
||||
#[test]
|
||||
fn ut_async_pool_spawner_new() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread();
|
||||
@@ -1065,7 +1022,7 @@ mod test {
|
||||
assert!(!async_pool_spawner.exe_mng_info.is_cancel.load(Acquire));
|
||||
}
|
||||
|
||||
/// UT test for `create_async_thread_pool`.
|
||||
/// UT test cases for `create_async_thread_pool`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Create an async_pool_spawner with `is_affinity` setting to false
|
||||
@@ -1077,7 +1034,7 @@ mod test {
|
||||
let _ = AsyncPoolSpawner::new(&thread_pool_builder.is_affinity(false));
|
||||
}
|
||||
|
||||
/// UT test for `UnboundedSender`.
|
||||
/// UT test cases for `UnboundedSender`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Create an async_pool_spawner with `is_affinity` setting to true
|
||||
|
||||
@@ -12,20 +12,19 @@
|
||||
// limitations under the License.
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::future::Future;
|
||||
use std::option::Option::Some;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Condvar, Mutex, Weak};
|
||||
use std::task::{Context, Poll};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::builder::{CallbackHook, CommonBuilder};
|
||||
use crate::error::{ErrorKind, ScheduleError};
|
||||
use crate::executor::PlaceholderScheduler;
|
||||
use crate::task::TaskBuilder;
|
||||
use crate::task::VirtualTableType;
|
||||
use crate::task::{TaskBuilder, VirtualTableType};
|
||||
use crate::{task, JoinHandle};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pub(crate) const BLOCKING_THREAD_QUIT_WAIT_TIME: Duration = Duration::from_secs(3);
|
||||
|
||||
@@ -358,25 +357,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::builder::RuntimeBuilder;
|
||||
use crate::executor::blocking_pool::BlockPoolSpawner;
|
||||
use crate::executor::PlaceholderScheduler;
|
||||
use crate::task::Task;
|
||||
use crate::task::VirtualTableType;
|
||||
use std::sync::Weak;
|
||||
use std::time::Duration;
|
||||
|
||||
/*
|
||||
* @title BlockPoolSpawner::new() UT test
|
||||
* @design The function has no invalid values in the input, no exception branch, direct check function, return value
|
||||
* @precon Use BlockPoolSpawner::new(), Get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、Checking the parameters after initialization is completed
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
use crate::builder::RuntimeBuilder;
|
||||
use crate::executor::blocking_pool::BlockPoolSpawner;
|
||||
use crate::executor::PlaceholderScheduler;
|
||||
use crate::task::{Task, VirtualTableType};
|
||||
|
||||
/// UT test cases for BlockPoolSpawner::new()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Checking the parameters after initialization is completed.
|
||||
#[test]
|
||||
fn ut_blocking_pool_new() {
|
||||
let thread_pool_builder =
|
||||
@@ -400,17 +394,17 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title BlockPoolSpawner::shutdown() UT test
|
||||
* @design The function entry has no invalid value, there is an exception branch, direct check function, return value
|
||||
* @precon Use BlockPoolSpawner::new(), Get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、When shared.shutdown is false, the thread is safely exited without a timeout
|
||||
* 2、When shared.shutdown is false, the thread is not safely exited in case of timeout
|
||||
* 3、When shared.shutdown is true, BlockPoolSpawner::shutdown returns directly, representing that the blocking thread pool has safely exited
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for BlockPoolSpawner::shutdown()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. When shared.shutdown is false, the thread is safely exited without a
|
||||
/// timeout
|
||||
/// 2. When shared.shutdown is false, the thread is not safely exited in
|
||||
/// case of timeout
|
||||
/// 3. When shared.shutdown is true, BlockPoolSpawner::shutdown returns
|
||||
/// directly, representing that the blocking thread pool has safely
|
||||
/// exited
|
||||
|
||||
#[test]
|
||||
fn ut_blocking_pool_shutdown() {
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread();
|
||||
@@ -438,17 +432,14 @@ mod test {
|
||||
assert!(!blocking_pool.shutdown(Duration::from_secs(0)));
|
||||
}
|
||||
|
||||
/*
|
||||
* @title BlockPoolSpawner::create_permanent_threads() UT test
|
||||
* @design The function has no input parameters, there is an exception branch, direct check function, return value
|
||||
* @precon Use BlockPoolSpawner::new(), Get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、self.inner.is_permanent == true, self.inner.worker_name.clone() != None, self.inner.stack_size != None
|
||||
* 2、self.inner.is_permanent == true, self.inner.worker_name.clone() == None, self.inner.stack_size == None
|
||||
* 3、self.inner.is_permanent == false
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed. Compare whether the naming under different branches corresponds to each other.
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for BlockPoolSpawner::create_permanent_threads()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. self.inner.is_permanent == true, self.inner.worker_name.clone() !=
|
||||
/// None, self.inner.stack_size != None
|
||||
/// 2. self.inner.is_permanent == true, self.inner.worker_name.clone() ==
|
||||
/// None, self.inner.stack_size == None
|
||||
/// 3. self.inner.is_permanent == false
|
||||
#[test]
|
||||
fn ut_blocking_pool_spawner_create_permanent_threads() {
|
||||
let thread_pool_builder =
|
||||
@@ -511,24 +502,26 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title BlockPoolSpawner::spawn() UT test
|
||||
* @design The function has no input parameters, there is an exception branch, direct check function, return value
|
||||
* @precon Use BlockPoolSpawner::new(), Get its creation object
|
||||
* @brief Describe test case execution
|
||||
* 1、shared.shutdown == true, return directly.
|
||||
* 2、shared.shutdown == false, shared.idle_thread_num != 0
|
||||
* 3、shared.shutdown == false, shared.idle_thread_num == 0, shared.total_thread_num == self.inner.max_pool_size
|
||||
* 4、shared.shutdown == false, shared.idle_thread_num == 0, shared.total_thread_num != self.inner.max_pool_size, self.inner.worker_name.clone() != None
|
||||
* 5、shared.shutdown == false, shared.idle_thread_num == 0, shared.total_thread_num != self.inner.max_pool_size, self.inner.worker_name.clone() == None
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed. Compare whether the naming under different branches corresponds to each other.
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for BlockPoolSpawner::spawn()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. shared.shutdown == true, return directly.
|
||||
/// 2. shared.shutdown == false, shared.idle_thread_num != 0
|
||||
/// 3. shared.shutdown == false, shared.idle_thread_num == 0,
|
||||
/// shared.total_thread_num == self.inner.max_pool_size
|
||||
/// 4. shared.shutdown == false, shared.idle_thread_num == 0,
|
||||
/// shared.total_thread_num != self.inner.max_pool_size,
|
||||
/// self.inner.worker_name.clone() != None
|
||||
/// 5. shared.shutdown == false, shared.idle_thread_num == 0,
|
||||
/// shared.total_thread_num != self.inner.max_pool_size,
|
||||
/// self.inner.worker_name.clone() == None
|
||||
|
||||
#[test]
|
||||
fn ut_blocking_pool_spawner_spawn() {
|
||||
use std::thread::sleep;
|
||||
|
||||
use crate::executor::blocking_pool::BlockingTask;
|
||||
use crate::task::TaskBuilder;
|
||||
use std::thread::sleep;
|
||||
|
||||
let thread_pool_builder = RuntimeBuilder::new_multi_thread();
|
||||
let blocking_pool = BlockPoolSpawner::new(&thread_pool_builder.common);
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::cfg_io;
|
||||
use crate::executor::Schedule;
|
||||
use crate::task::{JoinHandle, Task, TaskBuilder, VirtualTableType};
|
||||
use std::collections::VecDeque;
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
@@ -22,6 +19,10 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering::{Acquire, Release};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
use crate::cfg_io;
|
||||
use crate::executor::Schedule;
|
||||
use crate::task::{JoinHandle, Task, TaskBuilder, VirtualTableType};
|
||||
cfg_io!(
|
||||
use std::time::Duration;
|
||||
use crate::net::Driver;
|
||||
@@ -183,7 +184,7 @@ impl CurrentThreadSpawner {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
macro_rules! cfg_sync {
|
||||
($($item:item)*) => {
|
||||
@@ -201,12 +202,13 @@ mod test {
|
||||
)*
|
||||
}
|
||||
}
|
||||
use crate::executor::current_thread::CurrentThreadSpawner;
|
||||
use crate::task::{yield_now, TaskBuilder};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::executor::current_thread::CurrentThreadSpawner;
|
||||
use crate::task::{yield_now, TaskBuilder};
|
||||
|
||||
cfg_sync! {
|
||||
use crate::sync::Waiter;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
@@ -298,15 +300,15 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
/// UT test for `spawn()`.
|
||||
///
|
||||
/// # Title
|
||||
/// ut_current_thread_block_on
|
||||
/// UT test cases for `spawn()`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Check the running status of tasks in the queue when the yield task is awakened once.
|
||||
/// 2.Check the running status of tasks in the queue when the yield task is awakened twice.
|
||||
/// 3.Check the running status of tasks in the queue when the yield task is awakened three times.
|
||||
/// 1. Check the running status of tasks in the queue when the yield task is
|
||||
/// awakened once.
|
||||
/// 2. Check the running status of tasks in the queue when the yield task is
|
||||
/// awakened twice.
|
||||
/// 3. Check the running status of tasks in the queue when the yield task is
|
||||
/// awakened three times.
|
||||
#[test]
|
||||
fn ut_current_thread_spawn() {
|
||||
let spawner = CurrentThreadSpawner::new();
|
||||
@@ -328,15 +330,15 @@ mod test {
|
||||
assert_eq!(spawner.scheduler.inner.lock().unwrap().len(), 2);
|
||||
}
|
||||
|
||||
/// UT test for `block_on()`.
|
||||
///
|
||||
/// # Title
|
||||
/// ut_current_thread_block_on
|
||||
/// UT test cases for `block_on()`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Check the running status of tasks in the queue when the yield task is awakened once.
|
||||
/// 2.Check the running status of tasks in the queue when the yield task is awakened twice.
|
||||
/// 3.Check the running status of tasks in the queue when the yield task is awakened three times.
|
||||
/// 1. Check the running status of tasks in the queue when the yield task is
|
||||
/// awakened once.
|
||||
/// 2. Check the running status of tasks in the queue when the yield task is
|
||||
/// awakened twice.
|
||||
/// 3. Check the running status of tasks in the queue when the yield task is
|
||||
/// awakened three times.
|
||||
#[test]
|
||||
fn ut_current_thread_block_on() {
|
||||
let spawner = CurrentThreadSpawner::new();
|
||||
@@ -358,14 +360,13 @@ mod test {
|
||||
assert_eq!(spawner.scheduler.inner.lock().unwrap().len(), 0);
|
||||
}
|
||||
|
||||
/// UT test for `spawn()` and `block_on()`.
|
||||
///
|
||||
/// # Title
|
||||
/// ut_current_thread_run_queue
|
||||
/// UT test cases for `spawn()` and `block_on()`.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Spawn two tasks before the blocked task running and check the status of two tasks.
|
||||
/// 2.Spawn two tasks after the blocked task running and check the status of two tasks.
|
||||
/// 1. Spawn two tasks before the blocked task running and check the status
|
||||
/// of two tasks.
|
||||
/// 2. Spawn two tasks after the blocked task running and check the status
|
||||
/// of two tasks.
|
||||
#[test]
|
||||
#[cfg(feature = "sync")]
|
||||
fn ut_current_thread_run_queue() {
|
||||
@@ -430,14 +431,11 @@ mod test {
|
||||
});
|
||||
}
|
||||
|
||||
/// UT test for io tasks.
|
||||
///
|
||||
/// # Title
|
||||
/// ut_current_thread_io
|
||||
/// UT test cases for io tasks.
|
||||
///
|
||||
/// # Brief
|
||||
/// 1.Spawns a tcp server to read and write data for three times.
|
||||
/// 2.Spawns a tcp client to read and write data for three times.
|
||||
/// 1. Spawns a tcp server to read and write data for three times.
|
||||
/// 2. Spawns a tcp client to read and write data for three times.
|
||||
#[test]
|
||||
#[cfg(feature = "net")]
|
||||
fn ut_current_thread_io() {
|
||||
|
||||
@@ -21,18 +21,18 @@ pub(crate) mod current_thread;
|
||||
|
||||
#[cfg(any(feature = "time", feature = "net"))]
|
||||
pub(crate) mod netpoller;
|
||||
use std::future::Future;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::Once;
|
||||
|
||||
use crate::builder::multi_thread_builder::GLOBAL_BUILDER;
|
||||
use crate::builder::{initialize_blocking_spawner, RuntimeBuilder};
|
||||
use crate::executor::blocking_pool::BlockPoolSpawner;
|
||||
#[cfg(feature = "current_thread_runtime")]
|
||||
use crate::executor::current_thread::CurrentThreadSpawner;
|
||||
use crate::macros::{cfg_ffrt, cfg_not_ffrt};
|
||||
use crate::task::TaskBuilder;
|
||||
use crate::{JoinHandle, Task};
|
||||
use std::future::Future;
|
||||
|
||||
use crate::builder::multi_thread_builder::GLOBAL_BUILDER;
|
||||
#[cfg(feature = "current_thread_runtime")]
|
||||
use crate::executor::current_thread::CurrentThreadSpawner;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::Once;
|
||||
cfg_ffrt! {
|
||||
use crate::builder::initialize_ffrt_spawner;
|
||||
use crate::ffrt::spawner::spawn;
|
||||
@@ -73,13 +73,14 @@ pub(crate) enum AsyncHandle {
|
||||
/// Runtime struct.
|
||||
///
|
||||
/// # If `multi_instance_runtime` feature is turned on
|
||||
/// There will be multiple runtime executors, initializing from user settings in `RuntimeBuilder`.
|
||||
/// There will be multiple runtime executors, initializing from user settings in
|
||||
/// `RuntimeBuilder`.
|
||||
///
|
||||
/// # If `multi_instance_runtime` feature is turned off
|
||||
/// There will be only *ONE* runtime executor singleton inside one process.
|
||||
/// The async and blocking pools working when calling methods of this struct are stored in the
|
||||
/// global static executor instance. Here, keep the empty struct for compatibility
|
||||
/// and possibility for function extension in the future.
|
||||
/// The async and blocking pools working when calling methods of this struct are
|
||||
/// stored in the global static executor instance. Here, keep the empty struct
|
||||
/// for compatibility and possibility for function extension in the future.
|
||||
pub struct Runtime {
|
||||
pub(crate) async_spawner: AsyncHandle,
|
||||
}
|
||||
@@ -158,13 +159,14 @@ impl Runtime {
|
||||
impl Runtime {
|
||||
/// Spawns a future onto the runtime, returning a [`JoinHandle`] for it.
|
||||
///
|
||||
/// The future will be later polled by the executor, which is usually implemented as a thread
|
||||
/// pool. The executor will run the future util finished.
|
||||
/// The future will be later polled by the executor, which is usually
|
||||
/// implemented as a thread pool. The executor will run the future util
|
||||
/// finished.
|
||||
///
|
||||
/// Awaits on the JoinHandle will return the result of the future, but users don't have to
|
||||
/// `.await` the `JoinHandle` in order to run the future, since the future will be executed
|
||||
/// in the background once it's spawned. Dropping the JoinHandle will throw away the returned
|
||||
/// value.
|
||||
/// Awaits on the JoinHandle will return the result of the future, but users
|
||||
/// don't have to `.await` the `JoinHandle` in order to run the future,
|
||||
/// since the future will be executed in the background once it's
|
||||
/// spawned. Dropping the JoinHandle will throw away the returned value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -212,8 +214,8 @@ impl Runtime {
|
||||
|
||||
/// Spawns the provided function or closure onto the runtime.
|
||||
///
|
||||
/// It's usually used for cpu-bounded computation that does not return pending and takes a
|
||||
/// relatively long time.
|
||||
/// It's usually used for cpu-bounded computation that does not return
|
||||
/// pending and takes a relatively long time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -240,13 +242,13 @@ impl Runtime {
|
||||
crate::spawn::spawn_blocking(&TaskBuilder::new(), task)
|
||||
}
|
||||
|
||||
/// Blocks the current thread and runs the given future (usually a JoinHandle) to completion,
|
||||
/// and gets its return value.
|
||||
/// Blocks the current thread and runs the given future (usually a
|
||||
/// JoinHandle) to completion, and gets its return value.
|
||||
///
|
||||
/// Any code after the `block_on` will be executed once the future is done.
|
||||
///
|
||||
/// Don't use this method on an asynchronous environment, since it will block the worker
|
||||
/// thread and may cause deadlock.
|
||||
/// Don't use this method on an asynchronous environment, since it will
|
||||
/// block the worker thread and may cause deadlock.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
use crate::time::Driver as TimerDriver;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
use crate::time::Driver as TimerDriver;
|
||||
|
||||
#[cfg(any(not(feature = "ffrt"), all(feature = "net", feature = "ffrt")))]
|
||||
const NET_POLL_INTERVAL_TIME: std::time::Duration = std::time::Duration::from_millis(10);
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::{Driver, Handle};
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
use std::thread;
|
||||
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::{Driver, Handle};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Parker {
|
||||
inner: Arc<Inner>,
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// Schedule strategy implementation, includes FIFO LIFO priority and work-stealing
|
||||
/// work-stealing strategy include stealing half of every worker or the largest amount of worker
|
||||
use crate::task::Task;
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::collections::linked_list::LinkedList;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
|
||||
use std::sync::atomic::{AtomicU16, AtomicUsize};
|
||||
use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{cmp, ptr};
|
||||
|
||||
/// Schedule strategy implementation, includes FIFO LIFO priority and
|
||||
/// work-stealing work-stealing strategy include stealing half of every worker
|
||||
/// or the largest amount of worker
|
||||
use crate::task::Task;
|
||||
|
||||
unsafe fn non_atomic_load(data: &AtomicU16) -> u16 {
|
||||
ptr::read(data as *const AtomicU16 as *const u16)
|
||||
}
|
||||
@@ -247,8 +247,8 @@ impl InnerBuffer {
|
||||
let mut count = loop {
|
||||
let (src_front_steal, src_front_real) = unwrap(src_prev_front);
|
||||
|
||||
// if these two values are not equal, it means another worker has stolen from this
|
||||
// queue, therefore abort this steal.
|
||||
// if these two values are not equal, it means another worker has stolen from
|
||||
// this queue, therefore abort this steal.
|
||||
if src_front_steal != src_front_real {
|
||||
return None;
|
||||
};
|
||||
@@ -422,13 +422,8 @@ impl GlobalQueue {
|
||||
}
|
||||
|
||||
#[cfg(feature = "multi_instance_runtime")]
|
||||
#[cfg(all(test))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::executor::async_pool::MultiThreadScheduler;
|
||||
use crate::executor::queue::{unwrap, GlobalQueue, InnerBuffer, LocalQueue, LOCAL_QUEUE_CAP};
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::Driver;
|
||||
use crate::task::{Task, TaskBuilder, VirtualTableType};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::Ordering::Acquire;
|
||||
@@ -436,6 +431,12 @@ mod test {
|
||||
use std::task::{Context, Poll};
|
||||
use std::thread::park;
|
||||
|
||||
use crate::executor::async_pool::MultiThreadScheduler;
|
||||
use crate::executor::queue::{unwrap, GlobalQueue, InnerBuffer, LocalQueue, LOCAL_QUEUE_CAP};
|
||||
#[cfg(feature = "net")]
|
||||
use crate::net::Driver;
|
||||
use crate::task::{Task, TaskBuilder, VirtualTableType};
|
||||
|
||||
impl InnerBuffer {
|
||||
fn len(&self) -> u16 {
|
||||
let front = self.front.load(Acquire);
|
||||
@@ -468,8 +469,8 @@ mod test {
|
||||
type Output = usize;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
if self.total > self.value {
|
||||
//unsafe {
|
||||
//Pin::get_unchecked_mut(self).value += 1;
|
||||
// unsafe {
|
||||
// Pin::get_unchecked_mut(self).value += 1;
|
||||
|
||||
//}
|
||||
self.get_mut().value += 1;
|
||||
@@ -495,31 +496,26 @@ mod test {
|
||||
ut_inner_buffer_steal_into();
|
||||
}
|
||||
|
||||
/*
|
||||
* @title InnerBuffer::new() UT test
|
||||
* @design The function has no invalid values in the input, no exception branch, direct check function, return value
|
||||
* @precon After calling InnerBuffer::new() function, get its created object
|
||||
* @brief Describe test case execution
|
||||
* 1、Checking the parameters after initialization is completed
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
/// UT test cases for InnerBuffer::new()
|
||||
///
|
||||
/// # Brief
|
||||
/// 1. Checking the parameters after initialization is completed
|
||||
fn ut_inner_buffer_new() {
|
||||
let inner_buffer = InnerBuffer::new(LOCAL_QUEUE_CAP as u16);
|
||||
assert_eq!(inner_buffer.cap, LOCAL_QUEUE_CAP as u16);
|
||||
assert_eq!(inner_buffer.buffer.len(), LOCAL_QUEUE_CAP);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title InnerBuffer::is_empty() UT test
|
||||
* @design The function has no invalid values in the input, no exception branch, direct check function, return value
|
||||
* @precon After calling InnerBuffer::new() function, get its created object
|
||||
* @brief Describe test case execution
|
||||
* 1、Checking the parameters after initialization is completed
|
||||
* 2、After entering a task into the queue space, determine again whether it is empty or not, and it should be non-empty
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
// InnerBuffer::is_empty() UT test cases
|
||||
//
|
||||
|
||||
/// # Brief
|
||||
// case execution 1. Checking the parameters after initialization is
|
||||
// completed 2. After entering a task into the queue space,
|
||||
// determine again whether it is empty or not, and it should be non-empty
|
||||
//
|
||||
// property value should be related to the entry after the initialization is
|
||||
// completed
|
||||
fn ut_inner_buffer_is_empty() {
|
||||
let inner_buffer = InnerBuffer::new(LOCAL_QUEUE_CAP as u16);
|
||||
assert!(inner_buffer.is_empty());
|
||||
@@ -546,17 +542,17 @@ mod test {
|
||||
assert!(!inner_buffer.is_empty());
|
||||
}
|
||||
|
||||
/*
|
||||
* @title InnerBuffer::len() UT test
|
||||
* @design The function entry has no invalid value, there is an exception branch, direct check function, return value
|
||||
* @precon After calling InnerBuffer::new() function, get its created object
|
||||
* @brief Describe test case execution
|
||||
* 1、Checking the parameters after initialization is completed
|
||||
* 2、Insert tasks up to their capacity into the local queue, checking the local queue length
|
||||
* 3、Insert tasks into the local queue that exceed its capacity, checking the local queue length as well as the global queue length
|
||||
* @expect The function entry has no invalid value, no exception branch, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
// InnerBuffer::len() UT test cases
|
||||
//
|
||||
|
||||
/// # Brief
|
||||
// case execution 1. Checking the parameters after initialization is
|
||||
// completed 2. Insert tasks up to their capacity into the local
|
||||
// queue, checking the local queue length 3. Insert tasks into the
|
||||
// local queue that exceed its capacity, checking the local queue length as well
|
||||
// as the global queue length
|
||||
// value, no exception branch, and the property value should be related to the
|
||||
// entry after the initialization is completed
|
||||
fn ut_inner_buffer_len() {
|
||||
let inner_buffer = InnerBuffer::new(LOCAL_QUEUE_CAP as u16);
|
||||
assert_eq!(inner_buffer.len(), 0);
|
||||
@@ -605,18 +601,19 @@ mod test {
|
||||
assert_eq!(global_queue.len.load(Acquire), 1 + LOCAL_QUEUE_CAP / 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title InnerBuffer::push_back() UT test
|
||||
* @design The function entry has no invalid value, there is an exception branch, direct check function, return value
|
||||
* @precon After calling InnerBuffer::new() function, get its created object
|
||||
* @brief Describe test case execution
|
||||
* 1、Insert tasks up to capacity into the local queue, verifying that they are functionally correct
|
||||
* 2、Insert tasks that exceed the capacity into the local queue and verify that they are functionally correct
|
||||
* @expect The function entry has no invalid value, there is an exception branch, after the initialization is completed the property value should be related to the entry
|
||||
* @auto true
|
||||
*/
|
||||
// InnerBuffer::push_back() UT test cases
|
||||
//
|
||||
|
||||
/// # Brief
|
||||
// case execution 1. Insert tasks up to capacity into the local
|
||||
// queue, verifying that they are functionally correct 2. Insert
|
||||
// tasks that exceed the capacity into the local queue and verify that they are
|
||||
// functionally correct
|
||||
// there is an exception branch, after the initialization is completed the
|
||||
// property value should be related to the entry
|
||||
fn ut_inner_buffer_push_back() {
|
||||
// 1、Insert tasks up to capacity into the local queue, verifying that they are functionally correct
|
||||
// 1. Insert tasks up to capacity into the local queue, verifying that they are
|
||||
// functionally correct
|
||||
let local_queue = LocalQueue::new();
|
||||
let global_queue = GlobalQueue::new();
|
||||
|
||||
@@ -656,7 +653,8 @@ mod test {
|
||||
|
||||
assert_eq!(local_queue.len(), 256);
|
||||
|
||||
// 2、Insert tasks that exceed the capacity into the local queue and verify that they are functionally correct
|
||||
// 2. Insert tasks that exceed the capacity into the local queue and verify that
|
||||
// they are functionally correct
|
||||
let local_queue = LocalQueue::new();
|
||||
let global_queue = GlobalQueue::new();
|
||||
|
||||
@@ -700,24 +698,28 @@ mod test {
|
||||
assert_eq!(global_queue.len.load(Acquire), 1 + LOCAL_QUEUE_CAP / 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* @title InnerBuffer::pop_front() UT test
|
||||
* @design The function entry has no invalid value, there is an exception branch, direct check function, return value
|
||||
* @precon After calling InnerBuffer::new() function, get its created object
|
||||
* @brief Describe test case execution
|
||||
* 1、Multi-threaded take out task operation with empty local queue, check if the function is correct
|
||||
* 2、If the local queue is not empty, multi-threaded take out operations up to the number of existing tasks and check if the function is correct
|
||||
* 3、If the local queue is not empty, the multi-threaded operation to take out more than the number of existing tasks, check whether the function is correct
|
||||
* @expect The function entry has no invalid value, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
// InnerBuffer::pop_front() UT test cases
|
||||
//
|
||||
|
||||
/// # Brief
|
||||
// case execution 1. Multi-threaded take out task operation with
|
||||
// empty local queue, check if the function is correct 2. If the
|
||||
// local queue is not empty, multi-threaded take out operations up to the number
|
||||
// of existing tasks and check if the function is correct 3. If the
|
||||
// local queue is not empty, the multi-threaded operation to take out more than
|
||||
// the number of existing tasks, check whether the function is correct
|
||||
//
|
||||
// should be related to the entry after the initialization is completed
|
||||
//
|
||||
fn ut_inner_buffer_pop_front() {
|
||||
// 1、Multi-threaded take out task operation with empty local queue, check if the function is correct
|
||||
// 1. Multi-threaded take out task operation with empty local queue, check if
|
||||
// the function is correct
|
||||
let local_queue = LocalQueue::new();
|
||||
let global_queue = GlobalQueue::new();
|
||||
assert!(local_queue.pop_front().is_none());
|
||||
|
||||
// 2、If the local queue is not empty, multi-threaded take out operations up to the number of existing tasks and check if the function is correct
|
||||
// 2. If the local queue is not empty, multi-threaded take out operations up to
|
||||
// the number of existing tasks and check if the function is correct
|
||||
let local_queue = Arc::new(LocalQueue::new());
|
||||
let builder = TaskBuilder::new();
|
||||
|
||||
@@ -759,7 +761,8 @@ mod test {
|
||||
thread_two.join().expect("failed");
|
||||
assert!(local_queue.is_empty());
|
||||
|
||||
// 3、If the local queue is not empty, the multi-threaded operation to take out more than the number of existing tasks, check whether the function is correct
|
||||
// 3. If the local queue is not empty, the multi-threaded operation to take out
|
||||
// more than the number of existing tasks, check whether the function is correct
|
||||
let local_queue = Arc::new(LocalQueue::new());
|
||||
|
||||
#[cfg(feature = "net")]
|
||||
@@ -801,21 +804,29 @@ mod test {
|
||||
assert!(local_queue.is_empty());
|
||||
}
|
||||
|
||||
/*
|
||||
* @title InnerBuffer::steal_into() UT test
|
||||
* @design The function entry has no invalid value, there is an exception branch, direct check function, return value
|
||||
* @precon After calling InnerBuffer::new() function, get its created object
|
||||
* @brief Describe test case execution
|
||||
* 1、In the single-threaded case, the local queue has more than half the number of tasks, steal from other local queues, the number of steals is 0, check whether the function is completed
|
||||
* 2、In the single-threaded case, the number of tasks already in the local queue is not more than half, steal from other local queues, the number of steals is 0, check whether the function is completed
|
||||
* 3、In the single-threaded case, the number of tasks already in the local queue is not more than half, steal from other local queues, the number of steals is not 0, check whether the function is completed
|
||||
* 4、Multi-threaded case, other queues are doing take out operations, but steal from this queue to see if the function is completed
|
||||
* 5、In the multi-threaded case, other queues are being stolen by non-local queues, steal from that stolen queue and see if the function is completed
|
||||
* @expect The function entry has no invalid value, and the property value should be related to the entry after the initialization is completed
|
||||
* @auto true
|
||||
*/
|
||||
// InnerBuffer::steal_into() UT test cases
|
||||
//
|
||||
|
||||
/// # Brief
|
||||
// case execution 1. In the single-threaded case, the local queue
|
||||
// has more than half the number of tasks, steal from other local queues, the
|
||||
// number of steals is 0, check whether the function is completed
|
||||
// 2. In the single-threaded case, the number of tasks already in the
|
||||
// local queue is not more than half, steal from other local queues, the number
|
||||
// of steals is 0, check whether the function is completed 3. In the
|
||||
// single-threaded case, the number of tasks already in the local queue is not
|
||||
// more than half, steal from other local queues, the number of steals is not 0,
|
||||
// check whether the function is completed 4. Multi-threaded case,
|
||||
// other queues are doing take out operations, but steal from this queue to see
|
||||
// if the function is completed 5. In the multi-threaded case, other
|
||||
// queues are being stolen by non-local queues, steal from that stolen queue and
|
||||
// see if the function is completed
|
||||
// invalid value, and the property value should be related to the entry after
|
||||
// the initialization is completed
|
||||
fn ut_inner_buffer_steal_into() {
|
||||
// 1、In the single-threaded case, the local queue has more than half the number of tasks, steal from other local queues, the number of steals is 0, check whether the function is completed
|
||||
// 1. In the single-threaded case, the local queue has more than half the number
|
||||
// of tasks, steal from other local queues, the number of steals is 0, check
|
||||
// whether the function is completed
|
||||
let local_queue = LocalQueue::new();
|
||||
let other_local_queue = LocalQueue::new();
|
||||
let global_queue = GlobalQueue::new();
|
||||
@@ -858,13 +869,17 @@ mod test {
|
||||
|
||||
assert!(other_local_queue.steal_into(&local_queue).is_none());
|
||||
|
||||
// 2、In the single-threaded case, the number of tasks already in the local queue is not more than half, steal from other local queues, the number of steals is 0, check whether the function is completed
|
||||
// 2. In the single-threaded case, the number of tasks already in the local
|
||||
// queue is not more than half, steal from other local queues, the number of
|
||||
// steals is 0, check whether the function is completed
|
||||
let local_queue = LocalQueue::new();
|
||||
let other_local_queue = LocalQueue::new();
|
||||
|
||||
assert!(other_local_queue.steal_into(&local_queue).is_none());
|
||||
|
||||
// 3、In the single-threaded case, the number of tasks already in the local queue is not more than half, steal from other local queues, the number of steals is not 0, check whether the function is completed
|
||||
// 3. In the single-threaded case, the number of tasks already in the local
|
||||
// queue is not more than half, steal from other local queues, the number of
|
||||
// steals is not 0, check whether the function is completed
|
||||
let local_queue = LocalQueue::new();
|
||||
let other_local_queue = LocalQueue::new();
|
||||
let global_queue = GlobalQueue::new();
|
||||
@@ -890,7 +905,8 @@ mod test {
|
||||
assert_eq!(other_local_queue.len(), (LOCAL_QUEUE_CAP / 2) as u16);
|
||||
assert_eq!(local_queue.len(), (LOCAL_QUEUE_CAP / 2 - 1) as u16);
|
||||
|
||||
// 4、Multi-threaded case, other queues are doing take out operations, but steal from this queue to see if the function is completed
|
||||
// 4. Multi-threaded case, other queues are doing take out operations, but steal
|
||||
// from this queue to see if the function is completed
|
||||
let local_queue = Arc::new(LocalQueue::new());
|
||||
let local_queue_clone = local_queue.clone();
|
||||
|
||||
@@ -935,7 +951,8 @@ mod test {
|
||||
(LOCAL_QUEUE_CAP / 2) as u16
|
||||
);
|
||||
|
||||
// 5、In the multi-threaded case, other queues are being stolen by non-local queues, steal from that stolen queue and see if the function is completed
|
||||
// 5. In the multi-threaded case, other queues are being stolen by non-local
|
||||
// queues, steal from that stolen queue and see if the function is completed
|
||||
let local_queue_one = Arc::new(LocalQueue::new());
|
||||
let local_queue_one_clone = local_queue_one.clone();
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
///worker struct info and method
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::task::Waker;
|
||||
|
||||
/// worker struct info and method
|
||||
use crate::executor::async_pool::MultiThreadScheduler;
|
||||
use crate::executor::parker::Parker;
|
||||
use crate::executor::queue::LocalQueue;
|
||||
@@ -19,10 +24,6 @@ use crate::executor::queue::LocalQueue;
|
||||
use crate::net::Handle;
|
||||
use crate::task::yield_now::wake_yielded_tasks;
|
||||
use crate::task::Task;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::task::Waker;
|
||||
|
||||
thread_local! {
|
||||
pub(crate) static CURRENT_WORKER : Cell<* const ()> = Cell::new(ptr::null());
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::executor::PlaceholderScheduler;
|
||||
use crate::task::{JoinHandle, Task, VirtualTableType};
|
||||
use crate::TaskBuilder;
|
||||
use libc::c_void;
|
||||
use std::future::Future;
|
||||
use std::ptr::null;
|
||||
use std::sync::Weak;
|
||||
|
||||
use libc::c_void;
|
||||
use ylong_ffrt::FfrtRet::{FfrtCoroutinePending, FfrtCoroutineReady};
|
||||
use ylong_ffrt::{ffrt_submit_h_coroutine, FfrtRet, FfrtTaskAttr, FfrtTaskHandle};
|
||||
|
||||
use crate::executor::PlaceholderScheduler;
|
||||
use crate::task::{JoinHandle, Task, VirtualTableType};
|
||||
use crate::TaskBuilder;
|
||||
|
||||
pub(crate) fn ffrt_submit(t: Task, attr: &FfrtTaskAttr) -> FfrtTaskHandle {
|
||||
extern "C" fn exec_future(data: *mut c_void) -> FfrtRet {
|
||||
unsafe {
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::fs::{async_op, poll_ready};
|
||||
use crate::futures::poll_fn;
|
||||
use crate::spawn::spawn_blocking;
|
||||
use crate::{JoinHandle, TaskBuilder};
|
||||
use std::collections::VecDeque;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{FileType, Metadata};
|
||||
@@ -27,6 +23,11 @@ use std::sync::Arc;
|
||||
use std::task::Poll::Ready;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::fs::{async_op, poll_ready};
|
||||
use crate::futures::poll_fn;
|
||||
use crate::spawn::spawn_blocking;
|
||||
use crate::{JoinHandle, TaskBuilder};
|
||||
|
||||
const BLOCK_SIZE: usize = 32;
|
||||
|
||||
/// Creates a new directory at the given path.
|
||||
@@ -35,18 +36,20 @@ const BLOCK_SIZE: usize = 32;
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// In the following situations, the function will return an error, but is not limited
|
||||
/// to just these cases:
|
||||
/// In the following situations, the function will return an error, but is not
|
||||
/// limited to just these cases:
|
||||
///
|
||||
/// * The path has already been used.
|
||||
/// * No permission to create directory at the given path.
|
||||
/// * A parent directory in the path does not exist. In this case, use [`create_dir_all`] to create
|
||||
/// the missing parent directory and the target directory at the same time.
|
||||
/// * A parent directory in the path does not exist. In this case, use
|
||||
/// [`create_dir_all`] to create the missing parent directory and the target
|
||||
/// directory at the same time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// fs::create_dir("/parent/dir").await?;
|
||||
@@ -64,8 +67,8 @@ pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// In the following situations, the function will return an error, but is not limited
|
||||
/// to just these cases:
|
||||
/// In the following situations, the function will return an error, but is not
|
||||
/// limited to just these cases:
|
||||
///
|
||||
/// * The path has already been used.
|
||||
/// * No permission to create directory at the given path.
|
||||
@@ -75,6 +78,7 @@ pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// fs::create_dir_all("/parent/dir").await?;
|
||||
@@ -92,8 +96,8 @@ pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// In the following situations, the function will return an error, but is not limited
|
||||
/// to just these cases:
|
||||
/// In the following situations, the function will return an error, but is not
|
||||
/// limited to just these cases:
|
||||
///
|
||||
/// * The directory does not exist.
|
||||
/// * The given path is not a directory.
|
||||
@@ -104,6 +108,7 @@ pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// fs::remove_dir("/parent/dir").await?;
|
||||
@@ -129,6 +134,7 @@ pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// fs::remove_dir_all("/parent/dir").await?;
|
||||
@@ -154,6 +160,7 @@ pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// let mut dir = fs::read_dir("/parent/dir").await?;
|
||||
@@ -254,6 +261,7 @@ impl ReadDir {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// let mut dir = fs::read_dir("/parent/dir").await?;
|
||||
@@ -280,12 +288,13 @@ impl DirEntry {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
///
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// let mut dir = fs::read_dir("/parent/dir").await?;
|
||||
/// while let Some(entry) = dir.next().await? {
|
||||
/// println!("{:?}", entry.path());
|
||||
/// println!("{:?}", entry.path());
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
@@ -307,12 +316,13 @@ impl DirEntry {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
///
|
||||
/// async fn fs_func() -> io::Result<()>{
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// let mut dir = fs::read_dir("/parent/dir").await?;
|
||||
/// while let Some(entry) = dir.next().await? {
|
||||
/// println!("{:?}", entry.file_name());
|
||||
/// println!("{:?}", entry.file_name());
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
@@ -330,14 +340,15 @@ impl DirEntry {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
///
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// let mut dir = fs::read_dir("/parent/dir").await?;
|
||||
/// while let Some(entry) = dir.next().await? {
|
||||
/// if let Ok(metadata) = entry.metadata().await {
|
||||
/// if let Ok(metadata) = entry.metadata().await {
|
||||
/// println!("{:?}", metadata.permissions());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
@@ -356,14 +367,15 @@ impl DirEntry {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ylong_runtime::fs;
|
||||
///
|
||||
/// async fn fs_func() -> io::Result<()> {
|
||||
/// let mut dir = fs::read_dir("/parent/dir").await?;
|
||||
/// while let Some(entry) = dir.next().await? {
|
||||
/// if let Ok(file_type) = entry.file_type().await {
|
||||
/// if let Ok(file_type) = entry.file_type().await {
|
||||
/// println!("{:?}", file_type);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
|
||||
@@ -11,13 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::fs::file_buf::FileBuf;
|
||||
use crate::fs::{async_op, poll_ready};
|
||||
use crate::futures::poll_fn;
|
||||
use crate::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
|
||||
use crate::spawn::spawn_blocking;
|
||||
use crate::sync::Mutex;
|
||||
use crate::task::{JoinHandle, TaskBuilder};
|
||||
use std::fs::{File as SyncFile, Metadata, Permissions};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
@@ -27,7 +20,16 @@ use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// An asynchronous wrapping of [`std::fs::File`]. Provides async read/write methods.
|
||||
use crate::fs::file_buf::FileBuf;
|
||||
use crate::fs::{async_op, poll_ready};
|
||||
use crate::futures::poll_fn;
|
||||
use crate::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
|
||||
use crate::spawn::spawn_blocking;
|
||||
use crate::sync::Mutex;
|
||||
use crate::task::{JoinHandle, TaskBuilder};
|
||||
|
||||
/// An asynchronous wrapping of [`std::fs::File`]. Provides async read/write
|
||||
/// methods.
|
||||
pub struct File {
|
||||
file: Arc<SyncFile>,
|
||||
inner: Mutex<FileInner>,
|
||||
@@ -323,7 +325,8 @@ impl AsyncRead for File {
|
||||
match inner.state {
|
||||
FileState::Idle(ref mut file_buf) => {
|
||||
let mut r_buf = file_buf.take().unwrap();
|
||||
// There is still remaining data from the last read, append it to read buf directly
|
||||
// There is still remaining data from the last read, append it to read buf
|
||||
// directly
|
||||
if r_buf.remaining() != 0 {
|
||||
r_buf.append_to(buf);
|
||||
*file_buf = Some(r_buf);
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::ReadBuf;
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::io::ReadBuf;
|
||||
|
||||
pub(crate) struct FileBuf {
|
||||
pub(crate) buf: Vec<u8>,
|
||||
idx: usize,
|
||||
|
||||
@@ -18,12 +18,14 @@ mod async_file;
|
||||
mod file_buf;
|
||||
mod open_options;
|
||||
|
||||
use crate::spawn::spawn_blocking;
|
||||
use crate::task::TaskBuilder;
|
||||
use std::io;
|
||||
|
||||
pub use async_dir::{create_dir, create_dir_all, read_dir, remove_dir, remove_dir_all};
|
||||
pub use async_file::File;
|
||||
pub use open_options::OpenOptions;
|
||||
use std::io;
|
||||
|
||||
use crate::spawn::spawn_blocking;
|
||||
use crate::task::TaskBuilder;
|
||||
|
||||
pub(crate) async fn async_op<T, R>(task: T) -> io::Result<R>
|
||||
where
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::fs::{async_op, File};
|
||||
use std::fs::OpenOptions as SyncOpenOptions;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::fs::{async_op, File};
|
||||
|
||||
/// An asynchronous version of the [`std::fs::OpenOptions`];
|
||||
///
|
||||
/// Options and flags which can be used to configure how a file is opened.
|
||||
@@ -25,19 +26,22 @@ use std::path::Path;
|
||||
///
|
||||
/// async fn open_with_options() {
|
||||
/// let file = OpenOptions::new()
|
||||
/// .read(true)
|
||||
/// .write(true)
|
||||
/// .create(true)
|
||||
/// .open("foo.txt").await;
|
||||
/// .read(true)
|
||||
/// .write(true)
|
||||
/// .create(true)
|
||||
/// .open("foo.txt")
|
||||
/// .await;
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpenOptions(SyncOpenOptions);
|
||||
|
||||
impl OpenOptions {
|
||||
/// Creates a blank new set of options ready for configuration when opening a file.
|
||||
/// Creates a blank new set of options ready for configuration when opening
|
||||
/// a file.
|
||||
///
|
||||
/// All options are initially set to `false` just like [`std::fs::OpenOptions::new`].
|
||||
/// All options are initially set to `false` just like
|
||||
/// [`std::fs::OpenOptions::new`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -81,8 +85,8 @@ impl OpenOptions {
|
||||
/// This option, when true, will indicate that the file should be
|
||||
/// `write`-able if opened.
|
||||
///
|
||||
/// If the file already exists, any write calls on it will overwrite its previous
|
||||
/// contents, without truncating it.
|
||||
/// If the file already exists, any write calls on it will overwrite its
|
||||
/// previous contents, without truncating it.
|
||||
///
|
||||
/// This method's behavior is the same as [`std::fs::OpenOptions::write`].
|
||||
///
|
||||
@@ -105,20 +109,23 @@ impl OpenOptions {
|
||||
/// This option, when true, means that writes will append to a file instead
|
||||
/// of overwriting previous contents.
|
||||
///
|
||||
/// Note that when setting `.append(true)`, file write access will also be turned on
|
||||
/// Note that when setting `.append(true)`, file write access will also be
|
||||
/// turned on
|
||||
///
|
||||
/// For most filesystems, the operating system guarantees that all writes are
|
||||
/// atomic: no writes get mangled because another thread or process writes at the same
|
||||
/// time.
|
||||
/// For most filesystems, the operating system guarantees that all writes
|
||||
/// are atomic: no writes get mangled because another thread or process
|
||||
/// writes at the same time.
|
||||
///
|
||||
/// User should write all data that belongs together in one operation during appending.
|
||||
/// This can be done by concatenating strings before passing them to [`write()`],
|
||||
/// or using a buffered writer (with a buffer of adequate size),
|
||||
/// and calling [`flush()`] when the message is written completely.
|
||||
/// User should write all data that belongs together in one operation during
|
||||
/// appending. This can be done by concatenating strings before passing
|
||||
/// them to [`write()`], or using a buffered writer (with a buffer of
|
||||
/// adequate size), and calling [`flush()`] when the message is written
|
||||
/// completely.
|
||||
///
|
||||
/// If a file is opened with both read and append access, beware that after
|
||||
/// opening and every write, the position for reading may be set at the end of the file.
|
||||
/// So, before writing, save the current position, and restore it before the next read.
|
||||
/// opening and every write, the position for reading may be set at the end
|
||||
/// of the file. So, before writing, save the current position, and
|
||||
/// restore it before the next read.
|
||||
///
|
||||
/// This method's behavior is the same as [`std::fs::OpenOptions::append`].
|
||||
///
|
||||
@@ -148,13 +155,14 @@ impl OpenOptions {
|
||||
/// Sets the option for truncating a file's previous content.
|
||||
///
|
||||
/// If a file is successfully opened with this option set, it will truncate
|
||||
/// the file to 0 length if it already exists. Any already-existed content in
|
||||
/// this file will be dropped.
|
||||
/// the file to 0 length if it already exists. Any already-existed content
|
||||
/// in this file will be dropped.
|
||||
///
|
||||
/// The file must be opened with write access for truncate to work, which is different
|
||||
/// from append mode.
|
||||
/// The file must be opened with write access for truncate to work, which is
|
||||
/// different from append mode.
|
||||
///
|
||||
/// This method's behavior is the same as [`std::fs::OpenOptions::truncate`].
|
||||
/// This method's behavior is the same as
|
||||
/// [`std::fs::OpenOptions::truncate`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -162,7 +170,11 @@ impl OpenOptions {
|
||||
/// use ylong_runtime::fs::OpenOptions;
|
||||
///
|
||||
/// async fn open_with_truncate() {
|
||||
/// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt").await;
|
||||
/// let file = OpenOptions::new()
|
||||
/// .write(true)
|
||||
/// .truncate(true)
|
||||
/// .open("foo.txt")
|
||||
/// .await;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn truncate(&mut self, truncate: bool) -> &mut Self {
|
||||
@@ -170,8 +182,8 @@ impl OpenOptions {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the option to create a new file if it doesn't already exist, or simply open
|
||||
/// it if it does exist.
|
||||
/// Sets the option to create a new file if it doesn't already exist, or
|
||||
/// simply open it if it does exist.
|
||||
///
|
||||
/// In order for the file to be created, [`OpenOptions::write`] or
|
||||
/// [`OpenOptions::append`] access must be set to true.
|
||||
@@ -184,7 +196,11 @@ impl OpenOptions {
|
||||
/// use ylong_runtime::fs::OpenOptions;
|
||||
///
|
||||
/// async fn open_with_create() {
|
||||
/// let file = OpenOptions::new().write(true).create(true).open("foo.txt").await;
|
||||
/// let file = OpenOptions::new()
|
||||
/// .write(true)
|
||||
/// .create(true)
|
||||
/// .open("foo.txt")
|
||||
/// .await;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn create(&mut self, create: bool) -> &mut Self {
|
||||
@@ -194,13 +210,15 @@ impl OpenOptions {
|
||||
|
||||
/// Sets the option to create a new file.
|
||||
///
|
||||
/// If the file already exists, opening the file with the option set will cause an error.
|
||||
/// If the file already exists, opening the file with the option set will
|
||||
/// cause an error.
|
||||
///
|
||||
/// No file is allowed to exist at the target location, also no (dangling) symlink. In this
|
||||
/// way, if the call succeeds, the file returned is guaranteed to be new.
|
||||
/// No file is allowed to exist at the target location, also no (dangling)
|
||||
/// symlink. In this way, if the call succeeds, the file returned is
|
||||
/// guaranteed to be new.
|
||||
///
|
||||
/// This option guarantees the operation of checking whether a file exists and creating
|
||||
/// a new one is atomic.
|
||||
/// This option guarantees the operation of checking whether a file exists
|
||||
/// and creating a new one is atomic.
|
||||
///
|
||||
/// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
|
||||
/// ignored.
|
||||
@@ -211,7 +229,8 @@ impl OpenOptions {
|
||||
/// [`.create(true)`]: OpenOptions::create
|
||||
/// [`.truncate(true)`]: OpenOptions::truncate
|
||||
///
|
||||
/// This method's behavior is the same as [`std::fs::OpenOptions::create_new`].
|
||||
/// This method's behavior is the same as
|
||||
/// [`std::fs::OpenOptions::create_new`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -219,7 +238,11 @@ impl OpenOptions {
|
||||
/// use ylong_runtime::fs::OpenOptions;
|
||||
///
|
||||
/// async fn open_with_create_new() {
|
||||
/// let file = OpenOptions::new().write(true).create_new(true).open("foo.txt").await;
|
||||
/// let file = OpenOptions::new()
|
||||
/// .write(true)
|
||||
/// .create_new(true)
|
||||
/// .open("foo.txt")
|
||||
/// .await;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn create_new(&mut self, create_new: bool) -> &mut Self {
|
||||
@@ -227,29 +250,34 @@ impl OpenOptions {
|
||||
self
|
||||
}
|
||||
|
||||
/// Asynchronously opens a file at `path` with the options specified by `self`.
|
||||
/// Asynchronously opens a file at `path` with the options specified by
|
||||
/// `self`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This method's behavior is the same as [`std::fs::OpenOptions::open`].
|
||||
///
|
||||
/// * [`NotFound`]: The specified file does not exist and neither `create` or
|
||||
/// `create_new` is set.
|
||||
/// * [`NotFound`]: One of the directory components of the file path doesn't exist.
|
||||
/// * [`PermissionDenied`]: The user lacks permission to get the specified access
|
||||
/// rights for the file.
|
||||
/// * [`PermissionDenied`]: The user lacks permission to open one of the directory
|
||||
/// components of the specified path.
|
||||
/// * [`AlreadyExists`]: `create_new` was specified and the file already exists.
|
||||
/// * [`InvalidInput`]: Invalid combinations of open options (truncate without
|
||||
/// write access, no access mode set, etc.).
|
||||
/// * [`NotFound`]: The specified file does not exist and neither `create`
|
||||
/// or `create_new` is set.
|
||||
/// * [`NotFound`]: One of the directory components of the file path doesn't
|
||||
/// exist.
|
||||
/// * [`PermissionDenied`]: The user lacks permission to get the specified
|
||||
/// access rights for the file.
|
||||
/// * [`PermissionDenied`]: The user lacks permission to open one of the
|
||||
/// directory components of the specified path.
|
||||
/// * [`AlreadyExists`]: `create_new` was specified and the file already
|
||||
/// exists.
|
||||
/// * [`InvalidInput`]: Invalid combinations of open options (truncate
|
||||
/// without write access, no access mode set, etc.).
|
||||
///
|
||||
/// The following errors don't match any existing [`io::ErrorKind`] at the moment:
|
||||
/// * One of the directory components of the specified file path was not,
|
||||
/// in fact, a directory.
|
||||
/// * Filesystem-level errors: full disk, write permission requested on a read-only
|
||||
/// file system, exceeded disk quota, too many open files, too long filename,
|
||||
/// too many symbolic links in the specified path (Unix-like systems only), etc.
|
||||
/// The following errors don't match any existing [`io::ErrorKind`] at the
|
||||
/// moment:
|
||||
/// * One of the directory components of the specified file path was not, in
|
||||
/// fact, a directory.
|
||||
/// * Filesystem-level errors: full disk, write permission requested on a
|
||||
/// read-only file system, exceeded disk quota, too many open files, too
|
||||
/// long filename, too many symbolic links in the specified path
|
||||
/// (Unix-like systems only), etc.
|
||||
///
|
||||
/// [`NotFound`]: std::io::ErrorKind::NotFound
|
||||
/// [`PermissionDenied`]: std::io::ErrorKind::PermissionDenied
|
||||
@@ -275,13 +303,11 @@ impl OpenOptions {
|
||||
mod test {
|
||||
use crate::fs::OpenOptions;
|
||||
|
||||
/// UT test for Openoption.
|
||||
///
|
||||
/// # Title
|
||||
/// ut_set_openoption
|
||||
///
|
||||
/// UT test cases for Openoption.
|
||||
|
||||
/// # Brief
|
||||
/// 1. Call `read`、`write`、`append`、`truncate`、`create`、`create_new` function, passing in the specified parameters.
|
||||
/// 1. Call `read`、`write`、`append`、`truncate`、`create`、`create_new`
|
||||
/// function, passing in the specified parameters.
|
||||
/// 2. Check if the settings are correct.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
|
||||
@@ -17,8 +17,8 @@ use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// A future object that wraps a [`Fn`]. Awaits on this function will executed this
|
||||
/// underlying function.
|
||||
/// A future object that wraps a [`Fn`]. Awaits on this function will executed
|
||||
/// this underlying function.
|
||||
pub struct PollFn<F> {
|
||||
f: F,
|
||||
}
|
||||
|
||||
@@ -11,32 +11,33 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::read_task::{LinesTask, ReadLineTask, ReadUtilTask, SplitTask};
|
||||
use crate::io::AsyncRead;
|
||||
use std::io;
|
||||
use std::ops::DerefMut;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::io::read_task::{LinesTask, ReadLineTask, ReadUtilTask, SplitTask};
|
||||
use crate::io::AsyncRead;
|
||||
|
||||
/// It is an asynchronous version of [`std::io::BufRead`].
|
||||
///
|
||||
/// A `AsyncBufRead` is a type of `AsyncRead`er which has an internal buffer, allowing it
|
||||
/// to perform extra ways of reading, such as `read_line`.
|
||||
/// A `AsyncBufRead` is a type of `AsyncRead`er which has an internal buffer,
|
||||
/// allowing it to perform extra ways of reading, such as `read_line`.
|
||||
pub trait AsyncBufRead: AsyncRead {
|
||||
/// Returns the contents of the internal buffer, trying to fill it with more data
|
||||
/// from the inner reader if it is empty.
|
||||
/// Returns the contents of the internal buffer, trying to fill it with more
|
||||
/// data from the inner reader if it is empty.
|
||||
///
|
||||
/// This method is non-blocking. If the underlying reader is unable to perform
|
||||
/// a read at the time, this method would return a `Poll::Pending`. If there is data inside
|
||||
/// the buffer or the read is successfully performed, then it would return a
|
||||
/// `Poll::Ready(&[u8])`.
|
||||
/// This method is non-blocking. If the underlying reader is unable to
|
||||
/// perform a read at the time, this method would return a
|
||||
/// `Poll::Pending`. If there is data inside the buffer or the read is
|
||||
/// successfully performed, then it would return a `Poll::Ready(&[u8])`.
|
||||
///
|
||||
/// This method is a low-level call. It needs to be paired up with calls to
|
||||
/// [`Self::consume`] method to function properly.
|
||||
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>>;
|
||||
|
||||
/// Tells this buffer that `amt` bytes have been consumed from the buffer, so they should
|
||||
/// no longer be returned in calls to `read`.
|
||||
/// Tells this buffer that `amt` bytes have been consumed from the buffer,
|
||||
/// so they should no longer be returned in calls to `read`.
|
||||
///
|
||||
/// This method is a low-level call. It has to be called after a call to
|
||||
/// [`Self::poll_fill_buf`] in order to function properly.
|
||||
@@ -83,13 +84,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// An external trait that is automatically implemented for any object that has the AsyncBufRead trait.
|
||||
/// Provides std-like reading methods such as `read_until`, `read_line`, `split`, `lines`.
|
||||
/// Every method in this trait returns a future object. Awaits on the future will complete the
|
||||
/// task, but it doesn't guarantee whether the task will finished immediately or asynchronously.
|
||||
/// An external trait that is automatically implemented for any object that has
|
||||
/// the AsyncBufRead trait. Provides std-like reading methods such as
|
||||
/// `read_until`, `read_line`, `split`, `lines`. Every method in this trait
|
||||
/// returns a future object. Awaits on the future will complete the task, but it
|
||||
/// doesn't guarantee whether the task will finished immediately or
|
||||
/// asynchronously.
|
||||
pub trait AsyncBufReadExt: AsyncBufRead {
|
||||
/// Asynchronously reads data from the underlying stream into the `buf` until the
|
||||
/// desired delimiter appears or EOF is reached.
|
||||
/// Asynchronously reads data from the underlying stream into the `buf`
|
||||
/// until the desired delimiter appears or EOF is reached.
|
||||
///
|
||||
/// If successful, this function will return the total number of bytes read.
|
||||
///
|
||||
@@ -107,8 +110,8 @@ pub trait AsyncBufReadExt: AsyncBufRead {
|
||||
ReadUtilTask::new(self, byte, buf)
|
||||
}
|
||||
|
||||
/// Asynchronously reads data from the underlying stream into the `buf` until the
|
||||
/// delimiter '\n' appears or EOF is reached.
|
||||
/// Asynchronously reads data from the underlying stream into the `buf`
|
||||
/// until the delimiter '\n' appears or EOF is reached.
|
||||
///
|
||||
/// If successful, this function will return the total number of bytes read.
|
||||
///
|
||||
@@ -126,8 +129,8 @@ pub trait AsyncBufReadExt: AsyncBufRead {
|
||||
ReadLineTask::new(self, buf)
|
||||
}
|
||||
|
||||
/// Asynchronously reads data from the underlying stream until EOF is reached
|
||||
/// and splits it on a delimiter.
|
||||
/// Asynchronously reads data from the underlying stream until EOF is
|
||||
/// reached and splits it on a delimiter.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
@@ -143,8 +146,8 @@ pub trait AsyncBufReadExt: AsyncBufRead {
|
||||
SplitTask::new(self, byte)
|
||||
}
|
||||
|
||||
/// Asynchronously reads data from the underlying stream until EOF is reached
|
||||
/// and splits it on a delimiter.
|
||||
/// Asynchronously reads data from the underlying stream until EOF is
|
||||
/// reached and splits it on a delimiter.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
|
||||
@@ -11,28 +11,33 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::read_buf::ReadBuf;
|
||||
use crate::io::read_task::{ReadExactTask, ReadTask, ReadToEndTask, ReadToStringTask};
|
||||
use std::ops::DerefMut;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{cmp, io};
|
||||
|
||||
/// An async version of the `std::io::Read` trait. Provides all necessary reading methods in an
|
||||
/// asynchronous style.
|
||||
use crate::io::read_buf::ReadBuf;
|
||||
use crate::io::read_task::{ReadExactTask, ReadTask, ReadToEndTask, ReadToStringTask};
|
||||
|
||||
/// An async version of the `std::io::Read` trait. Provides all necessary
|
||||
/// reading methods in an asynchronous style.
|
||||
pub trait AsyncRead {
|
||||
/// Attempts to reads bytes from the an I/O source into the buffer passed in.
|
||||
/// Attempts to reads bytes from the an I/O source into the buffer passed
|
||||
/// in.
|
||||
///
|
||||
/// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n` indicates the number of
|
||||
/// bytes that have been successfully read. It's guaranteed that `n <= buf.len()`.
|
||||
/// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n`
|
||||
/// indicates the number of bytes that have been successfully read. It's
|
||||
/// guaranteed that `n <= buf.len()`.
|
||||
///
|
||||
/// If returns `Poll::Ready(Ok(0))`, one of the two scenarios below might have occurred
|
||||
/// 1. The underlying stream has been shut down and no longer transfers any bytes.
|
||||
/// If returns `Poll::Ready(Ok(0))`, one of the two scenarios below might
|
||||
/// have occurred
|
||||
/// 1. The underlying stream has been shut down and no longer transfers
|
||||
/// any bytes.
|
||||
/// 2. The buf passed in is empty
|
||||
///
|
||||
/// If `Poll::Pending` is returned, it means that the input source is currently not ready
|
||||
/// for reading. In this case, this task will be put to sleep until the underlying stream
|
||||
/// becomes readable or closed.
|
||||
/// If `Poll::Pending` is returned, it means that the input source is
|
||||
/// currently not ready for reading. In this case, this task will be put
|
||||
/// to sleep until the underlying stream becomes readable or closed.
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
@@ -77,21 +82,25 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// An external trait that is automatically implemented for any object that has the AsyncRead trait.
|
||||
/// Provides std-like reading methods such as `read`, `read_exact`, `read_to_end`.
|
||||
/// Every method in this trait returns a future object. Awaits on the future will complete the
|
||||
/// task, but it doesn't guarantee whether the task will finished immediately or asynchronously.
|
||||
/// An external trait that is automatically implemented for any object that has
|
||||
/// the AsyncRead trait. Provides std-like reading methods such as `read`,
|
||||
/// `read_exact`, `read_to_end`. Every method in this trait returns a future
|
||||
/// object. Awaits on the future will complete the task, but it doesn't
|
||||
/// guarantee whether the task will finished immediately or asynchronously.
|
||||
pub trait AsyncReadExt: AsyncRead {
|
||||
/// Reads data from the I/O source into the buffer.
|
||||
///
|
||||
/// On success, `Ok(n)` will be returned, where `n` indicates the number of bytes
|
||||
/// that have been successfully read into the buffer. It guarantees `0 <= n < buf.len()`, and if
|
||||
/// `n == 0`, then one of the two scenarios below might have been occurred.
|
||||
/// 1. The reader has reaches `end of file` and no more bytes will be produced.
|
||||
/// On success, `Ok(n)` will be returned, where `n` indicates the number of
|
||||
/// bytes that have been successfully read into the buffer. It
|
||||
/// guarantees `0 <= n < buf.len()`, and if `n == 0`, then one of the
|
||||
/// two scenarios below might have been occurred.
|
||||
/// 1. The reader has reaches `end of file` and no more bytes will be
|
||||
/// produced.
|
||||
/// 2. The length of the buffer passed in is 0.
|
||||
///
|
||||
/// `Err(e)` will be returned when encounters a fatal error during the read procedure.
|
||||
/// This method should not read anything into the buffer if an error has occurred.
|
||||
/// `Err(e)` will be returned when encounters a fatal error during the read
|
||||
/// procedure. This method should not read anything into the buffer if
|
||||
/// an error has occurred.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
@@ -103,13 +112,14 @@ pub trait AsyncReadExt: AsyncRead {
|
||||
ReadTask::new(self, buf)
|
||||
}
|
||||
|
||||
/// Reads data from the I/O source into the buffer until the buffer is entirely filled.
|
||||
/// Reads data from the I/O source into the buffer until the buffer is
|
||||
/// entirely filled.
|
||||
///
|
||||
/// On success, `Ok(())` will be returned, indicating the `buf` has been filled entirely.
|
||||
/// If the I/O connection closes before filling the entire buffer, io::Error::UnexpectedEof
|
||||
/// will be returned.
|
||||
/// If a read error occurs during the process, this method will finish immediately,
|
||||
/// the number of bytes that has been read is unspecified.
|
||||
/// On success, `Ok(())` will be returned, indicating the `buf` has been
|
||||
/// filled entirely. If the I/O connection closes before filling the
|
||||
/// entire buffer, io::Error::UnexpectedEof will be returned.
|
||||
/// If a read error occurs during the process, this method will finish
|
||||
/// immediately, the number of bytes that has been read is unspecified.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
@@ -123,11 +133,11 @@ pub trait AsyncReadExt: AsyncRead {
|
||||
|
||||
/// Reads all data from the I/O source into the buffer until EOF.
|
||||
///
|
||||
/// On success, `Ok(())` will be returned, indicating all data from the I/O source has been
|
||||
/// append to the buffer.
|
||||
/// On success, `Ok(())` will be returned, indicating all data from the I/O
|
||||
/// source has been append to the buffer.
|
||||
///
|
||||
/// If a read error occurs during the read process, this method will finish immediately,
|
||||
/// the number of bytes that has been read is unspecified.
|
||||
/// If a read error occurs during the read process, this method will finish
|
||||
/// immediately, the number of bytes that has been read is unspecified.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
@@ -141,11 +151,11 @@ pub trait AsyncReadExt: AsyncRead {
|
||||
|
||||
/// Reads all string data from the I/O source into the buffer until EOF.
|
||||
///
|
||||
/// On success, `Ok(())` will be returned, indicating all data from the I/O source has been
|
||||
/// append to the buffer.
|
||||
/// On success, `Ok(())` will be returned, indicating all data from the I/O
|
||||
/// source has been append to the buffer.
|
||||
///
|
||||
/// If a read error occurs during the read process, this method will finish immediately,
|
||||
/// the number of bytes that has been read is unspecified.
|
||||
/// If a read error occurs during the read process, this method will finish
|
||||
/// immediately, the number of bytes that has been read is unspecified.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
|
||||
@@ -11,29 +11,30 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::seek_task::SeekTask;
|
||||
use std::io;
|
||||
use std::io::SeekFrom;
|
||||
use std::ops::DerefMut;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::io::seek_task::SeekTask;
|
||||
|
||||
/// An asynchronous version of [`std::io::Seek`].
|
||||
///
|
||||
/// The `AsyncSeek` trait provides a cursor which can be moved within a stream of
|
||||
/// bytes asynchronously.
|
||||
/// The `AsyncSeek` trait provides a cursor which can be moved within a stream
|
||||
/// of bytes asynchronously.
|
||||
///
|
||||
/// The stream typically has a fixed size, allowing seeking relative to either end
|
||||
/// or the current offset.
|
||||
/// The stream typically has a fixed size, allowing seeking relative to either
|
||||
/// end or the current offset.
|
||||
pub trait AsyncSeek {
|
||||
/// Attempts to seek to a position in an I/O source.
|
||||
///
|
||||
/// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n` indicates the current
|
||||
/// position in the I/O source.
|
||||
/// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n`
|
||||
/// indicates the current position in the I/O source.
|
||||
///
|
||||
/// If `Poll::Pending` is returned, it means that the input source is currently not ready
|
||||
/// for seeking. In this case, this task will be put to sleep until the underlying stream
|
||||
/// becomes readable or closed.
|
||||
/// If `Poll::Pending` is returned, it means that the input source is
|
||||
/// currently not ready for seeking. In this case, this task will be put
|
||||
/// to sleep until the underlying stream becomes readable or closed.
|
||||
fn poll_seek(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
@@ -76,10 +77,11 @@ impl<T: AsyncSeek + Unpin + ?Sized> AsyncSeek for &mut T {
|
||||
|
||||
impl<T: AsyncSeek + ?Sized> AsyncSeekExt for T {}
|
||||
|
||||
/// An external trait that is automatically implemented for any object that has the AsyncSeek trait.
|
||||
/// Provides std-like `seek` method.
|
||||
/// `Seek` method in this trait returns a future object. Awaits on the future will complete the
|
||||
/// task, but it doesn't guarantee whether the task will finished immediately or asynchronously.
|
||||
/// An external trait that is automatically implemented for any object that has
|
||||
/// the AsyncSeek trait. Provides std-like `seek` method.
|
||||
/// `Seek` method in this trait returns a future object. Awaits on the future
|
||||
/// will complete the task, but it doesn't guarantee whether the task will
|
||||
/// finished immediately or asynchronously.
|
||||
pub trait AsyncSeekExt: AsyncSeek {
|
||||
/// Asynchronously seek to an offset, in bytes, in a stream.
|
||||
///
|
||||
@@ -91,7 +93,8 @@ pub trait AsyncSeekExt: AsyncSeek {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Seeking can fail, for example because it might involve flushing a buffer.
|
||||
/// Seeking can fail, for example because it might involve flushing a
|
||||
/// buffer.
|
||||
///
|
||||
/// Seeking to a negative offset is considered an error.
|
||||
fn seek(&mut self, pos: SeekFrom) -> SeekTask<Self>
|
||||
|
||||
@@ -11,28 +11,32 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::write_task::{FlushTask, ShutdownTask, WriteAllTask, WriteTask, WriteVectoredTask};
|
||||
use std::io;
|
||||
use std::io::IoSlice;
|
||||
use std::ops::DerefMut;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// Async version of the `std::io::Write` trait. Provides all necessary writing methods in an
|
||||
/// asynchronous style.
|
||||
use crate::io::write_task::{FlushTask, ShutdownTask, WriteAllTask, WriteTask, WriteVectoredTask};
|
||||
|
||||
/// Async version of the `std::io::Write` trait. Provides all necessary writing
|
||||
/// methods in an asynchronous style.
|
||||
pub trait AsyncWrite {
|
||||
/// Attempts to write bytes from buffer into an I/O source.
|
||||
///
|
||||
/// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n` indicates the number of
|
||||
/// bytes that have been successfully written. It's guaranteed that `n <= buf.len()`.
|
||||
/// If succeeds, this method will return `Poll::Ready(Ok(n))` where `n`
|
||||
/// indicates the number of bytes that have been successfully written.
|
||||
/// It's guaranteed that `n <= buf.len()`.
|
||||
///
|
||||
/// If returns `Poll::Ready(Ok(0))`, one of the two scenarios below might have occurred
|
||||
/// 1. The underlying stream has been shut down and no longer accepts any bytes.
|
||||
/// If returns `Poll::Ready(Ok(0))`, one of the two scenarios below might
|
||||
/// have occurred
|
||||
/// 1. The underlying stream has been shut down and no longer accepts
|
||||
/// any bytes.
|
||||
/// 2. The buf passed in is empty
|
||||
///
|
||||
/// If `Poll::Pending` is returned, it means that the output stream is currently not ready
|
||||
/// for writing. In this case, this task will be put to sleep until the underlying stream
|
||||
/// becomes writable or closed.
|
||||
/// If `Poll::Pending` is returned, it means that the output stream is
|
||||
/// currently not ready for writing. In this case, this task will be put
|
||||
/// to sleep until the underlying stream becomes writable or closed.
|
||||
fn poll_write(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
@@ -41,8 +45,8 @@ pub trait AsyncWrite {
|
||||
|
||||
/// Attempts to write bytes from a slice of buffers into an I/O source.
|
||||
///
|
||||
/// This default implementation writes the first none empty buffer, or writes an empty one
|
||||
/// if all buffers are empty.
|
||||
/// This default implementation writes the first none empty buffer, or
|
||||
/// writes an empty one if all buffers are empty.
|
||||
fn poll_write_vectored(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
@@ -55,35 +59,38 @@ pub trait AsyncWrite {
|
||||
self.poll_write(cx, buf)
|
||||
}
|
||||
|
||||
/// Indicates whether this AsyncWrite implementation has an efficient `write_vectored`.
|
||||
/// The default implementation is not.
|
||||
/// Indicates whether this AsyncWrite implementation has an efficient
|
||||
/// `write_vectored`. The default implementation is not.
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Attempts to flush the I/O source, ensuring that any buffered data has been sent to
|
||||
/// their destination.
|
||||
/// Attempts to flush the I/O source, ensuring that any buffered data has
|
||||
/// been sent to their destination.
|
||||
///
|
||||
/// If succeeds, `Poll::Ready(Ok(()))` will be returned
|
||||
///
|
||||
/// If `Poll::Pending` is returned, it means the stream cannot be flushed immediately.
|
||||
/// The task will continue once its waker receives a notification indicating the stream is
|
||||
/// ready.
|
||||
/// If `Poll::Pending` is returned, it means the stream cannot be flushed
|
||||
/// immediately. The task will continue once its waker receives a
|
||||
/// notification indicating the stream is ready.
|
||||
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
|
||||
|
||||
/// Attempts to shut down the writer, returns `Poll::Ready(Ok(()))` when the underlying I/O
|
||||
/// connection is completely closed and therefore safe to drop.
|
||||
/// Attempts to shut down the writer, returns `Poll::Ready(Ok(()))` when the
|
||||
/// underlying I/O connection is completely closed and therefore safe to
|
||||
/// drop.
|
||||
///
|
||||
/// This method is designed for asynchronous shutdown of the I/O connection. For protocols like
|
||||
/// TLS or TCP, this is the place to do a last flush of data and gracefully turn off the
|
||||
/// connection.
|
||||
/// This method is designed for asynchronous shutdown of the I/O connection.
|
||||
/// For protocols like TLS or TCP, this is the place to do a last flush
|
||||
/// of data and gracefully turn off the connection.
|
||||
///
|
||||
/// If `Poll::Ready(Err(e))` is returned, it indicates a fatal error has been occurred during
|
||||
/// the shutdown procedure. It typically means the I/O source is already broken.
|
||||
/// If `Poll::Ready(Err(e))` is returned, it indicates a fatal error has
|
||||
/// been occurred during the shutdown procedure. It typically means the
|
||||
/// I/O source is already broken.
|
||||
///
|
||||
/// If `Poll::Pending` is returned, it indicates the I/O connection is not ready to shut
|
||||
/// down immediately, it may have another final data to be flushed.
|
||||
/// This task will be continued once the waker receives a ready notification from the connection.
|
||||
/// If `Poll::Pending` is returned, it indicates the I/O connection is not
|
||||
/// ready to shut down immediately, it may have another final data to be
|
||||
/// flushed. This task will be continued once the waker receives a ready
|
||||
/// notification from the connection.
|
||||
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
|
||||
}
|
||||
|
||||
@@ -99,8 +106,8 @@ macro_rules! async_write_deref {
|
||||
Pin::new(&mut **self).poll_write(cx, buf)
|
||||
}
|
||||
|
||||
/// A default poll_write_vectored implementation for an object that could be deref to an
|
||||
/// AsyncWrite object.
|
||||
/// A default poll_write_vectored implementation for an object that could be
|
||||
/// deref to an AsyncWrite object.
|
||||
fn poll_write_vectored(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
@@ -109,8 +116,8 @@ macro_rules! async_write_deref {
|
||||
Pin::new(&mut **self).poll_write_vectored(cx, bufs)
|
||||
}
|
||||
|
||||
/// A default is_write_vectored implementation for an object that could be deref to an
|
||||
/// AsyncWrite object.
|
||||
/// A default is_write_vectored implementation for an object that could be deref
|
||||
/// to an AsyncWrite object.
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
(**self).is_write_vectored()
|
||||
}
|
||||
@@ -121,8 +128,8 @@ macro_rules! async_write_deref {
|
||||
Pin::new(&mut **self).poll_flush(cx)
|
||||
}
|
||||
|
||||
/// A default poll_shutdown implementation for an object that could be deref to an
|
||||
/// AsyncWrite object.
|
||||
/// A default poll_shutdown implementation for an object that could be deref to
|
||||
/// an AsyncWrite object.
|
||||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Pin::new(&mut **self).poll_shutdown(cx)
|
||||
}
|
||||
@@ -170,21 +177,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// An external trait that is automatically implemented for any object that has the AsyncWrite trait.
|
||||
/// Provides std-like writing methods such as `write`, `write_vectored`, 'write_all'.
|
||||
/// Every method in this trait returns a future object. Awaits on the future will complete the task
|
||||
/// but it doesn't guarantee whether the task will finished immediately or asynchronously.
|
||||
/// An external trait that is automatically implemented for any object that has
|
||||
/// the AsyncWrite trait. Provides std-like writing methods such as `write`,
|
||||
/// `write_vectored`, 'write_all'. Every method in this trait returns a future
|
||||
/// object. Awaits on the future will complete the task but it doesn't guarantee
|
||||
/// whether the task will finished immediately or asynchronously.
|
||||
pub trait AsyncWriteExt: AsyncWrite {
|
||||
/// Writes data from the buffer into the I/O source.
|
||||
///
|
||||
/// On success, `Ok(n)` will be returned, where `n` indicates the number of bytes
|
||||
/// that have been successfully written into the buffer. It guarantees `0 <= n < buf.len()`,
|
||||
/// and if `n == 0`, then one of the two scenarios below might have been occurred.
|
||||
/// On success, `Ok(n)` will be returned, where `n` indicates the number of
|
||||
/// bytes that have been successfully written into the buffer. It
|
||||
/// guarantees `0 <= n < buf.len()`, and if `n == 0`, then one of the
|
||||
/// two scenarios below might have been occurred.
|
||||
/// 1. The underlying I/O no longer accepts any bytes.
|
||||
/// 2. The length of the buffer passed in is 0.
|
||||
///
|
||||
/// `Err(e)` will be returned when encounters a fatal error during the write procedure.
|
||||
/// This method should not write anything into the buffer if an error has occurred.
|
||||
/// `Err(e)` will be returned when encounters a fatal error during the write
|
||||
/// procedure. This method should not write anything into the buffer if
|
||||
/// an error has occurred.
|
||||
///
|
||||
/// Not writing the entire buffer into the I/O is not an error.
|
||||
/// # Examples
|
||||
@@ -216,7 +226,6 @@ pub trait AsyncWriteExt: AsyncWrite {
|
||||
/// let slice2 = IoSlice::new(&mut data2);
|
||||
/// let mut io = Filre::create("foo.txt").await?;
|
||||
/// let n = io.write_vectored(&[slice1, slice2]).await?;
|
||||
///
|
||||
/// ```
|
||||
fn write_vectored<'a, 'b>(
|
||||
&'a mut self,
|
||||
@@ -230,11 +239,12 @@ pub trait AsyncWriteExt: AsyncWrite {
|
||||
|
||||
/// Writes all data from the buffer into the I/O source.
|
||||
///
|
||||
/// On success, `Ok(())` will be returned, indicating all data from the buffer has been
|
||||
/// written into the I/O.
|
||||
/// On success, `Ok(())` will be returned, indicating all data from the
|
||||
/// buffer has been written into the I/O.
|
||||
///
|
||||
/// If a write error occurs during the process, this method will finish immediately,
|
||||
/// the number of bytes that has been written is unspecified.
|
||||
/// If a write error occurs during the process, this method will finish
|
||||
/// immediately, the number of bytes that has been written is
|
||||
/// unspecified.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
@@ -251,7 +261,8 @@ pub trait AsyncWriteExt: AsyncWrite {
|
||||
|
||||
/// Flushes the stream to ensure that all data reach the destination.
|
||||
///
|
||||
/// `Err(e)` will be returned when the I/O error occurring or EOF being reached.
|
||||
/// `Err(e)` will be returned when the I/O error occurring or EOF being
|
||||
/// reached.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no run
|
||||
|
||||
@@ -11,23 +11,25 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::async_buf_read::AsyncBufRead;
|
||||
use crate::io::buffered::DEFAULT_BUF_SIZE;
|
||||
use crate::io::{poll_ready, AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
|
||||
use std::cmp;
|
||||
use std::io::{IoSlice, SeekFrom};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::io::async_buf_read::AsyncBufRead;
|
||||
use crate::io::buffered::DEFAULT_BUF_SIZE;
|
||||
use crate::io::{poll_ready, AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
|
||||
|
||||
/// This is an asynchronous version of [`std::io::BufReader`]
|
||||
///
|
||||
/// The `AsyncBufReader<R>` struct adds buffering to any reader that implements AsyncRead.
|
||||
/// It is suitable to perform large, infrequent reads on the underlying [`AsyncRead`] object
|
||||
/// and maintains an in-memory buffer of the results.
|
||||
/// The `AsyncBufReader<R>` struct adds buffering to any reader that implements
|
||||
/// AsyncRead. It is suitable to perform large, infrequent reads on the
|
||||
/// underlying [`AsyncRead`] object and maintains an in-memory buffer of the
|
||||
/// results.
|
||||
///
|
||||
/// When the `AsyncBufReader<R>` is dropped, the contents inside its buffer will be discarded.
|
||||
/// Creating multiple instances of `AsyncBufReader<R>` on the same [`AsyncRead`] stream may cause
|
||||
/// data loss.
|
||||
/// When the `AsyncBufReader<R>` is dropped, the contents inside its buffer will
|
||||
/// be discarded. Creating multiple instances of `AsyncBufReader<R>` on the same
|
||||
/// [`AsyncRead`] stream may cause data loss.
|
||||
pub struct AsyncBufReader<R> {
|
||||
inner: R,
|
||||
buf: Box<[u8]>,
|
||||
@@ -37,7 +39,8 @@ pub struct AsyncBufReader<R> {
|
||||
|
||||
impl<R: AsyncRead> AsyncBufReader<R> {
|
||||
/// Creates a new `AsyncBufReader<R>` with a default buffer capacity.
|
||||
/// The default buffer capacity is 8 KB, which is the same as [`std::io::BufReader`]
|
||||
/// The default buffer capacity is 8 KB, which is the same as
|
||||
/// [`std::io::BufReader`]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -161,7 +164,8 @@ impl<R> AsyncBufReader<R> {
|
||||
|
||||
/// Unwraps this `AsyncBufReader<R>`, returning the underlying reader.
|
||||
///
|
||||
/// Any leftover data inside the internal buffer of the `AsyncBufReader` is lost.
|
||||
/// Any leftover data inside the internal buffer of the `AsyncBufReader` is
|
||||
/// lost.
|
||||
pub fn into_inner(self) -> R {
|
||||
self.inner
|
||||
}
|
||||
|
||||
@@ -11,22 +11,24 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::buffered::DEFAULT_BUF_SIZE;
|
||||
use crate::io::{poll_ready, AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
|
||||
use std::io;
|
||||
use std::io::{IoSlice, SeekFrom};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::io::buffered::DEFAULT_BUF_SIZE;
|
||||
use crate::io::{poll_ready, AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
|
||||
|
||||
/// This is an asynchronous version of [`std::io::BufWriter`]
|
||||
///
|
||||
/// The `AsyncBufWriter<W>` struct adds buffering to any writer that implements AsyncWrite.
|
||||
/// It is suitable to perform large, infrequent writes on the underlying [`AsyncWrite`] object
|
||||
/// and maintains an in-memory buffer of the results.
|
||||
/// The `AsyncBufWriter<W>` struct adds buffering to any writer that implements
|
||||
/// AsyncWrite. It is suitable to perform large, infrequent writes on the
|
||||
/// underlying [`AsyncWrite`] object and maintains an in-memory buffer of the
|
||||
/// results.
|
||||
///
|
||||
/// When the `AsyncBufWriter<W>` is dropped, the contents inside its buffer will be discarded.
|
||||
/// Creating multiple instances of `AsyncBufWriter<W>` on the same [`AsyncWrite`] stream may cause
|
||||
/// data loss.
|
||||
/// When the `AsyncBufWriter<W>` is dropped, the contents inside its buffer will
|
||||
/// be discarded. Creating multiple instances of `AsyncBufWriter<W>` on the same
|
||||
/// [`AsyncWrite`] stream may cause data loss.
|
||||
pub struct AsyncBufWriter<W> {
|
||||
inner: W,
|
||||
buf: Vec<u8>,
|
||||
@@ -35,7 +37,8 @@ pub struct AsyncBufWriter<W> {
|
||||
|
||||
impl<W: AsyncWrite> AsyncBufWriter<W> {
|
||||
/// Creates a new `AsyncBufWriter<W>` with a default buffer capacity.
|
||||
/// The default buffer capacity is 8 KB, which is the same as [`std::io::BufWriter`]
|
||||
/// The default buffer capacity is 8 KB, which is the same as
|
||||
/// [`std::io::BufWriter`]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -114,7 +117,8 @@ impl<W: AsyncWrite> AsyncBufWriter<W> {
|
||||
|
||||
/// Unwraps this `AsyncBufWriter<R>`, returning the underlying writer.
|
||||
///
|
||||
/// Any leftover data inside the internal buffer of the `AsyncBufWriter` is lost.
|
||||
/// Any leftover data inside the internal buffer of the `AsyncBufWriter` is
|
||||
/// lost.
|
||||
pub fn into_inner(self) -> W {
|
||||
self.inner
|
||||
}
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
/// This buf comes from std::io::ReadBuf, an unstable std lib. This buffer is a wrapper around byte
|
||||
/// buffer and it allows users to read data into an uninitialized memory. It tracks three regions in
|
||||
/// the buffer: a region at the beginning of the buffer that has been logically filled with data,
|
||||
/// a region that has been initialized at some point but not yet logically filled, and a region at
|
||||
/// the end that is fully uninitialized. The filled region is guaranteed to be a subset of the
|
||||
/// initialized region.
|
||||
/// This buf comes from std::io::ReadBuf, an unstable std lib. This buffer is a
|
||||
/// wrapper around byte buffer and it allows users to read data into an
|
||||
/// uninitialized memory. It tracks three regions in the buffer: a region at the
|
||||
/// beginning of the buffer that has been logically filled with data,
|
||||
/// a region that has been initialized at some point but not yet logically
|
||||
/// filled, and a region at the end that is fully uninitialized. The filled
|
||||
/// region is guaranteed to be a subset of the initialized region.
|
||||
///
|
||||
/// In summary, the contents of the buffer can be visualized as:
|
||||
/// ```not_rust
|
||||
@@ -85,7 +86,8 @@ impl<'a> ReadBuf<'a> {
|
||||
self.initialized
|
||||
}
|
||||
|
||||
/// Returns a new ReadBuf that uses the first `n` unfilled bytes of the buffer.
|
||||
/// Returns a new ReadBuf that uses the first `n` unfilled bytes of the
|
||||
/// buffer.
|
||||
#[inline]
|
||||
pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
|
||||
let rsize = std::cmp::min(n, self.remaining());
|
||||
@@ -122,8 +124,9 @@ impl<'a> ReadBuf<'a> {
|
||||
unsafe { &mut *(&mut self.buf[..self.initialized] as *mut [MaybeUninit<u8>] as *mut [u8]) }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the entire buffer, including the initialized and uninitialized
|
||||
/// portion. If the buffer is partially initialized, the caller must call [`ReadBuf::assume_init`] with
|
||||
/// Returns a mutable reference to the entire buffer, including the
|
||||
/// initialized and uninitialized portion. If the buffer is partially
|
||||
/// initialized, the caller must call [`ReadBuf::assume_init`] with
|
||||
/// the number of bytes initialized.
|
||||
#[inline]
|
||||
pub fn inner_mut(&mut self) -> &mut [MaybeUninit<u8>] {
|
||||
@@ -136,8 +139,9 @@ impl<'a> ReadBuf<'a> {
|
||||
self.buf.len() - self.filled
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the first n bytes of the unfilled portion of the `ReadBuf`.
|
||||
/// This method guarantees the returned buffer is fully initialized.
|
||||
/// Returns a mutable reference to the first n bytes of the unfilled portion
|
||||
/// of the `ReadBuf`. This method guarantees the returned buffer is
|
||||
/// fully initialized.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if n is bigger than the remaining capacity of the buf.
|
||||
@@ -159,14 +163,15 @@ impl<'a> ReadBuf<'a> {
|
||||
unsafe { &mut *(&mut self.buf[self.filled..end] as *mut [MaybeUninit<u8>] as *mut [u8]) }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the unfilled portion of the `ReadBuf`. This method guarantees
|
||||
/// the the buffer is fully initialized.
|
||||
/// Returns a mutable reference to the unfilled portion of the `ReadBuf`.
|
||||
/// This method guarantees the the buffer is fully initialized.
|
||||
#[inline]
|
||||
pub fn initialize_unfilled(&mut self) -> &mut [u8] {
|
||||
self.initialize_unfilled_to(self.remaining())
|
||||
}
|
||||
|
||||
/// Clears the `ReadBuf`. The filled size turns to zero while the initialized size is unchanged.
|
||||
/// Clears the `ReadBuf`. The filled size turns to zero while the
|
||||
/// initialized size is unchanged.
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
self.filled = 0;
|
||||
@@ -175,7 +180,8 @@ impl<'a> ReadBuf<'a> {
|
||||
/// Sets the filled size of the buffer.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the filled portion is bigger than the initialized portion of the buffer.
|
||||
/// Panics if the filled portion is bigger than the initialized portion of
|
||||
/// the buffer.
|
||||
#[inline]
|
||||
pub fn set_filled(&mut self, n: usize) {
|
||||
if n > self.initialized {
|
||||
@@ -187,8 +193,10 @@ impl<'a> ReadBuf<'a> {
|
||||
/// Advances the filled portion of the buffer by n bytes.
|
||||
///
|
||||
/// # Panics
|
||||
/// 1. Panics if the filled size is overflowed after adding the advance size.
|
||||
/// 2. Panics if the filled portion becomes larger than the initialized portion of the buffer.
|
||||
/// 1. Panics if the filled size is overflowed after adding the advance
|
||||
/// size.
|
||||
/// 2. Panics if the filled portion becomes larger than the initialized
|
||||
/// portion of the buffer.
|
||||
#[inline]
|
||||
pub fn advance(&mut self, n: usize) {
|
||||
let filled = self
|
||||
@@ -198,8 +206,9 @@ impl<'a> ReadBuf<'a> {
|
||||
self.set_filled(filled);
|
||||
}
|
||||
|
||||
/// Makes the n bytes after the filled portion of the buffer become initialized. If adding
|
||||
/// n bytes exceeds the capacity, the initialized size will be set to the capacity.
|
||||
/// Makes the n bytes after the filled portion of the buffer become
|
||||
/// initialized. If adding n bytes exceeds the capacity, the initialized
|
||||
/// size will be set to the capacity.
|
||||
#[inline]
|
||||
pub fn assume_init(&mut self, n: usize) {
|
||||
let end = std::cmp::min(self.filled + n, self.capacity());
|
||||
@@ -208,11 +217,12 @@ impl<'a> ReadBuf<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends the input data into the `BufRead`. Advances the filled size and initialized size
|
||||
/// accordingly.
|
||||
/// Appends the input data into the `BufRead`. Advances the filled size and
|
||||
/// initialized size accordingly.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the size of the appending buffer is greater than the remaining size of the `ReadBuf`
|
||||
/// Panics if the size of the appending buffer is greater than the remaining
|
||||
/// size of the `ReadBuf`
|
||||
#[inline]
|
||||
pub fn append(&mut self, buf: &[u8]) {
|
||||
if buf.len() > self.remaining() {
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::futures::poll_fn;
|
||||
use crate::io::async_buf_read::AsyncBufRead;
|
||||
use crate::io::async_read::AsyncRead;
|
||||
use crate::io::poll_ready;
|
||||
use crate::io::read_buf::ReadBuf;
|
||||
use std::future::Future;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::pin::Pin;
|
||||
@@ -24,6 +19,12 @@ use std::string::FromUtf8Error;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{io, mem};
|
||||
|
||||
use crate::futures::poll_fn;
|
||||
use crate::io::async_buf_read::AsyncBufRead;
|
||||
use crate::io::async_read::AsyncRead;
|
||||
use crate::io::poll_ready;
|
||||
use crate::io::read_buf::ReadBuf;
|
||||
|
||||
macro_rules! take_reader {
|
||||
($self: expr) => {
|
||||
match $self.reader.take() {
|
||||
@@ -99,8 +100,8 @@ fn poll_read_to_end<R: AsyncRead + Unpin>(
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
// Allocate 32 bytes every time, if the remaining capacity is larger than 32 bytes,
|
||||
// this will do nothing.
|
||||
// Allocate 32 bytes every time, if the remaining capacity is larger than 32
|
||||
// bytes, this will do nothing.
|
||||
buf.reserve(32);
|
||||
let len = buf.len();
|
||||
let mut read_buf = ReadBuf::uninit(unsafe {
|
||||
@@ -378,8 +379,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A future for reading every data from the source into a vector and splitting it
|
||||
/// into segments by a delimiter.
|
||||
/// A future for reading every data from the source into a vector and splitting
|
||||
/// it into segments by a delimiter.
|
||||
///
|
||||
/// Returned by [`crate::io::AsyncBufReadExt::split`]
|
||||
pub struct SplitTask<R> {
|
||||
@@ -422,8 +423,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A future for reading every data from the source into a vector and splitting it
|
||||
/// into segments by row.
|
||||
/// A future for reading every data from the source into a vector and splitting
|
||||
/// it into segments by row.
|
||||
///
|
||||
/// Returned by [`crate::io::AsyncBufReadExt::split`]
|
||||
pub struct LinesTask<R> {
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::AsyncSeek;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::io::AsyncSeek;
|
||||
|
||||
/// A future for seeking the io.
|
||||
///
|
||||
/// Returned by [`crate::io::AsyncSeekExt::seek`]
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::io::AsyncWrite;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::io::IoSlice;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::io::AsyncWrite;
|
||||
|
||||
macro_rules! take_writer {
|
||||
($self: expr) => {
|
||||
match $self.writer.take() {
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::pariter::Consumer;
|
||||
use super::pariter::ParallelIterator;
|
||||
|
||||
use super::pariter::{Consumer, ParallelIterator};
|
||||
use crate::error::ScheduleError;
|
||||
use crate::executor::{global_default_async, AsyncHandle};
|
||||
use crate::macros::{cfg_ffrt, cfg_not_ffrt};
|
||||
@@ -120,8 +118,9 @@ where
|
||||
}
|
||||
|
||||
// Safety
|
||||
// No restriction on lifetime to static, so it must be ensured that the data pointed to is always valid until the execution is completed,
|
||||
// in other word .await the join handle after it is created.
|
||||
// No restriction on lifetime to static, so it must be ensured that the data
|
||||
// pointed to is always valid until the execution is completed, in other word
|
||||
// .await the join handle after it is created.
|
||||
#[cfg(not(feature = "ffrt"))]
|
||||
#[inline]
|
||||
unsafe fn spawn_task<P, C>(
|
||||
@@ -182,8 +181,9 @@ where
|
||||
}
|
||||
|
||||
// Safety
|
||||
// No restriction on lifetime to static, so it must be ensured that the data pointed to is always valid until the execution is completed,
|
||||
// in other word .await the join handle after it is created.
|
||||
// No restriction on lifetime to static, so it must be ensured that the data
|
||||
// pointed to is always valid until the execution is completed, in other word
|
||||
// .await the join handle after it is created.
|
||||
#[cfg(feature = "ffrt")]
|
||||
#[inline]
|
||||
unsafe fn spawn_task_ffrt<P, C>(
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! ParIter module, providing asynchronous iter lambda function implementations such as
|
||||
//! `for_each`, `zip`, `map`, `filter`.
|
||||
//!
|
||||
//!
|
||||
//! ParIter module, providing asynchronous iter lambda function implementations
|
||||
//! such as `for_each`, `zip`, `map`, `filter`.
|
||||
mod core;
|
||||
|
||||
/// Parallel type and implementation
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::IntoParIter;
|
||||
use super::ParIter;
|
||||
use super::{IntoParIter, ParIter};
|
||||
|
||||
impl<'a, T, const N: usize> IntoParIter for &'a [T; N] {
|
||||
type Data = &'a [T];
|
||||
|
||||
@@ -11,11 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::par_vec_impl;
|
||||
use std::collections::BinaryHeap;
|
||||
|
||||
use crate::iter::parallel::IntoParIter;
|
||||
use crate::iter::parallel::ParIter;
|
||||
use super::par_vec_impl;
|
||||
use crate::iter::parallel::{IntoParIter, ParIter};
|
||||
|
||||
par_vec_impl!(BinaryHeap<T>, Vec<T>, into_iter, impl <T>);
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::par_vec_impl;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::iter::parallel::IntoParIter;
|
||||
use crate::iter::parallel::ParIter;
|
||||
use super::par_vec_impl;
|
||||
use crate::iter::parallel::{IntoParIter, ParIter};
|
||||
|
||||
par_vec_impl!(BTreeMap<T, V>, Vec<(T,V)>, into_iter, impl <T, V>);
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::par_vec_impl;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use crate::iter::parallel::IntoParIter;
|
||||
use crate::iter::parallel::ParIter;
|
||||
use super::par_vec_impl;
|
||||
use crate::iter::parallel::{IntoParIter, ParIter};
|
||||
|
||||
par_vec_impl!(BTreeSet<T>, Vec<T>, into_iter, impl <T>);
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::par_vec_impl;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::iter::parallel::IntoParIter;
|
||||
use crate::iter::parallel::ParIter;
|
||||
use super::par_vec_impl;
|
||||
use crate::iter::parallel::{IntoParIter, ParIter};
|
||||
|
||||
par_vec_impl!(HashMap<T, V>, Vec<(T, V)>, into_iter, impl <T, V>);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user