diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..758f41a --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,6 @@ +edition = "2021" +wrap_comments = true +imports_granularity = "Module" +group_imports = "StdExternalCrate" +format_code_in_doc_comments = true +normalize_comments = true diff --git a/ylong_ffrt/build_ffrt.rs b/ylong_ffrt/build_ffrt.rs index 5e1b461..71ecd3e 100644 --- a/ylong_ffrt/build_ffrt.rs +++ b/ylong_ffrt/build_ffrt.rs @@ -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"; diff --git a/ylong_ffrt/src/condition_variable.rs b/ylong_ffrt/src/condition_variable.rs index e05cfaa..9f1ca78 100644 --- a/ylong_ffrt/src/condition_variable.rs +++ b/ylong_ffrt/src/condition_variable.rs @@ -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()); } } diff --git a/ylong_ffrt/src/config.rs b/ylong_ffrt/src/config.rs index d58e569..edd3f9e 100644 --- a/ylong_ffrt/src/config.rs +++ b/ylong_ffrt/src/config.rs @@ -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) } } diff --git a/ylong_ffrt/src/deadline.rs b/ylong_ffrt/src/deadline.rs index 2165749..36da0b4 100644 --- a/ylong_ffrt/src/deadline.rs +++ b/ylong_ffrt/src/deadline.rs @@ -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); diff --git a/ylong_ffrt/src/lib.rs b/ylong_ffrt/src/lib.rs index ee57a10..dca2465 100644 --- a/ylong_ffrt/src/lib.rs +++ b/ylong_ffrt/src/lib.rs @@ -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. diff --git a/ylong_ffrt/src/mutex.rs b/ylong_ffrt/src/mutex.rs index fae9db9..8130edc 100644 --- a/ylong_ffrt/src/mutex.rs +++ b/ylong_ffrt/src/mutex.rs @@ -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 { /// Mutexguard used for operating the value inside the mutex. pub struct MutexGuard<'a, T: ?Sized + 'a> { pub(crate) lock: &'a Mutex, - _phantom: PhantomData>, // Not Send, Not Sync + // Not Send, Not Sync + _phantom: PhantomData>, } #[repr(C)] @@ -104,7 +103,8 @@ impl Mutex { 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 Drop for Mutex { fn drop(&mut self) { unsafe { - let _ = ffrt_mtx_destroy(self.inner.get()); // ignore result + // ignore result + let _ = ffrt_mtx_destroy(self.inner.get()); } } } diff --git a/ylong_ffrt/src/sleep.rs b/ylong_ffrt/src/sleep.rs index 3c6e6ee..12c0536 100644 --- a/ylong_ffrt/src/sleep.rs +++ b/ylong_ffrt/src/sleep.rs @@ -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 { diff --git a/ylong_ffrt/src/sys_event.rs b/ylong_ffrt/src/sys_event.rs index 63ba6e5..c44deaa 100644 --- a/ylong_ffrt/src/sys_event.rs +++ b/ylong_ffrt/src/sys_event.rs @@ -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, diff --git a/ylong_ffrt/src/task.rs b/ylong_ffrt/src/task.rs index 2a0cf3c..4e13660 100644 --- a/ylong_ffrt/src/task.rs +++ b/ylong_ffrt/src/task.rs @@ -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 diff --git a/ylong_ffrt/src/thread.rs b/ylong_ffrt/src/thread.rs index f5e82d4..3d2464e 100644 --- a/ylong_ffrt/src/thread.rs +++ b/ylong_ffrt/src/thread.rs @@ -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); diff --git a/ylong_io/examples/ylong_io_tcp_client.rs b/ylong_io/examples/ylong_io_tcp_client.rs index f42880c..3c732fd 100644 --- a/ylong_io/examples/ylong_io_tcp_client.rs +++ b/ylong_io/examples/ylong_io_tcp_client.rs @@ -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() { diff --git a/ylong_io/examples/ylong_io_tcp_server.rs b/ylong_io/examples/ylong_io_tcp_server.rs index dbaa4a2..38793f9 100644 --- a/ylong_io/examples/ylong_io_tcp_server.rs +++ b/ylong_io/examples/ylong_io_tcp_server.rs @@ -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}"); diff --git a/ylong_io/src/lib.rs b/ylong_io/src/lib.rs index db62a29..08c7b68 100644 --- a/ylong_io/src/lib.rs +++ b/ylong_io/src/lib.rs @@ -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}; diff --git a/ylong_io/src/poll.rs b/ylong_io/src/poll.rs index f5d2ee8..8016a1d 100644 --- a/ylong_io/src/poll.rs +++ b/ylong_io/src/poll.rs @@ -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) -> 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(&self, source: &mut S) -> io::Result<()> where S: Source + ?Sized, diff --git a/ylong_io/src/source.rs b/ylong_io/src/source.rs index fa5f2f6..7cfbd59 100644 --- a/ylong_io/src/source.rs +++ b/ylong_io/src/source.rs @@ -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, diff --git a/ylong_io/src/sys/linux/epoll.rs b/ylong_io/src/sys/linux/epoll.rs index 0d0fc96..a63a7c6 100644 --- a/ylong_io/src/sys/linux/epoll.rs +++ b/ylong_io/src/sys/linux/epoll.rs @@ -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) -> 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(); diff --git a/ylong_io/src/sys/linux/socket_addr.rs b/ylong_io/src/sys/linux/socket_addr.rs index f34446c..ab82a30 100644 --- a/ylong_io/src/sys/linux/socket_addr.rs +++ b/ylong_io/src/sys/linux/socket_addr.rs @@ -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, diff --git a/ylong_io/src/sys/linux/tcp/listener.rs b/ylong_io/src/sys/linux/tcp/listener.rs index 2450856..b9311a7 100644 --- a/ylong_io/src/sys/linux/tcp/listener.rs +++ b/ylong_io/src/sys/linux/tcp/listener.rs @@ -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 { @@ -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 = MaybeUninit::uninit(); let mut length = size_of::() as socklen_t; diff --git a/ylong_io/src/sys/linux/tcp/socket.rs b/ylong_io/src/sys/linux/tcp/socket.rs index e210da8..17de034 100644 --- a/ylong_io/src/sys/linux/tcp/socket.rs +++ b/ylong_io/src/sys/linux/tcp/socket.rs @@ -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, } diff --git a/ylong_io/src/sys/linux/tcp/stream.rs b/ylong_io/src/sys/linux/tcp/stream.rs index 37d92d2..73a41f4 100644 --- a/ylong_io/src/sys/linux/tcp/stream.rs +++ b/ylong_io/src/sys/linux/tcp/stream.rs @@ -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 { diff --git a/ylong_io/src/sys/linux/udp/socket.rs b/ylong_io/src/sys/linux/udp/socket.rs index fd2bdb2..db56955 100644 --- a/ylong_io/src/sys/linux/udp/socket.rs +++ b/ylong_io/src/sys/linux/udp/socket.rs @@ -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, } diff --git a/ylong_io/src/sys/linux/udp/udp_socket.rs b/ylong_io/src/sys/linux/udp/udp_socket.rs index d8bf933..3fbe69d 100644 --- a/ylong_io/src/sys/linux/udp/udp_socket.rs +++ b/ylong_io/src/sys/linux/udp/udp_socket.rs @@ -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) } diff --git a/ylong_io/src/sys/linux/waker.rs b/ylong_io/src/sys/linux/waker.rs index 6cdd3e7..45b5329 100644 --- a/ylong_io/src/sys/linux/waker.rs +++ b/ylong_io/src/sys/linux/waker.rs @@ -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, diff --git a/ylong_io/src/sys/windows/afd.rs b/ylong_io/src/sys/windows/afd.rs index aefeae4..c3c3818 100644 --- a/ylong_io/src/sys/windows/afd.rs +++ b/ylong_io/src/sys/windows/afd.rs @@ -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, diff --git a/ylong_io/src/sys/windows/events.rs b/ylong_io/src/sys/windows/events.rs index 69905ed..b9f3c5a 100644 --- a/ylong_io/src/sys/windows/events.rs +++ b/ylong_io/src/sys/windows/events.rs @@ -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)] diff --git a/ylong_io/src/sys/windows/handle.rs b/ylong_io/src/sys/windows/handle.rs index 434461b..123c3d1 100644 --- a/ylong_io/src/sys/windows/handle.rs +++ b/ylong_io/src/sys/windows/handle.rs @@ -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 diff --git a/ylong_io/src/sys/windows/io_status_block.rs b/ylong_io/src/sys/windows/io_status_block.rs index bf57233..10a21ff 100644 --- a/ylong_io/src/sys/windows/io_status_block.rs +++ b/ylong_io/src/sys/windows/io_status_block.rs @@ -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); diff --git a/ylong_io/src/sys/windows/iocp.rs b/ylong_io/src/sys/windows/iocp.rs index 8a433ca..c7f776e 100644 --- a/ylong_io/src/sys/windows/iocp.rs +++ b/ylong_io/src/sys/windows/iocp.rs @@ -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], diff --git a/ylong_io/src/sys/windows/net.rs b/ylong_io/src/sys/windows/net.rs index aba1e02..cdc6e25 100644 --- a/ylong_io/src/sys/windows/net.rs +++ b/ylong_io/src/sys/windows/net.rs @@ -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(&self, task: F, io: &T) -> io::Result where F: FnOnce(&T) -> io::Result, diff --git a/ylong_io/src/sys/windows/overlapped.rs b/ylong_io/src/sys/windows/overlapped.rs index bfc7a38..6c015e4 100644 --- a/ylong_io/src/sys/windows/overlapped.rs +++ b/ylong_io/src/sys/windows/overlapped.rs @@ -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 diff --git a/ylong_io/src/sys/windows/selector.rs b/ylong_io/src/sys/windows/selector.rs index 4f5c13a..4cff099 100644 --- a/ylong_io/src/sys/windows/selector.rs +++ b/ylong_io/src/sys/windows/selector.rs @@ -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, @@ -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 and put it in the asynchronous IO structure + /// No actual system call is made at register, it only starts at + /// Poll::poll(). Return Arc and put it in the asynchronous + /// IO structure pub(crate) fn register( this: &Arc, 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; diff --git a/ylong_io/src/sys/windows/socket_addr.rs b/ylong_io/src/sys/windows/socket_addr.rs index 1ee15af..203158c 100644 --- a/ylong_io/src/sys/windows/socket_addr.rs +++ b/ylong_io/src/sys/windows/socket_addr.rs @@ -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, diff --git a/ylong_io/src/sys/windows/tcp/listener.rs b/ylong_io/src/sys/windows/tcp/listener.rs index 90ba172..c31093e 100644 --- a/ylong_io/src/sys/windows/tcp/listener.rs +++ b/ylong_io/src/sys/windows/tcp/listener.rs @@ -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( diff --git a/ylong_io/src/sys/windows/tcp/socket.rs b/ylong_io/src/sys/windows/tcp/socket.rs index 533cfe3..991e74e 100644 --- a/ylong_io/src/sys/windows/tcp/socket.rs +++ b/ylong_io/src/sys/windows/tcp/socket.rs @@ -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); diff --git a/ylong_io/src/sys/windows/tcp/stream.rs b/ylong_io/src/sys/windows/tcp/stream.rs index d10f71e..b27755b 100644 --- a/ylong_io/src/sys/windows/tcp/stream.rs +++ b/ylong_io/src/sys/windows/tcp/stream.rs @@ -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 { 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 { 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> { @@ -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"); /// ``` diff --git a/ylong_io/src/sys/windows/udp/socket.rs b/ylong_io/src/sys/windows/udp/socket.rs index 6886228..c435957 100644 --- a/ylong_io/src/sys/windows/udp/socket.rs +++ b/ylong_io/src/sys/windows/udp/socket.rs @@ -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, diff --git a/ylong_io/src/sys/windows/udp/udp_socket.rs b/ylong_io/src/sys/windows/udp/udp_socket.rs index a40cde7..1718d56 100644 --- a/ylong_io/src/sys/windows/udp/udp_socket.rs +++ b/ylong_io/src/sys/windows/udp/udp_socket.rs @@ -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 { 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 { 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 { 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 { @@ -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 { 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 { 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 { 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]), diff --git a/ylong_io/src/sys/windows/waker.rs b/ylong_io/src/sys/windows/waker.rs index 84c9a84..c83c1a8 100644 --- a/ylong_io/src/sys/windows/waker.rs +++ b/ylong_io/src/sys/windows/waker.rs @@ -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, diff --git a/ylong_io/src/waker.rs b/ylong_io/src/waker.rs index b19c07f..866cb22 100644 --- a/ylong_io/src/waker.rs +++ b/ylong_io/src/waker.rs @@ -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)] diff --git a/ylong_io/tests/udp_socket_test.rs b/ylong_io/tests/udp_socket_test.rs index b53b619..9f67296 100644 --- a/ylong_io/tests/udp_socket_test.rs +++ b/ylong_io/tests/udp_socket_test.rs @@ -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(); diff --git a/ylong_runtime/benches/bin/ylong_runtime_async_benchmark.rs b/ylong_runtime/benches/bin/ylong_runtime_async_benchmark.rs index 8b31846..944760c 100644 --- a/ylong_runtime/benches/bin/ylong_runtime_async_benchmark.rs +++ b/ylong_runtime/benches/bin/ylong_runtime_async_benchmark.rs @@ -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}; diff --git a/ylong_runtime/benches/bin/ylong_runtime_tcp_client_perf.rs b/ylong_runtime/benches/bin/ylong_runtime_tcp_client_perf.rs index 414f911..cf843df 100644 --- a/ylong_runtime/benches/bin/ylong_runtime_tcp_client_perf.rs +++ b/ylong_runtime/benches/bin/ylong_runtime_tcp_client_perf.rs @@ -15,6 +15,7 @@ use std::io; use std::time::Instant; + use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; use ylong_runtime::net::TcpStream; diff --git a/ylong_runtime/benches/bin/ylong_runtime_tcp_server_perf.rs b/ylong_runtime/benches/bin/ylong_runtime_tcp_server_perf.rs index ee5cfd2..f670082 100644 --- a/ylong_runtime/benches/bin/ylong_runtime_tcp_server_perf.rs +++ b/ylong_runtime/benches/bin/ylong_runtime_tcp_server_perf.rs @@ -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; diff --git a/ylong_runtime/benches/bin/ylong_sync_mutex_perf.rs b/ylong_runtime/benches/bin/ylong_sync_mutex_perf.rs index 270e2ab..075a9af 100644 --- a/ylong_runtime/benches/bin/ylong_sync_mutex_perf.rs +++ b/ylong_runtime/benches/bin/ylong_sync_mutex_perf.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use std::time::Instant; + use ylong_runtime::sync::Mutex; fn main() { diff --git a/ylong_runtime/benches/bin/ylong_sync_rwlock_perf.rs b/ylong_runtime/benches/bin/ylong_sync_rwlock_perf.rs index bd8bdfb..c55243c 100644 --- a/ylong_runtime/benches/bin/ylong_sync_rwlock_perf.rs +++ b/ylong_runtime/benches/bin/ylong_sync_rwlock_perf.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use std::time::Instant; + use ylong_runtime::sync::rwlock::RwLock; fn main() { diff --git a/ylong_runtime/benches/bin/ylong_tokio_mem.rs b/ylong_runtime/benches/bin/ylong_tokio_mem.rs index 33f219a..468e215 100644 --- a/ylong_runtime/benches/bin/ylong_tokio_mem.rs +++ b/ylong_runtime/benches/bin/ylong_tokio_mem.rs @@ -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; diff --git a/ylong_runtime/benches/bin/ylong_tokio_spawn.rs b/ylong_runtime/benches/bin/ylong_tokio_spawn.rs index 51421a3..6fd87a6 100644 --- a/ylong_runtime/benches/bin/ylong_tokio_spawn.rs +++ b/ylong_runtime/benches/bin/ylong_tokio_spawn.rs @@ -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; diff --git a/ylong_runtime/benches/bin/ylong_tokio_tcp_perf.rs b/ylong_runtime/benches/bin/ylong_tokio_tcp_perf.rs index 389e4d4..3579052 100644 --- a/ylong_runtime/benches/bin/ylong_tokio_tcp_perf.rs +++ b/ylong_runtime/benches/bin/ylong_tokio_tcp_perf.rs @@ -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; diff --git a/ylong_runtime/benches/sync_benchmarks.rs b/ylong_runtime/benches/sync_benchmarks.rs index 3a2398c..639b76b 100644 --- a/ylong_runtime/benches/sync_benchmarks.rs +++ b/ylong_runtime/benches/sync_benchmarks.rs @@ -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(|| { diff --git a/ylong_runtime/benches/task_helpers/mod.rs b/ylong_runtime/benches/task_helpers/mod.rs index 59451d7..2a6c42c 100644 --- a/ylong_runtime/benches/task_helpers/mod.rs +++ b/ylong_runtime/benches/task_helpers/mod.rs @@ -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; diff --git a/ylong_runtime/benches/ylong_tokio_async_file.rs b/ylong_runtime/benches/ylong_tokio_async_file.rs index e184ff4..65fb94b 100644 --- a/ylong_runtime/benches/ylong_tokio_async_file.rs +++ b/ylong_runtime/benches/ylong_tokio_async_file.rs @@ -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); } diff --git a/ylong_runtime/benches/ylong_tokio_multi_threaded.rs b/ylong_runtime/benches/ylong_tokio_multi_threaded.rs index 2f2d45f..b7c7fe9 100644 --- a/ylong_runtime/benches/ylong_tokio_multi_threaded.rs +++ b/ylong_runtime/benches/ylong_tokio_multi_threaded.rs @@ -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); diff --git a/ylong_runtime/benches/ylong_tokio_mutex.rs b/ylong_runtime/benches/ylong_tokio_mutex.rs index 9eaf0a4..e0f17bf 100644 --- a/ylong_runtime/benches/ylong_tokio_mutex.rs +++ b/ylong_runtime/benches/ylong_tokio_mutex.rs @@ -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); diff --git a/ylong_runtime/benches/ylong_tokio_rwlock.rs b/ylong_runtime/benches/ylong_tokio_rwlock.rs index 589635e..73b2246 100644 --- a/ylong_runtime/benches/ylong_tokio_rwlock.rs +++ b/ylong_runtime/benches/ylong_tokio_rwlock.rs @@ -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 {}); diff --git a/ylong_runtime/benches/ylong_tokio_schedule.rs b/ylong_runtime/benches/ylong_tokio_schedule.rs index dc85a04..09dbebc 100644 --- a/ylong_runtime/benches/ylong_tokio_schedule.rs +++ b/ylong_runtime/benches/ylong_tokio_schedule.rs @@ -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); diff --git a/ylong_runtime/benches/ylong_tokio_tcp.rs b/ylong_runtime/benches/ylong_tokio_tcp.rs index ae01908..245509d 100644 --- a/ylong_runtime/benches/ylong_tokio_tcp.rs +++ b/ylong_runtime/benches/ylong_tokio_tcp.rs @@ -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, diff --git a/ylong_runtime/benches/ylong_tokio_udp.rs b/ylong_runtime/benches/ylong_tokio_udp.rs index 4ce9b37..b7cbc18 100644 --- a/ylong_runtime/benches/ylong_tokio_udp.rs +++ b/ylong_runtime/benches/ylong_tokio_udp.rs @@ -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:"; diff --git a/ylong_runtime/examples/ylong_runtime_memory.rs b/ylong_runtime/examples/ylong_runtime_memory.rs index 41cfae1..943f103 100644 --- a/ylong_runtime/examples/ylong_runtime_memory.rs +++ b/ylong_runtime/examples/ylong_runtime_memory.rs @@ -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)] diff --git a/ylong_runtime/examples/ylong_runtime_multi_runtimes.rs b/ylong_runtime/examples/ylong_runtime_multi_runtimes.rs index 99ca767..3a9b388 100644 --- a/ylong_runtime/examples/ylong_runtime_multi_runtimes.rs +++ b/ylong_runtime/examples/ylong_runtime_multi_runtimes.rs @@ -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) diff --git a/ylong_runtime/examples/ylong_runtime_tcp.rs b/ylong_runtime/examples/ylong_runtime_tcp.rs index 8cca677..d285587 100644 --- a/ylong_runtime/examples/ylong_runtime_tcp.rs +++ b/ylong_runtime/examples/ylong_runtime_tcp.rs @@ -13,6 +13,7 @@ //! An example for `tcp` use std::net::SocketAddr; + use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; use ylong_runtime::net::{TcpListener, TcpStream}; diff --git a/ylong_runtime/examples/ylong_runtime_timer_sleep.rs b/ylong_runtime/examples/ylong_runtime_timer_sleep.rs index 8d90d2f..0147662 100644 --- a/ylong_runtime/examples/ylong_runtime_timer_sleep.rs +++ b/ylong_runtime/examples/ylong_runtime_timer_sleep.rs @@ -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; diff --git a/ylong_runtime/examples/ylong_tokio_schedule.rs b/ylong_runtime/examples/ylong_tokio_schedule.rs index 94edf64..31e695c 100644 --- a/ylong_runtime/examples/ylong_tokio_schedule.rs +++ b/ylong_runtime/examples/ylong_tokio_schedule.rs @@ -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 { diff --git a/ylong_runtime/src/builder/common_builder.rs b/ylong_runtime/src/builder/common_builder.rs index 456a470..e0db003 100644 --- a/ylong_runtime/src/builder/common_builder.rs +++ b/ylong_runtime/src/builder/common_builder.rs @@ -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 diff --git a/ylong_runtime/src/builder/current_thread_builder.rs b/ylong_runtime/src/builder/current_thread_builder.rs index 0c16621..f8f9a2e 100644 --- a/ylong_runtime/src/builder/current_thread_builder.rs +++ b/ylong_runtime/src/builder/current_thread_builder.rs @@ -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 { diff --git a/ylong_runtime/src/builder/mod.rs b/ylong_runtime/src/builder/mod.rs index e511cc1..4b0e3af 100644 --- a/ylong_runtime/src/builder/mod.rs +++ b/ylong_runtime/src/builder/mod.rs @@ -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; /// 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() { diff --git a/ylong_runtime/src/builder/multi_thread_builder.rs b/ylong_runtime/src/builder/multi_thread_builder.rs index ba99d8a..90df9d0 100644 --- a/ylong_runtime/src/builder/multi_thread_builder.rs +++ b/ylong_runtime/src/builder/multi_thread_builder.rs @@ -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> = 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 diff --git a/ylong_runtime/src/error.rs b/ylong_runtime/src/error.rs index 7c67646..23016a2 100644 --- a/ylong_runtime/src/error.rs +++ b/ylong_runtime/src/error.rs @@ -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 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(); diff --git a/ylong_runtime/src/executor/async_pool.rs b/ylong_runtime/src/executor/async_pool.rs index c85be06..a74fdeb 100644 --- a/ylong_runtime/src/executor/async_pool.rs +++ b/ylong_runtime/src/executor/async_pool.rs @@ -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>, - /// 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 diff --git a/ylong_runtime/src/executor/blocking_pool.rs b/ylong_runtime/src/executor/blocking_pool.rs index b8e6ea6..1cd83d1 100644 --- a/ylong_runtime/src/executor/blocking_pool.rs +++ b/ylong_runtime/src/executor/blocking_pool.rs @@ -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); diff --git a/ylong_runtime/src/executor/current_thread.rs b/ylong_runtime/src/executor/current_thread.rs index bff3a0b..2f9127d 100644 --- a/ylong_runtime/src/executor/current_thread.rs +++ b/ylong_runtime/src/executor/current_thread.rs @@ -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() { diff --git a/ylong_runtime/src/executor/mod.rs b/ylong_runtime/src/executor/mod.rs index 3e9ba91..685684b 100644 --- a/ylong_runtime/src/executor/mod.rs +++ b/ylong_runtime/src/executor/mod.rs @@ -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 /// diff --git a/ylong_runtime/src/executor/netpoller.rs b/ylong_runtime/src/executor/netpoller.rs index f3520f6..9906c23 100644 --- a/ylong_runtime/src/executor/netpoller.rs +++ b/ylong_runtime/src/executor/netpoller.rs @@ -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); diff --git a/ylong_runtime/src/executor/parker.rs b/ylong_runtime/src/executor/parker.rs index fbcbd26..bc531ef 100644 --- a/ylong_runtime/src/executor/parker.rs +++ b/ylong_runtime/src/executor/parker.rs @@ -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, diff --git a/ylong_runtime/src/executor/queue.rs b/ylong_runtime/src/executor/queue.rs index 08856dd..9b45671 100644 --- a/ylong_runtime/src/executor/queue.rs +++ b/ylong_runtime/src/executor/queue.rs @@ -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 { 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(); diff --git a/ylong_runtime/src/executor/worker.rs b/ylong_runtime/src/executor/worker.rs index e142bf5..956c250 100644 --- a/ylong_runtime/src/executor/worker.rs +++ b/ylong_runtime/src/executor/worker.rs @@ -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()); diff --git a/ylong_runtime/src/ffrt/spawner.rs b/ylong_runtime/src/ffrt/spawner.rs index c0ebafe..9822267 100644 --- a/ylong_runtime/src/ffrt/spawner.rs +++ b/ylong_runtime/src/ffrt/spawner.rs @@ -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 { diff --git a/ylong_runtime/src/fs/async_dir.rs b/ylong_runtime/src/fs/async_dir.rs index 46b7a3f..5c6f994 100644 --- a/ylong_runtime/src/fs/async_dir.rs +++ b/ylong_runtime/src/fs/async_dir.rs @@ -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>(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>(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>(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>(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>(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>(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(()) /// } diff --git a/ylong_runtime/src/fs/async_file.rs b/ylong_runtime/src/fs/async_file.rs index 927f439..c3b47ee 100644 --- a/ylong_runtime/src/fs/async_file.rs +++ b/ylong_runtime/src/fs/async_file.rs @@ -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, inner: Mutex, @@ -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); diff --git a/ylong_runtime/src/fs/file_buf.rs b/ylong_runtime/src/fs/file_buf.rs index 1179869..ee56c21 100644 --- a/ylong_runtime/src/fs/file_buf.rs +++ b/ylong_runtime/src/fs/file_buf.rs @@ -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, idx: usize, diff --git a/ylong_runtime/src/fs/mod.rs b/ylong_runtime/src/fs/mod.rs index 61f8f3d..08756c1 100644 --- a/ylong_runtime/src/fs/mod.rs +++ b/ylong_runtime/src/fs/mod.rs @@ -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(task: T) -> io::Result where diff --git a/ylong_runtime/src/fs/open_options.rs b/ylong_runtime/src/fs/open_options.rs index 48a49a5..bff21e9 100644 --- a/ylong_runtime/src/fs/open_options.rs +++ b/ylong_runtime/src/fs/open_options.rs @@ -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] diff --git a/ylong_runtime/src/futures.rs b/ylong_runtime/src/futures.rs index f90fe6b..d571eaa 100644 --- a/ylong_runtime/src/futures.rs +++ b/ylong_runtime/src/futures.rs @@ -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, } diff --git a/ylong_runtime/src/io/async_buf_read.rs b/ylong_runtime/src/io/async_buf_read.rs index f8c83c5..fbc7469 100644 --- a/ylong_runtime/src/io/async_buf_read.rs +++ b/ylong_runtime/src/io/async_buf_read.rs @@ -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>; - /// 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 diff --git a/ylong_runtime/src/io/async_read.rs b/ylong_runtime/src/io/async_read.rs index 9929fcb..8a66ab9 100644 --- a/ylong_runtime/src/io/async_read.rs +++ b/ylong_runtime/src/io/async_read.rs @@ -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 diff --git a/ylong_runtime/src/io/async_seek.rs b/ylong_runtime/src/io/async_seek.rs index 4ab5ec0..7b769ae 100644 --- a/ylong_runtime/src/io/async_seek.rs +++ b/ylong_runtime/src/io/async_seek.rs @@ -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 AsyncSeek for &mut T { impl 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 diff --git a/ylong_runtime/src/io/async_write.rs b/ylong_runtime/src/io/async_write.rs index 7419b24..47dac01 100644 --- a/ylong_runtime/src/io/async_write.rs +++ b/ylong_runtime/src/io/async_write.rs @@ -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>; - /// 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>; } @@ -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> { 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 diff --git a/ylong_runtime/src/io/buffered/async_buf_reader.rs b/ylong_runtime/src/io/buffered/async_buf_reader.rs index 0f82b0f..988e48e 100644 --- a/ylong_runtime/src/io/buffered/async_buf_reader.rs +++ b/ylong_runtime/src/io/buffered/async_buf_reader.rs @@ -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` 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` 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` is dropped, the contents inside its buffer will be discarded. -/// Creating multiple instances of `AsyncBufReader` on the same [`AsyncRead`] stream may cause -/// data loss. +/// When the `AsyncBufReader` is dropped, the contents inside its buffer will +/// be discarded. Creating multiple instances of `AsyncBufReader` on the same +/// [`AsyncRead`] stream may cause data loss. pub struct AsyncBufReader { inner: R, buf: Box<[u8]>, @@ -37,7 +39,8 @@ pub struct AsyncBufReader { impl AsyncBufReader { /// Creates a new `AsyncBufReader` 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 AsyncBufReader { /// Unwraps this `AsyncBufReader`, 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 } diff --git a/ylong_runtime/src/io/buffered/async_buf_writer.rs b/ylong_runtime/src/io/buffered/async_buf_writer.rs index 225a0dc..90b273a 100644 --- a/ylong_runtime/src/io/buffered/async_buf_writer.rs +++ b/ylong_runtime/src/io/buffered/async_buf_writer.rs @@ -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` 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` 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` is dropped, the contents inside its buffer will be discarded. -/// Creating multiple instances of `AsyncBufWriter` on the same [`AsyncWrite`] stream may cause -/// data loss. +/// When the `AsyncBufWriter` is dropped, the contents inside its buffer will +/// be discarded. Creating multiple instances of `AsyncBufWriter` on the same +/// [`AsyncWrite`] stream may cause data loss. pub struct AsyncBufWriter { inner: W, buf: Vec, @@ -35,7 +37,8 @@ pub struct AsyncBufWriter { impl AsyncBufWriter { /// Creates a new `AsyncBufWriter` 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 AsyncBufWriter { /// Unwraps this `AsyncBufWriter`, 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 } diff --git a/ylong_runtime/src/io/read_buf.rs b/ylong_runtime/src/io/read_buf.rs index 21355e2..3bbd924 100644 --- a/ylong_runtime/src/io/read_buf.rs +++ b/ylong_runtime/src/io/read_buf.rs @@ -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] 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] { @@ -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] 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() { diff --git a/ylong_runtime/src/io/read_task.rs b/ylong_runtime/src/io/read_task.rs index ff8e10f..ec953e6 100644 --- a/ylong_runtime/src/io/read_task.rs +++ b/ylong_runtime/src/io/read_task.rs @@ -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( cx: &mut Context<'_>, ) -> Poll> { 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 { @@ -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 { diff --git a/ylong_runtime/src/io/seek_task.rs b/ylong_runtime/src/io/seek_task.rs index 3dd91d7..b49d367 100644 --- a/ylong_runtime/src/io/seek_task.rs +++ b/ylong_runtime/src/io/seek_task.rs @@ -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`] diff --git a/ylong_runtime/src/io/write_task.rs b/ylong_runtime/src/io/write_task.rs index e650d1f..b95e012 100644 --- a/ylong_runtime/src/io/write_task.rs +++ b/ylong_runtime/src/io/write_task.rs @@ -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() { diff --git a/ylong_runtime/src/iter/core.rs b/ylong_runtime/src/iter/core.rs index 50d6001..f5f9155 100644 --- a/ylong_runtime/src/iter/core.rs +++ b/ylong_runtime/src/iter/core.rs @@ -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( @@ -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( diff --git a/ylong_runtime/src/iter/mod.rs b/ylong_runtime/src/iter/mod.rs index b6433e4..5d09b48 100644 --- a/ylong_runtime/src/iter/mod.rs +++ b/ylong_runtime/src/iter/mod.rs @@ -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 diff --git a/ylong_runtime/src/iter/parallel/array.rs b/ylong_runtime/src/iter/parallel/array.rs index 9848bf8..8094e4d 100644 --- a/ylong_runtime/src/iter/parallel/array.rs +++ b/ylong_runtime/src/iter/parallel/array.rs @@ -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]; diff --git a/ylong_runtime/src/iter/parallel/collections/binary_heap.rs b/ylong_runtime/src/iter/parallel/collections/binary_heap.rs index 407e185..f4208d1 100644 --- a/ylong_runtime/src/iter/parallel/collections/binary_heap.rs +++ b/ylong_runtime/src/iter/parallel/collections/binary_heap.rs @@ -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, Vec, into_iter, impl ); diff --git a/ylong_runtime/src/iter/parallel/collections/btree_map.rs b/ylong_runtime/src/iter/parallel/collections/btree_map.rs index 1035d4d..9e460f2 100644 --- a/ylong_runtime/src/iter/parallel/collections/btree_map.rs +++ b/ylong_runtime/src/iter/parallel/collections/btree_map.rs @@ -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, Vec<(T,V)>, into_iter, impl ); diff --git a/ylong_runtime/src/iter/parallel/collections/btree_set.rs b/ylong_runtime/src/iter/parallel/collections/btree_set.rs index 7faf833..1405fe6 100644 --- a/ylong_runtime/src/iter/parallel/collections/btree_set.rs +++ b/ylong_runtime/src/iter/parallel/collections/btree_set.rs @@ -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, Vec, into_iter, impl ); diff --git a/ylong_runtime/src/iter/parallel/collections/hash_map.rs b/ylong_runtime/src/iter/parallel/collections/hash_map.rs index 1272568..b22e630 100644 --- a/ylong_runtime/src/iter/parallel/collections/hash_map.rs +++ b/ylong_runtime/src/iter/parallel/collections/hash_map.rs @@ -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, Vec<(T, V)>, into_iter, impl ); diff --git a/ylong_runtime/src/iter/parallel/collections/hash_set.rs b/ylong_runtime/src/iter/parallel/collections/hash_set.rs index 171c910..72d40a1 100644 --- a/ylong_runtime/src/iter/parallel/collections/hash_set.rs +++ b/ylong_runtime/src/iter/parallel/collections/hash_set.rs @@ -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::HashSet; -use crate::iter::parallel::IntoParIter; -use crate::iter::parallel::ParIter; +use super::par_vec_impl; +use crate::iter::parallel::{IntoParIter, ParIter}; par_vec_impl!(HashSet, Vec, into_iter, impl ); diff --git a/ylong_runtime/src/iter/parallel/collections/linked_list.rs b/ylong_runtime/src/iter/parallel/collections/linked_list.rs index 2407358..4bbd1d7 100644 --- a/ylong_runtime/src/iter/parallel/collections/linked_list.rs +++ b/ylong_runtime/src/iter/parallel/collections/linked_list.rs @@ -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::LinkedList; -use crate::iter::parallel::IntoParIter; -use crate::iter::parallel::ParIter; +use super::par_vec_impl; +use crate::iter::parallel::{IntoParIter, ParIter}; par_vec_impl!(LinkedList, Vec, into_iter, impl ); diff --git a/ylong_runtime/src/iter/parallel/collections/vec_deque.rs b/ylong_runtime/src/iter/parallel/collections/vec_deque.rs index f671f04..330b16c 100644 --- a/ylong_runtime/src/iter/parallel/collections/vec_deque.rs +++ b/ylong_runtime/src/iter/parallel/collections/vec_deque.rs @@ -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::VecDeque; -use crate::iter::parallel::IntoParIter; -use crate::iter::parallel::ParIter; +use super::par_vec_impl; +use crate::iter::parallel::{IntoParIter, ParIter}; par_vec_impl!(VecDeque, Vec, into_iter, impl ); par_vec_impl!(&'a VecDeque, Vec<&'a T>, iter, impl <'a, T>); diff --git a/ylong_runtime/src/iter/parallel/mod.rs b/ylong_runtime/src/iter/parallel/mod.rs index 970ddd4..dda4e85 100644 --- a/ylong_runtime/src/iter/parallel/mod.rs +++ b/ylong_runtime/src/iter/parallel/mod.rs @@ -32,7 +32,8 @@ pub trait ParSplit: Sized + IntoIterator { /// Reduces the number of elements in the data fn reduce(self, len: usize) -> Self; - /// Splits data into two parts, if it can no longer be divided, returns None. + /// Splits data into two parts, if it can no longer be divided, returns + /// None. fn split(self) -> (Self, Option); /// Returns true if the parsplit has a length of 0 diff --git a/ylong_runtime/src/iter/parallel/vec.rs b/ylong_runtime/src/iter/parallel/vec.rs index 036f553..65a6aca 100644 --- a/ylong_runtime/src/iter/parallel/vec.rs +++ b/ylong_runtime/src/iter/parallel/vec.rs @@ -11,9 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::IntoParIter; -use super::ParIter; -use super::ParSplit; +use super::{IntoParIter, ParIter, ParSplit}; impl ParSplit for Vec { fn len(&self) -> usize { diff --git a/ylong_runtime/src/iter/pariter/filter.rs b/ylong_runtime/src/iter/pariter/filter.rs index f0b822e..4a19ce5 100644 --- a/ylong_runtime/src/iter/pariter/filter.rs +++ b/ylong_runtime/src/iter/pariter/filter.rs @@ -11,9 +11,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::ParallelIterator; use std::iter; +use super::ParallelIterator; + pub fn filter(par_iter: P, predicate: F) -> Filter { Filter { base: par_iter, diff --git a/ylong_runtime/src/iter/pariter/for_each.rs b/ylong_runtime/src/iter/pariter/for_each.rs index 6c3d41f..eddadaf 100644 --- a/ylong_runtime/src/iter/pariter/for_each.rs +++ b/ylong_runtime/src/iter/pariter/for_each.rs @@ -11,9 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::error::ScheduleError; - use super::{Consumer, ParallelIterator}; +use crate::error::ScheduleError; pub async fn for_each(par_iter: P, f: F) -> Result<(), ScheduleError> where diff --git a/ylong_runtime/src/iter/pariter/mod.rs b/ylong_runtime/src/iter/pariter/mod.rs index 428ca51..a150875 100644 --- a/ylong_runtime/src/iter/pariter/mod.rs +++ b/ylong_runtime/src/iter/pariter/mod.rs @@ -11,12 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::error::ScheduleError; - +use std::iter::Sum; use std::ops::Add; -use std::{iter::Sum, pin::Pin}; +use std::pin::Pin; use super::core::core; +use crate::error::ScheduleError; mod map; use map::Map; @@ -44,7 +44,8 @@ pub trait ParallelIterator: Sized + Send { /// Returns the number of elements in this parallel iterator. fn len(&self) -> usize; - /// Removes redundant elements, used in zip function, so that the two parts has the same length. + /// Removes redundant elements, used in zip function, so that the two parts + /// has the same length. fn reduce(self, len: usize) -> Self; /// Returns the std iterator. @@ -78,7 +79,8 @@ pub trait ParallelIterator: Sized + Send { zip::zip(self, another) } - /// Execute the OP in parallel on each element produced by the parallel iterator. + /// Execute the OP in parallel on each element produced by the parallel + /// iterator. fn for_each<'a, F>( self, f: F, diff --git a/ylong_runtime/src/iter/pariter/sum.rs b/ylong_runtime/src/iter/pariter/sum.rs index b9f07b5..7a528e1 100644 --- a/ylong_runtime/src/iter/pariter/sum.rs +++ b/ylong_runtime/src/iter/pariter/sum.rs @@ -11,11 +11,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::error::ScheduleError; use core::ops::Add; use std::iter::Sum; use super::{Consumer, ParallelIterator}; +use crate::error::ScheduleError; pub async fn sum

(par_iter: P) -> Result where diff --git a/ylong_runtime/src/iter/pariter/zip.rs b/ylong_runtime/src/iter/pariter/zip.rs index 0cfe22a..d5d4ce3 100644 --- a/ylong_runtime/src/iter/pariter/zip.rs +++ b/ylong_runtime/src/iter/pariter/zip.rs @@ -11,9 +11,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::ParallelIterator; use std::iter; +use super::ParallelIterator; + pub fn zip(mut a: A, mut b: B) -> Zip where A: ParallelIterator, diff --git a/ylong_runtime/src/lib.rs b/ylong_runtime/src/lib.rs index e8878d1..de17f59 100644 --- a/ylong_runtime/src/lib.rs +++ b/ylong_runtime/src/lib.rs @@ -25,10 +25,11 @@ compile_error!("Feature ffrt only works on linux currently"); extern crate core; +use std::future::Future; + use crate::error::ScheduleError; use crate::macros::cfg_io; use crate::task::{JoinHandle, Task, TaskBuilder}; -use std::future::Future; pub mod builder; pub mod error; diff --git a/ylong_runtime/src/net/async_source.rs b/ylong_runtime/src/net/async_source.rs index 27b9758..c6fdad7 100644 --- a/ylong_runtime/src/net/async_source.rs +++ b/ylong_runtime/src/net/async_source.rs @@ -11,12 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::io; +use std::ops::Deref; + +use ylong_io::{Interest, Source}; + use crate::macros::cfg_io; use crate::net::ScheduleIO; use crate::util::slab::Ref; -use std::io; -use std::ops::Deref; -use ylong_io::{Interest, Source}; cfg_io!( use std::task::{Context, Poll}; @@ -28,27 +30,29 @@ cfg_io!( use std::io::{Read, Write}; ); -/// Wrapper that turns a sync `Source` io into an async one. This struct interacts with the reactor -/// of the runtime. +/// Wrapper that turns a sync `Source` io into an async one. This struct +/// interacts with the reactor of the runtime. pub(crate) struct AsyncSource { /// Sync io that implements `Source` trait. io: Option, - /// Entry list of the runtime's reactor, `AsyncSource` object will be registered into it - /// when created. + /// Entry list of the runtime's reactor, `AsyncSource` object will be + /// registered into it when created. pub(crate) entry: Ref, } impl AsyncSource { - /// Wraps a `Source` object into an `AsyncSource`. When the `AsyncSource` object is created, - /// it's fd will be registered into runtime's reactor. + /// Wraps a `Source` object into an `AsyncSource`. When the `AsyncSource` + /// object is created, it's fd will be registered into runtime's + /// reactor. /// - /// If `interest` passed in is None, the interested event for fd registration will be both - /// readable and writable. + /// If `interest` passed in is None, the interested event for fd + /// registration will be both readable and writable. /// /// # Error /// - /// If no reactor is found or fd registration fails, an error will be returned. + /// If no reactor is found or fd registration fails, an error will be + /// returned. #[cfg(not(feature = "ffrt"))] pub fn new(mut io: E, interest: Option) -> io::Result> { let inner = { @@ -68,15 +72,17 @@ impl AsyncSource { }) } - /// Wraps a `Source` object into an `AsyncSource`. When the `AsyncSource` object is created, - /// it's fd will be registered into runtime's reactor. + /// Wraps a `Source` object into an `AsyncSource`. When the `AsyncSource` + /// object is created, it's fd will be registered into runtime's + /// reactor. /// - /// If `interest` passed in is None, the interested event for fd registration will be both - /// readable and writable. + /// If `interest` passed in is None, the interested event for fd + /// registration will be both readable and writable. /// /// # Error /// - /// If no reactor is found or fd registration fails, an error will be returned. + /// If no reactor is found or fd registration fails, an error will be + /// returned. #[cfg(feature = "ffrt")] pub fn new(mut io: E, interest: Option) -> io::Result> { let inner = crate::net::Handle::get_ref(); @@ -89,8 +95,9 @@ impl AsyncSource { }) } - /// Asynchronously waits for events to happen. If the io returns `EWOULDBLOCK`, the readiness - /// of the io will be reset. Otherwise, the corresponding event will be returned. + /// Asynchronously waits for events to happen. If the io returns + /// `EWOULDBLOCK`, the readiness of the io will be reset. Otherwise, the + /// corresponding event will be returned. pub(crate) async fn async_process(&self, interest: Interest, mut op: F) -> io::Result where F: FnMut() -> io::Result, diff --git a/ylong_runtime/src/net/driver.rs b/ylong_runtime/src/net/driver.rs index 569f2b9..8db0e6b 100644 --- a/ylong_runtime/src/net/driver.rs +++ b/ylong_runtime/src/net/driver.rs @@ -11,14 +11,16 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::io; +use std::ops::Deref; +use std::sync::{Arc, Mutex}; + +use ylong_io::{Interest, Source, Token}; + use crate::macros::{cfg_ffrt, cfg_not_ffrt}; use crate::net::{Ready, ScheduleIO, Tick}; use crate::util::bit::{Bit, Mask}; use crate::util::slab::{Address, Ref, Slab}; -use std::io; -use std::ops::Deref; -use std::sync::{Arc, Mutex}; -use ylong_io::{Interest, Source, Token}; cfg_ffrt! { use libc::{c_void, c_int, c_uint}; @@ -34,12 +36,11 @@ cfg_not_ffrt! { const DRIVER_TICK_INIT: u8 = 0; - // Token structure // | reserved | generation | address | // |----------|------------|---------| // | 1 bit | 7 bits | 24 bits | -//const RESERVED: Mask = Mask::new(1, 31); +// const RESERVED: Mask = Mask::new(1, 31); const GENERATION: Mask = Mask::new(7, 24); const ADDRESS: Mask = Mask::new(24, 0); @@ -108,9 +109,10 @@ impl Deref for Handle { /// 1)IO registration /// 2)Resource management pub(crate) struct Inner { - /// When the driver gets dropped, the resources in the driver will be transmitted to here. - /// Then all the slabs inside will get dropped when Inner's ref count clears to zero, so - /// there is no concurrent problem when new slabs gets inserted + /// When the driver gets dropped, the resources in the driver will be + /// transmitted to here. Then all the slabs inside will get dropped when + /// Inner's ref count clears to zero, so there is no concurrent problem + /// when new slabs gets inserted resources: Mutex>>, /// Used to register scheduleIO into the slab @@ -122,7 +124,8 @@ pub(crate) struct Inner { } impl Driver { - /// IO dispatch function. Wakes the task through the token getting from the epoll events. + /// IO dispatch function. Wakes the task through the token getting from the + /// epoll events. fn dispatch(&mut self, token: Token, ready: Ready) { let addr_bit = Bit::from_usize(token.0); let addr = addr_bit.get_by_mask(ADDRESS); @@ -178,8 +181,8 @@ impl Driver { ) } - /// Runs the driver. This method will blocking wait for fd events to come in and then - /// wakes the corresponding tasks through the events. + /// Runs the driver. This method will blocking wait for fd events to come in + /// and then wakes the corresponding tasks through the events. /// /// In linux environment, the driver uses epoll. pub(crate) fn drive(&mut self, time_out: Option) -> io::Result { @@ -250,9 +253,7 @@ impl Driver { /// Initializes the single instance IO driver. pub(crate) fn get_mut_ref() -> &'static mut Driver { Driver::initialize(); - unsafe { - &mut *DRIVER.as_mut_ptr() - } + unsafe { &mut *DRIVER.as_mut_ptr() } } } @@ -281,7 +282,8 @@ impl Inner { io: &mut impl Source, interest: Interest, ) -> io::Result> { - // Allocates space for the slab. If reaches maximum capacity, error will be returned + // Allocates space for the slab. If reaches maximum capacity, error will be + // returned let (schedule_io, token) = self.allocate_schedule_io_pair()?; self.registry @@ -311,7 +313,8 @@ impl Inner { io: &mut impl Source, interest: Interest, ) -> io::Result> { - // Allocates space for the slab. If reaches maximum capacity, error will be returned + // Allocates space for the slab. If reaches maximum capacity, error will be + // returned let (schedule_io, token) = self.allocate_schedule_io_pair()?; fn interests_to_io_event(interests: Interest) -> c_uint { diff --git a/ylong_runtime/src/net/linked_list.rs b/ylong_runtime/src/net/linked_list.rs index e88e048..a47d33e 100644 --- a/ylong_runtime/src/net/linked_list.rs +++ b/ylong_runtime/src/net/linked_list.rs @@ -75,7 +75,8 @@ impl LinkedList { } pub(crate) fn remove_node(&mut self, mut node: NonNull>) { - let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. + // this one is ours now, we can create an &mut. + let node = unsafe { node.as_mut() }; match node.prev { Some(prev) => unsafe { (*prev.as_ptr()).next = node.next }, diff --git a/ylong_runtime/src/net/mod.rs b/ylong_runtime/src/net/mod.rs index 0de3c5e..bc87768 100644 --- a/ylong_runtime/src/net/mod.rs +++ b/ylong_runtime/src/net/mod.rs @@ -13,17 +13,18 @@ //! Asynchronous TCP/UDP binding for `ylong_runtime` -pub(crate) use crate::schedule_io::{ScheduleIO, Tick}; pub(crate) use driver::Handle; - pub(crate) use linked_list::{LinkedList, Node}; pub(crate) use ready::{Ready, ReadyEvent}; pub use sys::{Listener, Stream}; + +pub(crate) use crate::schedule_io::{ScheduleIO, Tick}; pub(crate) mod async_source; pub(crate) mod sys; -use crate::macros::cfg_io; pub(crate) use async_source::AsyncSource; +use crate::macros::cfg_io; + pub(crate) mod driver; mod linked_list; pub(crate) mod ready; @@ -35,4 +36,4 @@ cfg_io! { } #[cfg(not(feature = "ffrt"))] -pub(crate) use driver::Driver; \ No newline at end of file +pub(crate) use driver::Driver; diff --git a/ylong_runtime/src/net/ready.rs b/ylong_runtime/src/net/ready.rs index 048390b..7a61d7e 100644 --- a/ylong_runtime/src/net/ready.rs +++ b/ylong_runtime/src/net/ready.rs @@ -12,6 +12,7 @@ // limitations under the License. use core::ops; + use ylong_io::Interest; const READABLE: usize = 0b0_01; @@ -212,19 +213,17 @@ crate::macros::cfg_ffrt! { } } -/* -* @title ready from_event function ut test -* @design conditions of use override -* @precon none -* @brief 1. Create an event -* 2. Call from_event -* 3. Verify the returned results -* @expect 1. Event readable to get readable Ready instances -* 2. Event writable, call writable Ready instances -* 3. Event Read Close, Call Read Close Ready Instance -* 4. Event Write Close, Call Write Close Ready Instance -* @auto Yes -*/ +// @title ready from_event function ut test +// @design conditions of use override +// @precon none +// @brief 1. Create an event +// 2. Call from_event +// 3. Verify the returned results +// @expect 1. Event readable to get readable Ready instances +// 2. Event writable, call writable Ready instances +// 3. Event Read Close, Call Read Close Ready Instance +// 4. Event Write Close, Call Write Close Ready Instance +// @auto Yes #[test] #[cfg(feature = "tcp")] fn ut_ready_from_event() { @@ -278,32 +277,23 @@ fn ut_ready_from_event() { } } -/* -* @title ready from_usize function ut test -* @design Use path override -* @precon None -* @brief 1. Enter a usize, call from_usize -* 2. Verify the returned results -* @expect 1. Generate a Ready that is passed into usize -* @auto Yes -*/ +/// UT test cases for ready from_usize function +/// +/// # Brief +/// 1. Enter a usize, call from_usize +/// 2. Verify the returned results #[test] fn ut_ready_from_usize() { let ready = Ready::from_usize(0x01); assert_eq!(ready.0, 0x01); } -/* -* @title ready is_empty function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Ready -* 2. Call is_empty -* 3. Verify the returned results -* @expect 1. Empty Ready instances, return true -* 2. Non-empty Ready instances, return false -* @auto Yes -*/ +/// UT test cases for ready is_empty function +/// +/// # Brief +/// 1. Create a Ready +/// 2. Call is_empty +/// 3. Verify the returned results #[test] fn ut_ready_is_empty() { let ready = Ready::from_usize(0x00); @@ -313,17 +303,12 @@ fn ut_ready_is_empty() { assert!(!ready.is_empty()); } -/* -* @title ready is_readable function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Ready -* 2. Call is_readable -* 3. Verify the returned results -* @expect 1. Readable Ready instances that return true -* 2. Non-readable Ready instance that returns false -* @auto Yes -*/ +/// UT test cases for ready is_readable function +/// +/// # Brief +/// 1. Create a Ready +/// 2. Call is_readable +/// 3. Verify the returned results #[test] fn ut_ready_is_readable() { let ready = Ready::from_usize(0x01); @@ -333,17 +318,12 @@ fn ut_ready_is_readable() { assert!(!ready.is_readable()); } -/* -* @title ready is_writable function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Ready -* 2. Call is_writable -* 3. Verify the returned results -* @expect 1. Writable Ready instances that return true -* 2. Non-writable Ready instance that returns false -* @auto Yes -*/ +/// UT test cases for ready is_writable function +/// +/// # Brief +/// 1. Create a Ready +/// 2. Call is_writable +/// 3. Verify the returned results #[test] fn ut_ready_is_writable() { let ready = Ready::from_usize(0x02); @@ -353,17 +333,12 @@ fn ut_ready_is_writable() { assert!(!ready.is_writable()); } -/* -* @title ready is_read_closed function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Ready -* 2. Call is_read_closed -* 3. Verify the returned results -* @expect 1. Read the closed Ready instance and return true -* 2. Ready instances that are not read off, return false -* @auto Yes -*/ +/// UT test cases for ready is_read_closed function +/// +/// # Brief +/// 1. Create a Ready +/// 2. Call is_read_closed +/// 3. Verify the returned results #[test] fn ut_ready_is_read_closed() { let ready = Ready::from_usize(0x04); @@ -373,17 +348,12 @@ fn ut_ready_is_read_closed() { assert!(!ready.is_read_closed()); } -/* -* @title ready is_write_closed function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Ready -* 2. Call is_write_closed -* 3. Verify the returned results -* @expect 1. Write closed Ready instances, return true -* 2. Ready instances that are not written off return false -* @auto Yes -*/ +/// UT test cases for ready is_write_closed function +/// +/// # Brief +/// 1. Create a Ready +/// 2. Call is_write_closed +/// 3. Verify the returned results #[test] fn ut_ready_is_write_closed() { let ready = Ready::from_usize(0x08); @@ -393,33 +363,24 @@ fn ut_ready_is_write_closed() { assert!(!ready.is_write_closed()); } -/* -* @title ready as_usize function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Ready -* 2. Call as_usize -* 3. Verify the returned results -* @expect 1. Get the usize in Ready -* @auto Yes -*/ +/// UT test cases for ready as_usize function +/// +/// # Brief +/// 1. Create a Ready +/// 2. Call as_usize +/// 3. Verify the returned results #[test] fn ut_ready_as_usize() { let ready = Ready::from_usize(0x08); assert_eq!(ready.as_usize(), 0x08); } -/* -* @title ready from_interest function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Interest instances -* 2. Call from_interest -* 3. Verify the returned results -* @expect 1. Create a readable Interest instances, get readable + read off Ready instances -* 2. Create a writable Interest instances, get writable + write off Ready instances -* @auto Yes -*/ +/// UT test cases for ready from_interest function +/// +/// # Brief +/// 1. Create a Interest instances +/// 2. Call from_interest +/// 3. Verify the returned results #[test] fn ut_ready_from_interest() { let interest = Interest::READABLE; @@ -431,16 +392,12 @@ fn ut_ready_from_interest() { assert_eq!(ready.as_usize(), 0b1010); } -/* -* @title ready intersection function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Interest instances and a Ready instances -* 2. Call intersection -* 3. Verify the returned results -* @expect 1. Get Ready instances of an intersection -* @auto Yes -*/ +/// UT test cases for ready intersection function +/// +/// # Brief +/// 1. Create a Interest instances and a Ready instances +/// 2. Call intersection +/// 3. Verify the returned results #[test] fn ut_ready_intersection() { let interest = Interest::READABLE; @@ -449,17 +406,12 @@ fn ut_ready_intersection() { assert_eq!(res.0, 0b0101); } -/* -* @title ready satisfies function ut test -* @design Use path override -* @precon None -* @brief 1. Create a Interest instances, and a Ready instances -* 2. Call satisfies -* 3. Verify the returned results -* @expect 1. Returns true if ready satisfies Interest - 2. Returns false if ready not satisfies Interest -* @auto Yes -*/ +/// UT test cases for ready satisfies function +/// +/// # Brief +/// 1. Create a Interest instances, and a Ready instances +/// 2. Call satisfies +/// 3. Verify the returned results #[test] fn ut_ready_satisfies() { let interest = Interest::READABLE; @@ -470,16 +422,12 @@ fn ut_ready_satisfies() { assert!(!ready.satisfies(interest)); } -/* -* @title ready bitor function ut test -* @design Use path override -* @precon None -* @brief 1. Create two Ready instances -* 2. Call bitor or use | logical operators -* 3. Verify the returned results -* @expect 1. Get an or result of Ready -* @auto Yes -*/ +/// UT test cases for ready bitor function +/// +/// # Brief +/// 1. Create two Ready instances +/// 2. Call bitor or use | logical operators +/// 3. Verify the returned results #[test] fn ut_ready_bitor() { let ready1 = Ready::from_usize(0b1010); @@ -488,16 +436,12 @@ fn ut_ready_bitor() { assert_eq!(ready3.0, 0b1111); } -/* -* @title ready bitor_assign function ut test -* @design Use path override -* @precon None -* @brief 1. Create two Ready instances -* 2. Call bitor_assign or use |= logical operators -* 3. Verify the returned results -* @expect 1. Get a Ready of or equal to the result of the operation -* @auto Yes -*/ +/// UT test cases for ready bitor_assign function +/// +/// # Brief +/// 1. Create two Ready instances +/// 2. Call bitor_assign or use |= logical operators +/// 3. Verify the returned results #[test] fn ut_ready_bitor_assign() { let mut ready1 = Ready::from_usize(0b1010); @@ -506,16 +450,12 @@ fn ut_ready_bitor_assign() { assert_eq!(ready1.0, 0b1111); } -/* -* @title ready bitand function ut test -* @design Use path override -* @precon None -* @brief 1. Create two Ready instances -* 2. Call bitand or use & logical operators -* 3. Verify the returned results -* @expect 1. Get a Ready with the result of the operation -* @auto Yes -*/ +/// UT test cases for ready bitand function +/// +/// # Brief +/// 1. Create two Ready instances +/// 2. Call bitand or use & logical operators +/// 3. Verify the returned results #[test] fn ut_ready_bitand() { let ready1 = Ready::from_usize(0b1010); @@ -524,16 +464,12 @@ fn ut_ready_bitand() { assert_eq!(ready.0, 0b0000); } -/* -* @title ready bitsub function ut test -* @design Use path override -* @precon None -* @brief 1. Create two Ready instances -* 2. Call bitsub or use - logical operators -* 3. Verify the returned results -* @expect 1. Get a Ready with the values ready1 & !ready2 -* @auto Yes -*/ +/// UT test cases for ready bitsub function +/// +/// # Brief +/// 1. Create two Ready instances +/// 2. Call bitsub or use - logical operators +/// 3. Verify the returned results #[test] fn ut_ready_bitsub() { let ready1 = Ready::from_usize(0b1111); @@ -542,15 +478,11 @@ fn ut_ready_bitsub() { assert_eq!(ready.0, 0b1010); } -/* -* @title ready_event new function ut test -* @design Use path override -* @precon None -* @brief 1. Call new -* 2. Verify the returned results -* @expect 1. Get a ready_event instances -* @auto Yes -*/ +/// UT test cases for ready_event new function +/// +/// # Brief +/// 1. Call new +/// 2. Verify the returned results #[test] fn ut_ready_event_new() { let ready_event = ReadyEvent::new(1u8, Ready::from_usize(0b0101)); @@ -558,32 +490,24 @@ fn ut_ready_event_new() { assert_eq!(ready_event.ready.0, 0b0101); } -/* -* @title ready_event get_tick function ut test -* @design Use path override -* @precon None -* @brief 1. Create a ready_event -* 2. Call get_tick -* 3. Verify the returned results -* @expect 1. Get the tick of ready_event -* @auto Yes -*/ +/// UT test cases for ready_event get_tick function +/// +/// # Brief +/// 1. Create a ready_event +/// 2. Call get_tick +/// 3. Verify the returned results #[test] fn ut_ready_event_get_tick() { let ready_event = ReadyEvent::new(1u8, Ready::from_usize(0b0101)); assert_eq!(ready_event.get_tick(), 1u8); } -/* -* @title ready_event get_ready function ut test -* @design Use path override -* @precon None -* @brief 1. Create a ready_event -* 2. Call get_ready -* 3. Verify the returned results -* @expect 1. Get the ready of ready_event -* @auto Yes -*/ +/// UT test cases for ready_event get_ready function +/// +/// # Brief +/// 1. Create a ready_event +/// 2. Call get_ready +/// 3. Verify the returned results #[test] fn ut_ready_event_get_ready() { let ready_event = ReadyEvent::new(1u8, Ready::from_usize(0b0101)); diff --git a/ylong_runtime/src/net/sys/mod.rs b/ylong_runtime/src/net/sys/mod.rs index fc29e65..3c99967 100644 --- a/ylong_runtime/src/net/sys/mod.rs +++ b/ylong_runtime/src/net/sys/mod.rs @@ -11,11 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::macros::cfg_io; use std::io; use std::net::SocketAddr; use std::sync::Arc; +use crate::macros::cfg_io; + cfg_io! { mod tcp; pub use tcp::{TcpListener, TcpStream}; diff --git a/ylong_runtime/src/net/sys/tcp/listener.rs b/ylong_runtime/src/net/sys/tcp/listener.rs index 18bf8ef..76b397c 100644 --- a/ylong_runtime/src/net/sys/tcp/listener.rs +++ b/ylong_runtime/src/net/sys/tcp/listener.rs @@ -11,18 +11,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::net::{AsyncSource, TcpStream}; use std::io; use std::net::SocketAddr; + use ylong_io::Interest; -/// An asynchronous version of [`std::net::TcpListener`]. Provides async bind/accept methods. +use crate::net::{AsyncSource, TcpStream}; + +/// An asynchronous version of [`std::net::TcpListener`]. Provides async +/// bind/accept methods. /// /// # Example /// ```rust -/// use ylong_runtime::net::TcpListener; /// use std::io; /// +/// use ylong_runtime::net::TcpListener; +/// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let server = TcpListener::bind(addr).await?; @@ -37,15 +41,16 @@ pub struct TcpListener { impl TcpListener { /// A TCP socket server, asynchronously listening for connections. /// - /// After creating a `TcpListener` by binding it to a socket address, it listens - /// for incoming TCP connections asynchronously. These connections can be accepted by calling - /// [`TcpListener::accept`] + /// After creating a `TcpListener` by binding it to a socket address, it + /// listens for incoming TCP connections asynchronously. These + /// connections can be accepted by calling [`TcpListener::accept`] /// /// # Example /// ```rust - /// use ylong_runtime::net::TcpListener; /// use std::io; /// + /// use ylong_runtime::net::TcpListener; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let server = TcpListener::bind(addr).await?; @@ -59,15 +64,16 @@ impl TcpListener { /// Asynchronously accepts a new incoming connection from this listener. /// - /// When connection gets established, the corresponding [`TcpStream`] and the - /// remote peer's address will be returned. + /// When connection gets established, the corresponding [`TcpStream`] and + /// the remote peer's address will be returned. /// /// /// # Example /// ```rust - /// use ylong_runtime::net::TcpListener; /// use std::io; /// + /// use ylong_runtime::net::TcpListener; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let server = TcpListener::bind(addr).await?; @@ -84,7 +90,8 @@ impl TcpListener { Ok((stream, addr)) } - // Registers the ylong_io::TcpListener's fd to the reactor, and returns the async TcpListener + // Registers the ylong_io::TcpListener's fd to the reactor, and returns the + // async TcpListener pub(crate) fn new(listener: ylong_io::TcpListener) -> io::Result { let source = AsyncSource::new(listener, None)?; Ok(TcpListener { source }) diff --git a/ylong_runtime/src/net/sys/tcp/stream.rs b/ylong_runtime/src/net/sys/tcp/stream.rs index d94c57b..dbfaab5 100644 --- a/ylong_runtime/src/net/sys/tcp/stream.rs +++ b/ylong_runtime/src/net/sys/tcp/stream.rs @@ -11,37 +11,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::io::{AsyncRead, AsyncWrite, ReadBuf}; -use crate::net::AsyncSource; use std::fmt::{Debug, Formatter}; use std::io; use std::io::IoSlice; use std::net::{Shutdown, SocketAddr}; use std::pin::Pin; use std::task::{Context, Poll}; + use ylong_io::Interest; +use crate::io::{AsyncRead, AsyncWrite, ReadBuf}; +use crate::net::AsyncSource; + /// An asynchronous version of [`std::net::TcpStream`] /// -/// After creating a `TcpStream` by either connecting to a remote host or accepting a -/// connection on a `TcpListener`, data can be transmitted asynchronously -/// by reading and writing to it. +/// After creating a `TcpStream` by either connecting to a remote host or +/// accepting a connection on a `TcpListener`, data can be transmitted +/// asynchronously by reading and writing to it. /// /// /// # Example /// ```rust -/// use ylong_runtime::net::TcpStream; -/// use std::io::IoSlice; -/// use std::io::IoSliceMut; /// use std::io; +/// use std::io::{IoSlice, IoSliceMut}; +/// /// use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; +/// use ylong_runtime::net::TcpStream; /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let mut stream = TcpStream::connect(addr).await?; /// /// let _ = stream.write(b"hello client").await?; -/// let _ = stream.write_vectored(&[IoSlice::new(b"hello client")]).await?; +/// let _ = stream +/// .write_vectored(&[IoSlice::new(b"hello client")]) +/// .await?; /// /// let mut read_buf = [0 as u8; 1024]; /// let _ = stream.read(&mut read_buf).await?; @@ -64,9 +68,10 @@ impl TcpStream { /// /// # Example /// ```rust - /// use ylong_runtime::net::TcpStream; /// use std::io; /// + /// use ylong_runtime::net::TcpStream; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let mut stream = TcpStream::connect(addr).await?; @@ -90,7 +95,8 @@ impl TcpStream { Ok(stream) } - // Registers the ylong_io::TcpStream's fd to the reactor, and returns async TcpStream. + // Registers the ylong_io::TcpStream's fd to the reactor, and returns async + // TcpStream. pub(crate) fn new(stream: ylong_io::TcpStream) -> io::Result { let source = AsyncSource::new(stream, None)?; Ok(TcpStream { source }) diff --git a/ylong_runtime/src/net/sys/udp.rs b/ylong_runtime/src/net/sys/udp.rs index c7f9fb4..9af739b 100644 --- a/ylong_runtime/src/net/sys/udp.rs +++ b/ylong_runtime/src/net/sys/udp.rs @@ -11,24 +11,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::io::ReadBuf; -use crate::net::AsyncSource; use std::fmt::{Debug, Formatter}; use std::io; use std::mem::MaybeUninit; use std::net::SocketAddr; use std::task::{Context, Poll}; + use ylong_io::Interest; +use crate::io::ReadBuf; +use crate::net::AsyncSource; + /// Asynchronous UdpSocket. /// /// # Examples /// /// ```rust -/// use ylong_runtime::net::UdpSocket; /// use std::io; /// -/// async fn io_func() -> io::Result<()>{ +/// use ylong_runtime::net::UdpSocket; +/// +/// async fn io_func() -> io::Result<()> { /// let sender_addr = "127.0.0.1:8081".parse().unwrap(); /// let receiver_addr = "127.0.0.1:8082".parse().unwrap(); /// let mut sender = UdpSocket::bind(sender_addr).await?; @@ -84,14 +87,16 @@ impl Debug for ConnectedUdpSocket { } impl UdpSocket { - /// Creates a new UDP socket and attempts to bind it to the address provided, + /// Creates a new UDP socket and attempts to bind it to the address + /// provided, /// /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let mut sock = UdpSocket::bind(addr).await?; @@ -103,7 +108,8 @@ impl UdpSocket { } /// Internal interfaces. - /// Creates new ylong_runtime::net::UdpSocket according to the incoming ylong_io::UdpSocket. + /// Creates new ylong_runtime::net::UdpSocket according to the incoming + /// ylong_io::UdpSocket. pub(crate) fn new(socket: ylong_io::UdpSocket) -> io::Result { let source = AsyncSource::new(socket, None)?; Ok(UdpSocket { source }) @@ -116,9 +122,10 @@ impl UdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -148,9 +155,10 @@ impl UdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let mut sock = UdpSocket::bind(addr).await?; @@ -162,8 +170,10 @@ impl UdpSocket { self.source.local_addr() } - /// Sends data on the socket to the given address. On success, returns the number of bytes written. - /// This will return an error when the IP version of the local socket does not match that returned from SocketAddr. + /// Sends data on the socket to the given address. On success, returns the + /// number of bytes written. This will return an error when the IP + /// version of the local socket does not match that returned from + /// SocketAddr. /// /// # Return value /// The function returns: @@ -173,9 +183,10 @@ impl UdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -199,16 +210,17 @@ impl UdpSocket { /// The function returns: /// * `Ok(n)` n is the number of bytes sent. /// * `Err(e)` if an error is encountered. - /// When the remote cannot receive the message, an [`ErrorKind::WouldBlock`] will be returned. - /// This will return an error If the IP version of the local socket does not match - /// that returned from SocketAddr. + /// When the remote cannot receive the message, an [`ErrorKind::WouldBlock`] + /// will be returned. This will return an error If the IP version of the + /// local socket does not match that returned from SocketAddr. /// /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -224,7 +236,8 @@ impl UdpSocket { /// Attempts to send data on the socket to a given address. /// Note that on multiple calls to a poll_* method in the send direction, - /// only the Waker from the Context passed to the most recent call will be scheduled to receive a wakeup + /// only the Waker from the Context passed to the most recent call will be + /// scheduled to receive a wakeup /// /// # Return value /// The function returns: @@ -235,10 +248,11 @@ impl UdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; - /// use ylong_runtime::futures::poll_fn; /// use std::io; /// + /// use ylong_runtime::futures::poll_fn; + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -258,22 +272,25 @@ impl UdpSocket { .poll_write_io(cx, || self.source.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, + /// 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 ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -291,22 +308,26 @@ impl UdpSocket { /// Attempts to receive a single datagram message on the socket. /// - /// The function is usually paired with `readable` and 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 function is usually paired with `readable` and 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 the remote. + /// * `Ok(n, addr)` n is the number of bytes received, addr is the address + /// of the remote. /// * `Err(e)` if an error is encountered. - /// If there is no pending data, an [`ErrorKind::WouldBlock`] will be returned. + /// If there is no pending data, an [`ErrorKind::WouldBlock`] will be + /// returned. /// /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -327,9 +348,10 @@ impl UdpSocket { /// # Examples /// /// ``` - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -350,9 +372,10 @@ impl UdpSocket { /// /// # Examples /// ``` - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let remote_addr = "127.0.0.1:8080".parse().unwrap(); @@ -369,21 +392,24 @@ impl UdpSocket { /// Attempts to receive a single datagram on the socket. /// Note that on multiple calls to a poll_* method in the recv direction, - /// only the Waker from the Context passed to the most recent call will be scheduled to receive a wakeup. + /// only the Waker from the Context passed to the most recent call will be + /// scheduled to receive a wakeup. /// /// # Return value /// The function returns: /// * `Poll::Pending` if the socket is not ready to read - /// * `Poll::Ready(Ok(addr))` reads data from addr into ReadBuf if the socket is ready + /// * `Poll::Ready(Ok(addr))` reads data from addr into ReadBuf if the + /// socket is ready /// * `Poll::Ready(Err(e))` if an error is encountered. /// /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; + /// /// use ylong_runtime::futures::poll_fn; /// use ylong_runtime::io::ReadBuf; + /// use ylong_runtime::net::UdpSocket; /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); @@ -416,12 +442,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_runtime::net::UdpSocket; /// /// async fn io_func() -> io::Result<()> { @@ -444,6 +472,7 @@ impl UdpSocket { /// /// ```rust /// use std::io; + /// /// use ylong_runtime::net::UdpSocket; /// /// async fn io_func() -> io::Result<()> { @@ -460,7 +489,8 @@ impl UdpSocket { impl ConnectedUdpSocket { /// Internal interfaces. - /// Creates new ylong_runtime::net::ConnectedUdpSocket according to the incoming ylong_io::UdpSocket. + /// Creates new ylong_runtime::net::ConnectedUdpSocket according to the + /// incoming ylong_io::UdpSocket. pub(crate) fn new(socket: ylong_io::ConnectedUdpSocket) -> io::Result { let source = AsyncSource::new(socket, None)?; Ok(ConnectedUdpSocket { source }) @@ -471,9 +501,10 @@ impl ConnectedUdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let mut sock = UdpSocket::bind(addr).await?; @@ -492,14 +523,16 @@ impl ConnectedUdpSocket { self.source.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 ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let addr = "127.0.0.1:8080".parse().unwrap(); /// let peer_addr = "127.0.0.1:8081".parse().unwrap(); @@ -518,19 +551,22 @@ impl ConnectedUdpSocket { self.source.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 value - /// 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 ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -551,8 +587,9 @@ impl ConnectedUdpSocket { .await } - /// Attempts to send data on the socket to the remote address that the socket is connected to. - /// This method will fail if the socket is not connected. + /// Attempts to send data on the socket to the remote address that the + /// socket is connected to. This method will fail if the socket is not + /// connected. /// /// The function is usually paired with `writable`. /// @@ -560,14 +597,16 @@ impl ConnectedUdpSocket { /// The function returns: /// * `Ok(n)` n is the number of bytes sent. /// * `Err(e)` if an error is encountered. - /// When the remote cannot receive the message, an [`ErrorKind::WouldBlock`] will be returned. + /// When the remote cannot receive the message, an [`ErrorKind::WouldBlock`] + /// will be returned. /// /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -587,11 +626,12 @@ impl ConnectedUdpSocket { .try_io(Interest::WRITABLE, || self.source.send(buf)) } - /// Attempts to send data on the socket to the remote address to which it was previously connected. - /// The connect method will connect this socket to a remote address. - /// This method will fail if the socket is not connected. - /// Note that on multiple calls to a poll_* method in the send direction, - /// only the Waker from the Context passed to the most recent call will be scheduled to receive a wakeup. + /// Attempts to send data on the socket to the remote address to which it + /// was previously connected. The connect method will connect this + /// socket to a remote address. This method will fail if the socket is + /// not connected. Note that on multiple calls to a poll_* method in the + /// send direction, only the Waker from the Context passed to the most + /// recent call will be scheduled to receive a wakeup. /// /// # Return value /// The function returns: @@ -602,9 +642,10 @@ impl ConnectedUdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; + /// /// use ylong_runtime::futures::poll_fn; + /// use ylong_runtime::net::UdpSocket; /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); @@ -624,10 +665,11 @@ impl ConnectedUdpSocket { self.source.poll_write_io(cx, || self.source.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. + /// 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. /// @@ -639,9 +681,10 @@ impl ConnectedUdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -664,25 +707,29 @@ impl ConnectedUdpSocket { .await } - /// Attempts to receive 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. - /// This method will fail if the socket is not connected. + /// Attempts to receive 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. This method will fail if the + /// socket is not connected. /// /// # Return value /// The function returns: - /// * `Ok(n, addr)` n is the number of bytes received, addr is the address of the remote. + /// * `Ok(n, addr)` n is the number of bytes received, addr is the address + /// of the remote. /// * `Err(e)` if an error is encountered. - /// If there is no pending data, an [`ErrorKind::WouldBlock`] will be returned. + /// If there is no pending data, an [`ErrorKind::WouldBlock`] will be + /// returned. /// /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; /// + /// use ylong_runtime::net::UdpSocket; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -704,11 +751,13 @@ impl ConnectedUdpSocket { .try_io(Interest::READABLE, || self.source.recv(buf)) } - /// Attempts to receive a single datagram message on the socket from the remote address to which it is connected. - /// The connect method will connect this socket to a remote address. - /// This method resolves to an error if the socket is not connected. - /// Note that on multiple calls to a poll_* method in the recv direction, - /// only the Waker from the Context passed to the most recent call will be scheduled to receive a wakeup. + /// Attempts to receive a single datagram message on the socket from the + /// remote address to which it is connected. The connect method will + /// connect this socket to a remote address. This method resolves to an + /// error if the socket is not connected. Note that on multiple calls to + /// a poll_* method in the recv direction, only the Waker from the + /// Context passed to the most recent call will be scheduled to receive a + /// wakeup. /// /// # Return value /// The function returns: @@ -720,10 +769,11 @@ impl ConnectedUdpSocket { /// # Examples /// /// ```rust - /// use ylong_runtime::net::UdpSocket; /// use std::io; + /// /// use ylong_runtime::futures::poll_fn; /// use ylong_runtime::io::ReadBuf; + /// use ylong_runtime::net::UdpSocket; /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); @@ -765,9 +815,10 @@ impl ConnectedUdpSocket { /// # Examples /// /// ``` - /// use ylong_runtime::net::{UdpSocket, ConnectedUdpSocket}; /// use std::io; /// + /// use ylong_runtime::net::{ConnectedUdpSocket, UdpSocket}; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -796,9 +847,10 @@ impl ConnectedUdpSocket { /// # Examples /// /// ``` - /// use ylong_runtime::net::{UdpSocket, ConnectedUdpSocket}; /// use std::io; /// + /// use ylong_runtime::net::{ConnectedUdpSocket, UdpSocket}; + /// /// async fn io_func() -> io::Result<()> { /// let local_addr = "127.0.0.1:8080".parse().unwrap(); /// let sock = UdpSocket::bind(local_addr).await?; @@ -828,16 +880,13 @@ mod tests { use crate::net::UdpSocket; use crate::{block_on, spawn}; - /// UT test for `poll_send()` and `poll_recv()`. - /// - /// # Title - /// test_send_recv_poll + /// UT test cases for `poll_send()` and `poll_recv()`. /// /// # Brief - /// 1.Create UdpSocket and connect to the remote address. - /// 2.Sender calls poll_fn() to send message first. - /// 3.Receiver calls poll_fn() to receive message. - /// 4.Check if the test results are correct. + /// 1. Create UdpSocket and connect to the remote address. + /// 2. Sender calls poll_fn() to send message first. + /// 3. Receiver calls poll_fn() to receive message. + /// 4. Check if the test results are correct. #[test] fn test_send_recv_poll() { let sender_addr = "127.0.0.1:8083".parse().unwrap(); @@ -890,16 +939,14 @@ mod tests { block_on(handle).expect("block_on failed"); } - /// UT test for `poll_send_to()` and `poll_recv_from()`. - /// - /// # Title - /// test_send_to_recv_from_poll - /// + /// UT test cases for `poll_send_to()` and `poll_recv_from()`. + /// # Brief - /// 1.Create UdpSocket. - /// 2.Sender calls poll_fn() to send message to the specified address. - /// 3.Receiver calls poll_fn() to receive message and return the address the message from. - /// 4.Check if the test results are correct. + /// 1. Create UdpSocket. + /// 2. Sender calls poll_fn() to send message to the specified address. + /// 3. Receiver calls poll_fn() to receive message and return the address + /// the message from. + /// 4. Check if the test results are correct. #[test] fn test_send_to_recv_from_poll() { let sender_addr = "127.0.0.1:8087".parse().unwrap(); @@ -939,16 +986,13 @@ mod tests { block_on(handle).expect("block_on failed"); } - /// UT test for `broadcast()` and `set_broadcast()`. - /// - /// # Title - /// ut_set_get_broadcast + /// UT test cases for `broadcast()` and `set_broadcast()`. /// /// # Brief - /// 1.Create UdpSocket. - /// 2.Sender calls set_broadcast() to set broadcast. - /// 3.Sender calls broadcast() to get broadcast. - /// 4.Check if the test results are correct. + /// 1. Create UdpSocket. + /// 2. Sender calls set_broadcast() to set broadcast. + /// 3. Sender calls broadcast() to get broadcast. + /// 4. Check if the test results are correct. #[test] fn ut_set_get_broadcast() { let local_addr = "127.0.0.1:8091".parse().unwrap(); @@ -969,15 +1013,12 @@ mod tests { block_on(handle).expect("block_on failed"); } - /// UT test for `local_addr()`. - /// - /// # Title - /// ut_get_local_addr + /// UT test cases for `local_addr()`. /// /// # Brief - /// 1.Create UdpSocket. - /// 2.Sender calls local_addr() to get local address. - /// 3.Check if the test results are correct. + /// 1. Create UdpSocket. + /// 2. Sender calls local_addr() to get local address. + /// 3. Check if the test results are correct. #[test] fn ut_get_local_addr() { let local_addr = "127.0.0.1:8092".parse().unwrap(); @@ -1002,15 +1043,13 @@ mod tests { block_on(handle).expect("block_on failed"); } - /// UT test for `peer_addr()`. - /// - /// # Title - /// ut_get_peer_addr + /// UT test cases for `peer_addr()`. /// /// # Brief - /// 1.Create UdpSocket. - /// 2.Sender calls peer_addr() to get the socket address of the remote peer. - /// 3.Check if the test results are correct. + /// 1. Create UdpSocket. + /// 2. Sender calls peer_addr() to get the socket address of the remote + /// peer. + /// 3. Check if the test results are correct. #[test] fn ut_get_peer_addr() { let local_addr = "127.0.0.1:8094".parse().unwrap(); diff --git a/ylong_runtime/src/schedule_io.rs b/ylong_runtime/src/schedule_io.rs index 4ef4d9d..ff1eeb6 100644 --- a/ylong_runtime/src/schedule_io.rs +++ b/ylong_runtime/src/schedule_io.rs @@ -11,10 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::futures::poll_fn; -use crate::net::{LinkedList, Node, Ready, ReadyEvent}; -use crate::util::bit::{Bit, Mask}; -use crate::util::slab::Entry; use std::cell::UnsafeCell; use std::future::Future; use std::io; @@ -25,8 +21,14 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::{AcqRel, Acquire, Release, SeqCst}; use std::sync::Mutex; use std::task::{Context, Poll, Waker}; + use ylong_io::Interest; +use crate::futures::poll_fn; +use crate::net::{LinkedList, Node, Ready, ReadyEvent}; +use crate::util::bit::{Bit, Mask}; +use crate::util::slab::Entry; + const GENERATION: Mask = Mask::new(7, 24); pub(crate) const DRIVER_TICK: Mask = Mask::new(8, 16); pub(crate) const READINESS: Mask = Mask::new(16, 0); @@ -381,21 +383,18 @@ impl Drop for Readiness<'_> { #[cfg(test)] mod schedule_io_test { - use crate::net::{Ready, ReadyEvent}; - use crate::schedule_io::{ScheduleIO, Tick}; - use crate::util::slab::Entry; use std::io; use std::sync::atomic::Ordering::{Acquire, Release}; - /* - * @title schedule_io default function ut test - * @design Use path override - * @precon None - * @brief 1. Call default - * 2. Verify the returned results - * @expect 1. Get a ScheduleIO Instances - * @auto Yes - */ + use crate::net::{Ready, ReadyEvent}; + use crate::schedule_io::{ScheduleIO, Tick}; + use crate::util::slab::Entry; + + /// UT test cases for schedule_io defalut + /// + /// # Brief + /// 1. Call default + /// 2. Verify the returned results #[test] fn ut_schedule_io_default() { let mut schedule_io = ScheduleIO::default(); @@ -405,16 +404,12 @@ mod schedule_io_test { assert!(!is_shutdown); } - /* - * @title schedule_io reset function ut test - * @design Use path override - * @precon None - * @brief 1. Create a ScheduleIO - * 2. Call reset - * 3. Verify the returned results - * @expect 1. Generation part of the ScheduleIO status bits +1 - * @auto Yes - */ + /// UT test cases for schedule_io reset + /// + /// # Brief + /// 1. Create a ScheduleIO + /// 2. Call reset + /// 3. Verify the returned results #[test] fn ut_schedule_io_reset() { let schedule_io = ScheduleIO::default(); @@ -425,16 +420,12 @@ mod schedule_io_test { assert_eq!(after_status, 0x1000000); } - /* - * @title schedule_io generation function ut test - * @design Use path override - * @precon None - * @brief 1. Create a ScheduleIO - * 2. Call generation - * 3. Verify the returned results - * @expect 1. Get the generation of ScheduleIO - * @auto Yes - */ + /// UT test cases for schedule_io generation + /// + /// # Brief + /// 1. Create a ScheduleIO + /// 2. Call generation + /// 3. Verify the returned results #[test] fn ut_schedule_io_generation() { let schedule_io = ScheduleIO::default(); @@ -442,16 +433,12 @@ mod schedule_io_test { assert_eq!(schedule_io.generation(), 0x7f); } - /* - * @title schedule_io shutdown function ut test - * @design Use path override - * @precon None - * @brief 1. Create a ScheduleIO - * 2. Call shutdown - * 3. Verify the returned results - * @expect 1. ScheduleIO shutdown. The is_shutdown part of the waiters is set to true - * @auto Yes - */ + /// UT test cases for schedule_io shutdown + /// + /// # Brief + /// 1. Create a ScheduleIO + /// 2. Call shutdown + /// 3. Verify the returned results #[test] fn ut_schedule_io_shutdown() { let mut schedule_io = ScheduleIO::default(); @@ -459,16 +446,12 @@ mod schedule_io_test { assert!(schedule_io.waiters.get_mut().unwrap().is_shutdown); } - /* - * @title schedule_io clear_readiness function ut test - * @design Use path override - * @precon None - * @brief 1. Create a ScheduleIO - * 2. Call clear_readiness - * 3. Verify the returned results - * @expect 1. ScheduleIO readiness status clear - * @auto Yes - */ + /// UT test cases for schedule_io clear_readiness + /// + /// # Brief + /// 1. Create a ScheduleIO + /// 2. Call clear_readiness + /// 3. Verify the returned results #[test] fn ut_schedule_io_clear_readiness() { let schedule_io = ScheduleIO::default(); @@ -478,18 +461,12 @@ mod schedule_io_test { assert_eq!(status, 0x0000000e); } - /* - * @title schedule_io set_readiness function ut test - * @design Use path override - * @precon None - * @brief 1. Create a ScheduleIO - * 2. Call set_readiness - * 3. Verify the returned results - * @expect 1. Constructed scenario, the generation part of the token is invalid, return failed - * 2. Construct scene, tick for Tick::Clear property, return failure - * 3. In a normal scenario, the ScheduleIO readiness section is modified successfully - * @auto Yes - */ + /// UT test cases for schedule_io set_readiness + /// + /// # Brief + /// 1. Create a ScheduleIO + /// 2. Call set_readiness + /// 3. Verify the returned results #[test] fn ut_schedule_io_set_readiness() { ut_schedule_io_set_readiness_01(); diff --git a/ylong_runtime/src/select.rs b/ylong_runtime/src/select.rs index 3b1c455..b02d523 100644 --- a/ylong_runtime/src/select.rs +++ b/ylong_runtime/src/select.rs @@ -26,9 +26,10 @@ /// ``` /// /// The `` for all branches will run concurrently. Once the -/// first expression is completed, the corresponding `` will be executed. -/// Each branch is optional `if `. if the `` returns -/// false, the corresponding `` will not be executed. +/// first expression is completed, the corresponding `` will be +/// executed. Each branch is optional `if `. if the +/// `` returns false, the corresponding `` will not be +/// executed. /// /// When none of the branches can match, Executes the else expression. /// @@ -58,7 +59,7 @@ /// } /// ``` /// -/// # Examples +/// # Examples /// /// Uses if to filter asynchronous tasks /// ``` @@ -69,7 +70,7 @@ /// 2 /// } /// async fn do_async3() -> bool { -/// false +/// false /// } /// async fn select_test() { /// let mut count = 0; @@ -94,7 +95,7 @@ /// assert_eq!(count, 2); /// } /// ``` -/// # Examples +/// # Examples /// /// Repeated uses select! until all task return. /// ``` @@ -125,9 +126,9 @@ /// /// assert_eq!(res.0, "first"); /// assert_eq!(res.1, "second"); -/// } +/// } /// ``` -/// # Examples +/// # Examples /// /// Uses 'biased' to execute four task in the specified sequence. /// It will poll branches with order, the first branch will be polled first. @@ -159,9 +160,9 @@ /// } /// } /// } -/// +/// /// assert_eq!(count, 4); -/// } +/// } /// ``` #[macro_export] macro_rules! select { @@ -338,10 +339,7 @@ macro_rules! select { #[cfg(test)] mod select_test { - /// select! basic usage ut test case. - /// - /// # Title - /// new_select_basic + /// UT test cases for select! basic usage case /// /// # Brief /// 1. Uses select! to run three async task. @@ -384,15 +382,13 @@ mod select_test { crate::block_on(handle).expect("select! fail"); } - /// select! oneshot::channel usage ut test case. - /// - /// # Title - /// new_select_channel + /// UT test cases for select! oneshot::channel usage /// /// # Brief /// 1. Creates two oneshot::channel and send message. /// 2. Repeated uses select! until both channel return. - /// 3. Checks whether the returned information of the two channels is correct. + /// 3. Checks whether the returned information of the two channels is + /// correct. #[test] #[cfg(feature = "sync")] fn new_select_channel() { @@ -426,10 +422,7 @@ mod select_test { crate::block_on(handle).expect("select! fail"); } - /// select! 'biased' usage ut test case. - /// - /// # Title - /// new_select_biased + /// UT test cases for select! 'biased' usage /// /// # Brief /// 1. Uses 'biased' to execute four task in the specified sequence. @@ -469,10 +462,7 @@ mod select_test { crate::block_on(handle).expect("select! fail"); } - /// select! match usage ut test case. - /// - /// # Title - /// new_select_match + /// UT test cases for select! match usage /// /// # Brief /// 1. Uses select! to run three async task. @@ -515,14 +505,12 @@ mod select_test { crate::block_on(handle).expect("select! fail"); } - /// select! precondition usage ut test case. - /// - /// # Title - /// new_select_precondition + /// UT test cases for select! precondition usage /// /// # Brief /// 1. Creates a struct and implement a call to the `&mut self` async fn. - /// 2. Uses select! to run the async fn, and sets the precondition to the struct member variable. + /// 2. Uses select! to run the async fn, and sets the precondition to the + /// struct member variable. /// 3. The select! will be successfully executed. #[test] fn new_select_precondition() { @@ -546,10 +534,7 @@ mod select_test { crate::block_on(handle).expect("select! fail"); } - /// select! panic! usage ut test case. - /// - /// # Title - /// new_select_panic + /// UT test cases for select! panic! usage /// /// # Brief /// 1. Uses select! to run two async task with `if false`. diff --git a/ylong_runtime/src/spawn.rs b/ylong_runtime/src/spawn.rs index 5839703..6550d5e 100644 --- a/ylong_runtime/src/spawn.rs +++ b/ylong_runtime/src/spawn.rs @@ -11,10 +11,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::future::Future; + use crate::executor::{global_default_async, global_default_blocking}; use crate::task::join_handle::JoinHandle; use crate::task::TaskBuilder; -use std::future::Future; /// Spawns a task on the blocking pool. pub(crate) fn spawn_blocking(builder: &TaskBuilder, task: T) -> JoinHandle @@ -27,7 +28,8 @@ where rt.spawn_blocking(builder, task) } -/// Gets global default executor, spawns async tasks by the task builder, and returns. +/// Gets global default executor, spawns async tasks by the task builder, and +/// returns. pub(crate) fn spawn_async(builder: &TaskBuilder, task: T) -> JoinHandle where T: Future, diff --git a/ylong_runtime/src/sync/mpsc/array.rs b/ylong_runtime/src/sync/mpsc/array.rs index dcb9474..8e57fb9 100644 --- a/ylong_runtime/src/sync/mpsc/array.rs +++ b/ylong_runtime/src/sync/mpsc/array.rs @@ -11,12 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::futures::poll_fn; -use crate::sync::atomic_waker::AtomicWaker; -use crate::sync::error::SendError::{Closed, Full}; -use crate::sync::error::{RecvError, SendError}; -use crate::sync::mpsc::Container; -use crate::sync::wake_list::WakerList; use std::cell::RefCell; use std::future::Future; use std::mem::MaybeUninit; @@ -26,6 +20,13 @@ use std::sync::atomic::Ordering::{AcqRel, Acquire, Release}; use std::task::Poll::{Pending, Ready}; use std::task::{Context, Poll}; +use crate::futures::poll_fn; +use crate::sync::atomic_waker::AtomicWaker; +use crate::sync::error::SendError::{Closed, Full}; +use crate::sync::error::{RecvError, SendError}; +use crate::sync::mpsc::Container; +use crate::sync::wake_list::WakerList; + /// The offset of the index. const INDEX_SHIFT: usize = 1; /// The flag marks that Array is closed. @@ -84,8 +85,8 @@ impl Array { let node = self.data.get(index).unwrap(); let node_index = node.index.load(Acquire); - // Compare the index of the node with the tail to avoid senders in different cycles - // writing data to the same point at the same time. + // Compare the index of the node with the tail to avoid senders in different + // cycles writing data to the same point at the same time. if (tail >> INDEX_SHIFT) == node_index { match self.tail.compare_exchange_weak( tail, diff --git a/ylong_runtime/src/sync/mpsc/bounded.rs b/ylong_runtime/src/sync/mpsc/bounded.rs index 1e4d17b..ec54ad3 100644 --- a/ylong_runtime/src/sync/mpsc/bounded.rs +++ b/ylong_runtime/src/sync/mpsc/bounded.rs @@ -84,7 +84,8 @@ pub struct BoundedReceiver { channel: Rx>, } -/// Creates a new mpsc channel, and returns the `Sender` and `Receiver` handle pair. +/// Creates a new mpsc channel, and returns the `Sender` and `Receiver` handle +/// pair. /// /// The channel is bounded with the passed in capacity. /// @@ -121,8 +122,8 @@ impl BoundedSender { /// Attempts to send a value to the associated [`BoundedReceiver`]. /// - /// If the receiver has been closed or the channel is full, this method will return an error - /// containing sent value. + /// If the receiver has been closed or the channel is full, this method will + /// return an error containing sent value. /// /// # Return value /// * `Ok(T)` if receiving a value successfully. @@ -151,8 +152,8 @@ impl BoundedSender { /// Sends a value to the associated receiver /// - /// If the receiver has been closed, this method will return an error containing the sent - /// value. + /// If the receiver has been closed, this method will return an error + /// containing the sent value. /// /// # Return value /// * `Ok()` if sending a value successfully. @@ -178,7 +179,8 @@ impl BoundedSender { self.channel.send(value).await } - /// Attempts to send a value to the associated receiver in a limited amount of time. + /// Attempts to send a value to the associated receiver in a limited amount + /// of time. /// /// If the receiver has been closed or the time limit has been passed, this /// method will return an error containing the sent value. @@ -192,6 +194,7 @@ impl BoundedSender { /// /// ``` /// use std::time::Duration; + /// /// use ylong_runtime::sync::mpsc::bounded::bounded_channel; /// async fn io_func() { /// let (tx, mut rx) = bounded_channel(1); @@ -221,8 +224,8 @@ impl BoundedSender { } /// Checks whether the channel is closed. If so, the sender could not - /// send values anymore. It returns true after the [`BoundedReceiver`] is dropped - /// or the [`close`] method gets called. + /// send values anymore. It returns true after the [`BoundedReceiver`] is + /// dropped or the [`close`] method gets called. /// /// [`close`]: BoundedReceiver::close /// @@ -372,7 +375,8 @@ impl BoundedReceiver { /// Receives a value from the associated [`BoundedSender`]. /// - /// The `receiver` can still receive all sent messages in the channel after the channel is closed. + /// The `receiver` can still receive all sent messages in the channel after + /// the channel is closed. /// /// # Return value /// * `Ok(T)` if receiving a value successfully. @@ -395,9 +399,11 @@ impl BoundedReceiver { self.channel.recv().await } - /// Attempts to receive a value from the associated [`BoundedSender`] in a limited amount of time. + /// Attempts to receive a value from the associated [`BoundedSender`] in a + /// limited amount of time. /// - /// The `receiver` can still receive all sent messages in the channel after the channel is closed. + /// The `receiver` can still receive all sent messages in the channel after + /// the channel is closed. /// /// # Return value /// * `Ok(T)` if receiving a value successfully. @@ -408,6 +414,7 @@ impl BoundedReceiver { /// /// ``` /// use std::time::Duration; + /// /// use ylong_runtime::sync::mpsc::bounded::bounded_channel; /// async fn io_func() { /// let (tx, mut rx) = bounded_channel(1); @@ -428,8 +435,9 @@ impl BoundedReceiver { /// Closes the channel, prevents the `Sender` from sending more values. /// - /// The `Sender` will fail to call [`send`] or [`try_send`] after the `Receiver` called - /// `close`. It will do nothing if the channel is already closed. + /// The `Sender` will fail to call [`send`] or [`try_send`] after the + /// `Receiver` called `close`. It will do nothing if the channel is + /// already closed. /// /// [`send`]: BoundedSender::send /// [`try_send`]: BoundedSender::try_send diff --git a/ylong_runtime/src/sync/mpsc/channel.rs b/ylong_runtime/src/sync/mpsc/channel.rs index 340f4a6..b978f04 100644 --- a/ylong_runtime/src/sync/mpsc/channel.rs +++ b/ylong_runtime/src/sync/mpsc/channel.rs @@ -11,12 +11,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::sync::mpsc::Container; use std::ops::Deref; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::{AcqRel, Relaxed}; use std::sync::Arc; +use crate::sync::mpsc::Container; + pub(crate) struct Channel { chan: C, tx_cnt: AtomicUsize, diff --git a/ylong_runtime/src/sync/mpsc/queue.rs b/ylong_runtime/src/sync/mpsc/queue.rs index 29f901d..e0550e3 100644 --- a/ylong_runtime/src/sync/mpsc/queue.rs +++ b/ylong_runtime/src/sync/mpsc/queue.rs @@ -11,10 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::futures::poll_fn; -use crate::sync::atomic_waker::AtomicWaker; -use crate::sync::error::{RecvError, SendError}; -use crate::sync::mpsc::Container; use std::cell::RefCell; use std::mem::MaybeUninit; use std::ptr; @@ -24,6 +20,11 @@ use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize}; use std::task::Poll::{Pending, Ready}; use std::task::{Context, Poll}; +use crate::futures::poll_fn; +use crate::sync::atomic_waker::AtomicWaker; +use crate::sync::error::{RecvError, SendError}; +use crate::sync::mpsc::Container; + /// The capacity of a block. const CAPACITY: usize = 32; /// The offset of the index. @@ -65,9 +66,10 @@ impl Block { fn insert(&self, ptr: *mut Block) { let mut curr = self; - // The number of cycles is limited. Recycling blocks is to avoid frequent creation and - // destruction, but trying too many times may consume more resources. Every block should - // stop trying after failing to insert for a certain times. + // The number of cycles is limited. Recycling blocks is to avoid frequent + // creation and destruction, but trying too many times may consume more + // resources. Every block should stop trying after failing to insert for + // a certain times. for _ in 0..5 { match curr.try_insert(ptr) { Ok(_) => return, diff --git a/ylong_runtime/src/sync/mpsc/unbounded.rs b/ylong_runtime/src/sync/mpsc/unbounded.rs index aa23ca6..0de4bca 100644 --- a/ylong_runtime/src/sync/mpsc/unbounded.rs +++ b/ylong_runtime/src/sync/mpsc/unbounded.rs @@ -22,8 +22,8 @@ cfg_time!( use std::time::Duration; ); /// The sender of unbounded channel. -/// A [`UnboundedSender`] and [`UnboundedReceiver`] handle pair are created by the -/// [`unbounded_channel`] function. +/// A [`UnboundedSender`] and [`UnboundedReceiver`] handle pair are created by +/// the [`unbounded_channel`] function. /// /// # Examples /// @@ -53,8 +53,8 @@ impl Clone for UnboundedSender { } /// The receiver of unbounded channel. -/// A [`UnboundedSender`] and [`UnboundedReceiver`] handle pair are created by the -/// [`unbounded_channel`] function. +/// A [`UnboundedSender`] and [`UnboundedReceiver`] handle pair are created by +/// the [`unbounded_channel`] function. /// /// # Examples /// @@ -74,7 +74,8 @@ pub struct UnboundedReceiver { channel: Rx>, } -/// Creates a new mpsc channel and returns a `Sender` and `Receiver` handle pair. +/// Creates a new mpsc channel and returns a `Sender` and `Receiver` handle +/// pair. /// /// # Examples /// @@ -101,7 +102,8 @@ impl UnboundedSender { /// Sends values to the associated receiver. /// - /// An error containing the sent value would be returned if the receiver is closed or dropped. + /// An error containing the sent value would be returned if the receiver is + /// closed or dropped. /// /// # Examples /// @@ -116,8 +118,8 @@ impl UnboundedSender { } /// Checks whether the channel is closed. If so, the sender could not - /// send values anymore. It returns true if the [`UnboundedReceiver`] is dropped - /// or calls the [`close`] method. + /// send values anymore. It returns true if the [`UnboundedReceiver`] is + /// dropped or calls the [`close`] method. /// /// [`close`]: UnboundedReceiver::close /// @@ -254,7 +256,8 @@ impl UnboundedReceiver { /// Receives a value from the associated [`UnboundedSender`]. /// - /// The `receiver` can still receive all sent messages in the channel after the channel is closed. + /// The `receiver` can still receive all sent messages in the channel after + /// the channel is closed. /// /// # Return value /// * `Ok(T)` if receiving a value successfully. @@ -276,11 +279,11 @@ impl UnboundedReceiver { self.channel.recv().await } - /// Attempts to receive a value from the associated [`UnboundedSender`] in a limited - /// amount of time. + /// Attempts to receive a value from the associated [`UnboundedSender`] in a + /// limited amount of time. /// - /// The `receiver` can still receive all sent messages in the channel after the channel - /// is closed. + /// The `receiver` can still receive all sent messages in the channel after + /// the channel is closed. /// /// # Return value /// * `Ok(T)` if receiving a value successfully. @@ -291,6 +294,7 @@ impl UnboundedReceiver { /// /// ``` /// use std::time::Duration; + /// /// use ylong_runtime::sync::mpsc::unbounded::unbounded_channel; /// async fn io_func() { /// let (tx, mut rx) = unbounded_channel(); diff --git a/ylong_runtime/src/sync/mutex.rs b/ylong_runtime/src/sync/mutex.rs index d933ce0..5cef039 100644 --- a/ylong_runtime/src/sync/mutex.rs +++ b/ylong_runtime/src/sync/mutex.rs @@ -13,22 +13,25 @@ //! Mutual exclusion locks -use crate::sync::semaphore_inner::SemaphoreInner; use std::cell::UnsafeCell; use std::error::Error; use std::fmt; use std::fmt::{Display, Formatter}; use std::ops::{Deref, DerefMut}; +use crate::sync::semaphore_inner::SemaphoreInner; + /// An async version of [`std::sync::Mutex`] /// -/// Often it's considered as normal to use [`std::sync::Mutex`] on an asynchronous environment. -/// The primal purpose of this async mutex is to protect shared reference of io, which contains -/// a lot await point during reading and writing. If you only wants to protect a data across -/// different threads, [`std::sync::Mutex`] will probably gain you better performance. +/// Often it's considered as normal to use [`std::sync::Mutex`] on an +/// asynchronous environment. The primal purpose of this async mutex is to +/// protect shared reference of io, which contains a lot await point during +/// reading and writing. If you only wants to protect a data across +/// different threads, [`std::sync::Mutex`] will probably gain you better +/// performance. /// -/// When using across different futures, users need to wrap the mutex inside an Arc, -/// just like the use of [`std::sync::Mutex`]. +/// When using across different futures, users need to wrap the mutex inside an +/// Arc, just like the use of [`std::sync::Mutex`]. pub struct Mutex { /// Semaphore to provide mutual exclusion sem: SemaphoreInner, @@ -60,7 +63,6 @@ impl Mutex { /// use ylong_runtime::sync::mutex::Mutex; /// /// let _a = Mutex::new(2); - /// /// ``` pub fn new(t: T) -> Mutex { Mutex { @@ -73,14 +75,16 @@ impl Mutex { impl Mutex { /// Locks the mutex. /// - /// If the mutex is already held by others, asynchronously waits for it to release. + /// If the mutex is already held by others, asynchronously waits for it to + /// release. /// /// # Examples /// /// ``` - /// use ylong_runtime::sync::mutex::Mutex; /// use std::sync::Arc; /// + /// use ylong_runtime::sync::mutex::Mutex; + /// /// let _res = ylong_runtime::block_on(async { /// let lock = Arc::new(Mutex::new(2)); /// let mut n = lock.lock().await; @@ -97,19 +101,20 @@ impl Mutex { /// Attempts to get the mutex. /// - /// If the lock is already held by others, LockError will be returned. Otherwise, - /// the mutex guard will be returned. + /// If the lock is already held by others, LockError will be returned. + /// Otherwise, the mutex guard will be returned. /// /// # Examples /// /// ``` - /// use ylong_runtime::sync::mutex::Mutex; /// use std::sync::Arc; /// + /// use ylong_runtime::sync::mutex::Mutex; + /// /// let _res = ylong_runtime::block_on(async { /// let mutex = Arc::new(Mutex::new(0)); /// match mutex.try_lock() { - /// Ok(lock) => println!("{}",lock), + /// Ok(lock) => println!("{}", lock), /// Err(_) => {} /// }; /// }); @@ -124,8 +129,9 @@ impl Mutex { /// Gets the mutable reference of the data protected by the lock without /// actually holding the lock. /// - /// This method takes the mutable reference of the mutex, so there is no need to actually - /// lock the mutex -- the mutable borrow statically guarantees no locks exist. + /// This method takes the mutable reference of the mutex, so there is no + /// need to actually lock the mutex -- the mutable borrow statically + /// guarantees no locks exist. pub fn get_mut(&mut self) -> &mut T { unsafe { &mut *self.data.get() } } @@ -177,40 +183,33 @@ impl DerefMut for MutexGuard<'_, T> { #[cfg(test)] mod tests { - use super::*; - use crate::{block_on, spawn}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; use std::time::Duration; - /* - * @title UT test case for Mutex::new() interface - * @design The design of this use case is carried out by the conditional coverage test method - * @precon None - * @brief Test case execution steps: - * 1. Creating a Concurrent Mutual Exclusion Lock - * 2. Verify the state of the lock object and the size of the internal value of the lock object - * @expect Mutex structure body state is UNLOCKED, data is preset value 10 - * @auto Yes - */ + use super::*; + use crate::{block_on, spawn}; + + /// UT test cases for Mutex::new() interface + /// + /// # Brief + /// 1. Creating a Concurrent Mutual Exclusion Lock + /// 2. Verify the state of the lock object and the size of the internal + /// value of the lock object #[test] fn ut_mutex_new_01() { let lock = Mutex::new(10); assert_eq!(lock.data.into_inner(), 10); } - /* - * @title UT test case for Mutex::lock() interface - * @design The design of this use case is carried out by the conditional coverage test method - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Modification of data in the concurrent mutex lock - * 3. Check the value in the changed concurrent mutex lock and check the status bit of the lock - * @expect Mutex structure body state is LOCKED, data value is 11 - * @auto Yes - */ + /// UT test cases for Mutex::lock() interface + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Modification of data in the concurrent mutex lock + /// 3. Check the value in the changed concurrent mutex lock and check the + /// status bit of the lock #[test] fn ut_mutex_lock_01() { let mutex = Mutex::new(10); @@ -221,18 +220,13 @@ mod tests { }); } - /* - * @title UT test case for Mutex::try_lock() interface - * @design The design of this use case is carried out by the conditional coverage test method - * @precon None - * @brief Test case execution steps: - * 1. Creating a Concurrent Mutual Exclusion Lock - * 2. Call try_lock() to try to get the lock - * 3. Operation on in-lock values - * 4. Calibrate in-lock values - * @expect data value is 110 - * @auto Yes - */ + /// UT test cases for Mutex::try_lock() interface + /// + /// # Brief + /// 1. Creating a Concurrent Mutual Exclusion Lock + /// 2. Call try_lock() to try to get the lock + /// 3. Operation on in-lock values + /// 4. Calibrate in-lock values #[test] fn ut_mutex_try_lock_01() { let mutex = Mutex::new(10); @@ -241,18 +235,14 @@ mod tests { assert_eq!(*lock, 110); } - /* - * @title UT test case for Mutex::try_lock() interface - * @design The design of this use case is carried out by the conditional coverage test method - * @precon None - * @brief Test case execution steps: - * 1. Creating a Concurrent Mutual Exclusion Lock - * 2. First build a concurrent process to hold the lock and sleep after obtaining the lock to hold the lock for a long time - * 3. Call try_lock() to try to get a lock - * 4. Check try_lock return value is None - * @expect lock2 is None - * @auto Yes - */ + /// UT test cases for Mutex::try_lock() interface + /// + /// # Brief + /// 1. Creating a Concurrent Mutual Exclusion Lock + /// 2. First build a concurrent process to hold the lock and sleep after + /// obtaining the lock to hold the lock for a long time + /// 3. Call try_lock() to try to get a lock + /// 4. Check try_lock return value is None #[test] fn ut_mutex_try_lock_02() { let mutex = Arc::new(Mutex::new(10)); @@ -277,18 +267,14 @@ mod tests { flag.store(false, Ordering::SeqCst); } - /* - * @title UT test case for Mutex::unlock() interface - * @design The design of this use case is carried out by the conditional coverage test method - * @precon None - * @brief Test case execution steps: - * 1. Creating a Concurrent Mutual Exclusion Lock - * 2. Perform locking operation - * 3. Call the drop() method to release the lock - * 4. Verify the status of the concurrent mutex lock before, after and after unlocking - * @expect Mutex structure unlocked state is UNLOCKED, when locking state is LOCKED, after unlocking state is UNLOCKED - * @auto Yes - */ + /// UT test cases for Mutex::unlock() interface + /// + /// # Brief + /// 1. Creating a Concurrent Mutual Exclusion Lock + /// 2. Perform locking operation + /// 3. Call the drop() method to release the lock + /// 4. Verify the status of the concurrent mutex lock before, after and + /// after unlocking #[test] fn ut_mutex_unlock_01() { let mutex = Mutex::new(10); diff --git a/ylong_runtime/src/sync/oneshot.rs b/ylong_runtime/src/sync/oneshot.rs index cdb4f0c..62ad195 100644 --- a/ylong_runtime/src/sync/oneshot.rs +++ b/ylong_runtime/src/sync/oneshot.rs @@ -11,12 +11,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! One-shot channel is used to send a single message from a single sender to a single receiver. -//! The [`channel`] function returns a [`Sender`] and [`Receiver`] handle pair that controls channel. +//! One-shot channel is used to send a single message from a single sender to a +//! single receiver. The [`channel`] function returns a [`Sender`] and +//! [`Receiver`] handle pair that controls channel. //! //! The `Sender` handle is used by the producer to send a message. -//! The `Receiver` handle is used by the consumer to receive the message. It has implemented the -//! `Future` trait +//! The `Receiver` handle is used by the consumer to receive the message. It has +//! implemented the `Future` trait //! //! The `send` method is not async. It can be called from non-async context. //! @@ -34,12 +35,10 @@ //! //! match rx.await { //! Ok(v) => println!("received : {:?}", v), -//! Err(_) => println!("Sender dropped") +//! Err(_) => println!("Sender dropped"), //! } //! } //! ``` -use super::atomic_waker::AtomicWaker; -use super::error::RecvError; use std::cell::RefCell; use std::fmt::{Debug, Formatter}; use std::future::Future; @@ -50,6 +49,9 @@ use std::sync::Arc; use std::task::Poll::{Pending, Ready}; use std::task::{Context, Poll}; +use super::atomic_waker::AtomicWaker; +use super::error::RecvError; + /// Initial state. const INIT: usize = 0b00; /// Sender has sent the value. @@ -75,7 +77,7 @@ const CLOSED: usize = 0b10; /// /// match rx.await { /// Ok(v) => println!("received : {:?}", v), -/// Err(_) => println!("Sender dropped") +/// Err(_) => println!("Sender dropped"), /// } /// } /// ``` @@ -89,7 +91,8 @@ pub fn channel() -> (Sender, Receiver) { } /// Sends a single value to the associated [`Receiver`]. -/// A [`Sender`] and [`Receiver`] handle pair is created by the [`channel`] function. +/// A [`Sender`] and [`Receiver`] handle pair is created by the [`channel`] +/// function. /// /// # Examples /// @@ -105,12 +108,13 @@ pub fn channel() -> (Sender, Receiver) { /// /// match rx.await { /// Ok(v) => println!("received : {:?}", v), -/// Err(_) => println!("Sender dropped") +/// Err(_) => println!("Sender dropped"), /// } /// } /// ``` /// -/// The receiver will fail with a [`RecvError`] if the sender is dropped without sending a value. +/// The receiver will fail with a [`RecvError`] if the sender is dropped without +/// sending a value. /// /// # Examples /// @@ -124,7 +128,7 @@ pub fn channel() -> (Sender, Receiver) { /// /// match rx.await { /// Ok(v) => panic!("This won't happen"), -/// Err(_) => println!("Sender dropped") +/// Err(_) => println!("Sender dropped"), /// } /// } /// ``` @@ -134,11 +138,11 @@ pub struct Sender { } impl Sender { - /// Sends a single value to the associated [`Receiver`], returns the value back - /// if it fails to send. + /// Sends a single value to the associated [`Receiver`], returns the value + /// back if it fails to send. /// - /// The sender will consume itself when calling this method. It can send a single value in - /// synchronous code as it doesn't need waiting. + /// The sender will consume itself when calling this method. It can send a + /// single value in synchronous code as it doesn't need waiting. /// /// # Examples /// @@ -154,7 +158,7 @@ impl Sender { /// /// match rx.await { /// Ok(v) => println!("received : {:?}", v), - /// Err(_) => println!("Sender dropped") + /// Err(_) => println!("Sender dropped"), /// } /// } /// ``` @@ -217,10 +221,12 @@ impl Drop for Sender { } /// Receives a single value from the associated [`Sender`]. -/// A [`Sender`] and [`Receiver`] handle pair is created by the [`channel`] function. +/// A [`Sender`] and [`Receiver`] handle pair is created by the [`channel`] +/// function. /// -/// There is no `recv` method to receive the message because the receiver itself implements the -/// [`Future`] trait. To receive a value, `.await` the `Receiver` object directly. +/// There is no `recv` method to receive the message because the receiver itself +/// implements the [`Future`] trait. To receive a value, `.await` the `Receiver` +/// object directly. /// /// # Examples /// @@ -236,12 +242,13 @@ impl Drop for Sender { /// /// match rx.await { /// Ok(v) => println!("received : {:?}", v), -/// Err(_) => println!("Sender dropped") +/// Err(_) => println!("Sender dropped"), /// } /// } /// ``` /// -/// The receiver will fail with [`RecvError`], if the sender is dropped without sending a value. +/// The receiver will fail with [`RecvError`], if the sender is dropped without +/// sending a value. /// /// # Examples /// @@ -255,7 +262,7 @@ impl Drop for Sender { /// /// match rx.await { /// Ok(v) => panic!("This won't happen"), -/// Err(_) => println!("Sender dropped") +/// Err(_) => println!("Sender dropped"), /// } /// } /// ``` @@ -267,8 +274,8 @@ pub struct Receiver { impl Receiver { /// Attempts to receive a value from the associated [`Sender`]. /// - /// The method will still receive the result if the `Sender` gets dropped after - /// sending the message. + /// The method will still receive the result if the `Sender` gets dropped + /// after sending the message. /// /// # Return value /// The function returns: @@ -328,8 +335,8 @@ impl Receiver { /// Closes the channel, prevents the `Sender` from sending a value. /// /// The `Sender` will fail to call [`send`] after the `Receiver` called - /// `close`. It will do nothing if the channel is already closed or the message - /// has been already received. + /// `close`. It will do nothing if the channel is already closed or the + /// message has been already received. /// /// [`send`]: Sender::send /// [`try_recv`]: Receiver::try_recv @@ -400,7 +407,8 @@ struct Channel { /// The state of the channel. state: AtomicUsize, - /// The value passed by channel, it is set by `Sender` and read by `Receiver`. + /// The value passed by channel, it is set by `Sender` and read by + /// `Receiver`. value: RefCell>, /// The waker to notify the sender task or the receiver task. @@ -454,16 +462,13 @@ mod tests { use crate::sync::error::RecvError; use crate::sync::oneshot; - /// UT test for `send()` and `try_recv()`. - /// - /// # Title - /// send_try_recv + /// UT test cases for `send()` and `try_recv()`. /// /// # Brief - /// 1.Call channel to create a sender and a receiver handle pair. - /// 2.Receiver tries receiving a message before the sender sends one. - /// 3.Receiver tries receiving a message after the sender sends one. - /// 4.Check if the test results are correct. + /// 1. Call channel to create a sender and a receiver handle pair. + /// 2. Receiver tries receiving a message before the sender sends one. + /// 3. Receiver tries receiving a message after the sender sends one. + /// 4. Check if the test results are correct. #[test] fn send_try_recv() { let (tx, mut rx) = oneshot::channel(); @@ -484,16 +489,13 @@ mod tests { } } - /// UT test for `send()` and async receive. - /// - /// # Title - /// send_recv_await + /// UT test cases for `send()` and async receive. /// /// # Brief - /// 1.Call channel to create a sender and a receiver handle pair. - /// 2.Sender sends message in ont thread. - /// 3.Receiver receives message in another thread. - /// 4.Check if the test results are correct. + /// 1. Call channel to create a sender and a receiver handle pair. + /// 2. Sender sends message in ont thread. + /// 3. Receiver receives message in another thread. + /// 4. Check if the test results are correct. #[test] fn send_recv_await() { let (tx, rx) = oneshot::channel(); @@ -508,17 +510,15 @@ mod tests { }); } - /// UT test for `is_closed()` and `close`. - /// - /// # Title - /// close_rx + /// UT test cases for `is_closed()` and `close`. /// /// # Brief - /// 1.Call channel to create a sender and a receiver handle pair. - /// 2.Check whether the sender is closed. - /// 3.Close the receiver. - /// 4.Check whether the receiver will receive the message sent before it closed. - /// 5.Check if the test results are correct. + /// 1. Call channel to create a sender and a receiver handle pair. + /// 2. Check whether the sender is closed. + /// 3. Close the receiver. + /// 4. Check whether the receiver will receive the message sent before it + /// closed. + /// 5. Check if the test results are correct. #[test] fn close_rx() { let (tx, mut rx) = oneshot::channel(); diff --git a/ylong_runtime/src/sync/rwlock.rs b/ylong_runtime/src/sync/rwlock.rs index 6ef3632..3ed5410 100644 --- a/ylong_runtime/src/sync/rwlock.rs +++ b/ylong_runtime/src/sync/rwlock.rs @@ -13,14 +13,15 @@ //! An asynchronous version of [`std::sync::RwLock`] -use crate::sync::semaphore_inner::SemaphoreInner; -use crate::sync::LockError; use std::cell::UnsafeCell; use std::fmt; use std::ops::{Deref, DerefMut}; use std::sync::atomic::AtomicI64; use std::sync::atomic::Ordering::{AcqRel, Acquire, Release}; +use crate::sync::semaphore_inner::SemaphoreInner; +use crate::sync::LockError; + const MAX_READS: i64 = i64::MAX >> 2; /// An asynchronous version of [`std::sync::RwLock`]. @@ -36,7 +37,6 @@ const MAX_READS: i64 = i64::MAX >> 2; /// ``` /// use ylong_runtime::sync::rwlock::RwLock; /// -/// /// ylong_runtime::block_on(async { /// let lock = RwLock::new(0); /// @@ -51,7 +51,6 @@ const MAX_READS: i64 = i64::MAX >> 2; /// let mut w = lock.write().await; /// *w += 1; /// assert_eq!(*w, 1); -/// /// }); /// ``` pub struct RwLock { @@ -92,11 +91,11 @@ impl RwLock { impl RwLock { /// Asynchronously acquires the read lock. /// - /// If there is a writer holding the write lock, then this method will wait asynchronously - /// for the write lock to get released. + /// If there is a writer holding the write lock, then this method will wait + /// asynchronously for the write lock to get released. /// - /// But if the write lock is not held, it's ok for multiple readers to hold the read lock - /// concurrently. + /// But if the write lock is not held, it's ok for multiple readers to hold + /// the read lock concurrently. /// /// /// @@ -120,8 +119,9 @@ impl RwLock { RwLockReadGuard(self) } - /// Attempts to get the read lock. If another writer is holding the write lock, then - /// None will be returned. Otherwise, the ReadMutexGuard will be returned. + /// Attempts to get the read lock. If another writer is holding the write + /// lock, then None will be returned. Otherwise, the ReadMutexGuard will + /// be returned. /// /// # Examples /// @@ -157,8 +157,8 @@ impl RwLock { /// Asynchronously acquires the write lock. /// - /// If there is other readers or writers, then this method will wait asynchronously - /// for them to get released. + /// If there is other readers or writers, then this method will wait + /// asynchronously for them to get released. /// /// # Examples /// @@ -177,9 +177,9 @@ impl RwLock { // `RwLock` will not close, so the result of `acquire()` must be `Ok(())`. self.write_mutex.acquire().await.unwrap(); let read_count = self.read_count.fetch_sub(MAX_READS, Release); - // If the `read_count` is not 0, it indicates that there is currently a reader holding - // a read lock. If the `read_wait` is 0 after addition, it indicates that all readers have - // been dropped. + // If the `read_count` is not 0, it indicates that there is currently a reader + // holding a read lock. If the `read_wait` is 0 after addition, it + // indicates that all readers have been dropped. if read_count >= 0 && self.read_wait.fetch_add(read_count, Release) != -read_count { self.write_sem.acquire().await.unwrap(); } @@ -235,9 +235,9 @@ impl RwLock { /// Gets the mutable reference of the data protected by the lock. /// - /// This method takes the mutable reference of the RwLock, so there is no need to actually - /// lock the RwLock -- the mutable borrow statically guarantees no locks exist. - /// ``` + /// This method takes the mutable reference of the RwLock, so there is no + /// need to actually lock the RwLock -- the mutable borrow statically + /// guarantees no locks exist. ``` /// use ylong_runtime::sync::rwlock::RwLock; /// /// ylong_runtime::block_on(async { @@ -257,7 +257,8 @@ pub struct RwLockReadGuard<'a, T: ?Sized>(&'a RwLock); unsafe impl Send for RwLockReadGuard<'_, T> {} unsafe impl Sync for RwLockReadGuard<'_, T> {} -/// Releases the read lock. Wakes any waiting writer if it's the last one holding the read lock. +/// Releases the read lock. Wakes any waiting writer if it's the last one +/// holding the read lock. impl RwLockReadGuard<'_, T> { fn unlock(&mut self) { if self.0.read_count.fetch_sub(1, Release) < 0 @@ -301,7 +302,8 @@ pub struct RwLockWriteGuard<'a, T: ?Sized>(&'a RwLock); unsafe impl Send for RwLockWriteGuard<'_, T> {} unsafe impl Sync for RwLockWriteGuard<'_, T> {} -/// Wakes all waiting readers first and releases the write lock when WriteGuard is dropped. +/// Wakes all waiting readers first and releases the write lock when WriteGuard +/// is dropped. impl Drop for RwLockWriteGuard<'_, T> { fn drop(&mut self) { let read_count = self.0.read_count.fetch_add(MAX_READS, Release) + MAX_READS; @@ -337,20 +339,17 @@ impl DerefMut for RwLockWriteGuard<'_, T> { #[cfg(test)] mod tests { - use super::*; - use crate::{block_on, spawn}; use std::sync::Arc; - /* - * @title Rwlock::new() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon Create a test structure with two members: flag, num - * @brief Test case execution steps: - * 1. Create a concurrent read/write lock with structure and value as input parameters - * 2. Verify the contents of the read/write lock - * @expect The flag inside the Test structure in lock is true, num is 1, and the value in lock2 is 0 - * @auto Yes - */ + use super::*; + use crate::{block_on, spawn}; + + /// UT test cases for Rwlock::new() + /// + /// # Brief + /// 1. Create a concurrent read/write lock with structure and value as input + /// parameters + /// 2. Verify the contents of the read/write lock #[test] fn ut_rwlock_new_01() { pub struct Test { @@ -366,17 +365,12 @@ mod tests { }); } - /* - * @title Rwlock::read() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Calling the read() function - * 3. Verify the value of the read() function dereference - * @expect The value in lock is 100 - * @auto Yes - */ + /// UT test cases for Rwlock::read() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Calling the read() function + /// 3. Verify the value of the read() function dereference #[test] fn ut_rwlock_read_01() { block_on(async { @@ -386,17 +380,14 @@ mod tests { }); } - /* - * @title Rwlock::read() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Call the write() function to make changes to the concurrent read/write lock data - * 3. Call the read() function to verify the value in the read/write lock of the concurrent process - * @expect The modified value in lock is 101 - * @auto Yes - */ + /// UT test cases for Rwlock::read() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Call the write() function to make changes to the concurrent + /// read/write lock data + /// 3. Call the read() function to verify the value in the read/write lock + /// of the concurrent process #[test] fn ut_rwlock_read_02() { let lock = Arc::new(RwLock::new(100)); @@ -413,17 +404,12 @@ mod tests { }); } - /* - * @title Rwlock::try_read() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Call try_read() - * 3. Verify the value of the return value dereference - * @expect res resolves the reference value to 100 - * @auto Yes - */ + /// UT test cases for Rwlock::try_read() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Call try_read() + /// 3. Verify the value of the return value dereference #[test] fn ut_rwlock_try_read_01() { let lock = RwLock::new(100); @@ -431,18 +417,14 @@ mod tests { assert_eq!(*res, 100); } - /* - * @title Rwlock::try_read() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Create a thread to call the write method to hold the lock, and then sleep to hold the lock for a long time - * 3. Call try_read() to try to get a lock - * 4. Check the try_read return value - * @expect res is None - * @auto Yes - */ + /// UT test cases for Rwlock::try_read() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Create a thread to call the write method to hold the lock, and then + /// sleep to hold the lock for a long time + /// 3. Call try_read() to try to get a lock + /// 4. Check the try_read return value #[test] fn ut_rwlock_try_read_02() { let lock = Arc::new(RwLock::new(100)); @@ -456,17 +438,13 @@ mod tests { assert!(res2.is_ok()); } - /* - * @title Rwlock::write() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Create a call to the write interface to modify the value inside the concurrent read/write lock - * 3. Verify the value of the concurrent read/write lock - * @expect The unreferenced value of a is 200 - * @auto Yes - */ + /// UT test cases for Rwlock::write() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Create a call to the write interface to modify the value inside the + /// concurrent read/write lock + /// 3. Verify the value of the concurrent read/write lock #[test] fn ut_rwlock_write_01() { let lock = Arc::new(RwLock::new(100)); @@ -477,18 +455,17 @@ mod tests { }); } - /* - * @title Rwlock::write() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. First create a thread to obtain a write lock, modify the data in the concurrent read/write lock, and then hibernate to ensure that the lock is held for a long time - * 3. Create two co-processes one to get a read lock and one to get a write lock, so that there is both a reader and a writer requesting the lock - * 4. Verify the value inside the concurrent read/write lock when the concurrent read/write lock is obtained - * @expect aa's dereference is 300 - * @auto Yes - */ + /// UT test cases for Rwlock::write() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. First create a thread to obtain a write lock, modify the data in the + /// concurrent read/write lock, and then hibernate to ensure that the + /// lock is held for a long time + /// 3. Create two co-processes one to get a read lock and one to get a write + /// lock, so that there is both a reader and a writer requesting the lock + /// 4. Verify the value inside the concurrent read/write lock when the + /// concurrent read/write lock is obtained #[test] fn ut_rwlock_write_test_02() { let lock = Arc::new(RwLock::new(100)); @@ -513,17 +490,13 @@ mod tests { block_on(handle2).unwrap(); } - /* - * @title Rwlock::try_write() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Call try_write() to try to get a write lock and modify the value in it - * 3. Verify the value in the read/write lock of the concurrent process - * @expect The dereference of aa is 200 - * @auto Yes - */ + /// UT test cases for Rwlock::try_write() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Call try_write() to try to get a write lock and modify the value in + /// it + /// 3. Verify the value in the read/write lock of the concurrent process #[test] fn ut_rwlock_try_write_01() { let lock = RwLock::new(100); @@ -532,16 +505,11 @@ mod tests { assert_eq!(*aa, 200); } - /* - * @title Rwlock::try_write() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Creating a concurrent read/write lock - * 2. Execute command cargo test ut_rwlock_try_write_02 - * @expect res is None - * @auto Yes - */ + /// UT test cases for Rwlock::try_write() + /// + /// # Brief + /// 1. Creating a concurrent read/write lock + /// 2. Execute command cargo test ut_rwlock_try_write_02 #[test] fn ut_rwlock_try_write_02() { let lock = Arc::new(RwLock::new(100)); @@ -555,16 +523,12 @@ mod tests { assert!(res2.is_ok()); } - /* - * @title Rwlock::into_inner() ut test - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Describe the test case execution, an example of which is as follows: - * 1. Add a temporary library path to the project directory export LD_LIBRARY_PATH=$(pwd)/platform - * 2. Execute command cargo test ut_rwlock_into_inner_01 - * @expect The value after the lock call function is 10 - * @auto Yes - */ + /// UT test cases for Rwlock::into_inner() + /// + /// # Brief + /// 1. Add a temporary library path to the project directory export + /// LD_LIBRARY_PATH=$(pwd)/platform + /// 2. Execute command cargo test ut_rwlock_into_inner_01 #[test] fn ut_rwlock_into_inner_01() { let lock = RwLock::new(10); diff --git a/ylong_runtime/src/sync/semaphore.rs b/ylong_runtime/src/sync/semaphore.rs index 1fe56a2..745fb60 100644 --- a/ylong_runtime/src/sync/semaphore.rs +++ b/ylong_runtime/src/sync/semaphore.rs @@ -15,64 +15,67 @@ use crate::sync::semaphore_inner::{SemaphoreError, SemaphoreInner}; -/// Asynchronous counting semaphore. It allows more than one caller to access the shared resource. -/// Semaphore contains a set of permits. Call `acquire` method and get a permit to access the shared -/// resource. When permits are used up, new requests to acquire permit will wait until `release` method -/// is called. When no request is waiting, calling `release` method will add a permit to semaphore. +/// Asynchronous counting semaphore. It allows more than one caller to access +/// the shared resource. Semaphore contains a set of permits. Call `acquire` +/// method and get a permit to access the shared resource. When permits are used +/// up, new requests to acquire permit will wait until `release` method +/// is called. When no request is waiting, calling `release` method will add a +/// permit to semaphore. /// -/// The difference between [`AutoRelSemaphore`] and [`Semaphore`] is that permit acquired from -/// [`Semaphore`] will be consumed. When permit from [`AutoRelSemaphore`] is dropped, it will be -/// assigned to another acquiring request or returned to the semaphore. +/// The difference between [`AutoRelSemaphore`] and [`Semaphore`] is that permit +/// acquired from [`Semaphore`] will be consumed. When permit from +/// [`AutoRelSemaphore`] is dropped, it will be assigned to another acquiring +/// request or returned to the semaphore. /// /// # Examples /// /// ``` -/// /// use std::sync::Arc; +/// /// use ylong_runtime::sync::semaphore::Semaphore; /// -/// async fn io_func() { +/// async fn io_func() { /// let sem = Arc::new(Semaphore::new(2).unwrap()); /// let sem2 = sem.clone(); /// let _permit1 = sem.try_acquire(); /// ylong_runtime::spawn(async move { /// let _permit2 = sem2.acquire().await.unwrap(); /// }); -/// } -/// +/// } /// ``` pub struct Semaphore { inner: SemaphoreInner, } -/// Asynchronous counting semaphore. It allows more than one caller to access the shared resource. -/// semaphore contains a set of permits. Call `acquire` method and get a permit to access the shared -/// resource. The total number of permits is fixed. When no permits are available, new request to -/// acquire permit will wait until another permit is dropped. When no request is waiting and one permit -/// is **dropped**, the permit will be return to semaphore so that the number of permits in semaphore will -/// increase. +/// Asynchronous counting semaphore. It allows more than one caller to access +/// the shared resource. semaphore contains a set of permits. Call `acquire` +/// method and get a permit to access the shared resource. The total number of +/// permits is fixed. When no permits are available, new request to +/// acquire permit will wait until another permit is dropped. When no request is +/// waiting and one permit is **dropped**, the permit will be return to +/// semaphore so that the number of permits in semaphore will increase. /// -/// The difference between [`AutoRelSemaphore`] and [`Semaphore`] is that permit acquired from -/// [`Semaphore`] will be consumed. When permit from [`AutoRelSemaphore`] is dropped, it will be -/// assigned to another acquiring request or returned to the semaphore, in other words, permit will +/// The difference between [`AutoRelSemaphore`] and [`Semaphore`] is that permit +/// acquired from [`Semaphore`] will be consumed. When permit from +/// [`AutoRelSemaphore`] is dropped, it will be assigned to another acquiring +/// request or returned to the semaphore, in other words, permit will /// be automatically released when it is dropped. /// /// # Examples /// /// ``` -/// /// use std::sync::Arc; +/// /// use ylong_runtime::sync::semaphore::AutoRelSemaphore; /// -/// async fn io_func() { +/// async fn io_func() { /// let sem = Arc::new(AutoRelSemaphore::new(2).unwrap()); /// let sem2 = sem.clone(); /// let _permit1 = sem.try_acquire(); /// ylong_runtime::spawn(async move { /// let _permit2 = sem2.acquire().await.unwrap(); /// }); -/// } -/// +/// } /// ``` pub struct AutoRelSemaphore { inner: SemaphoreInner, @@ -94,11 +97,9 @@ impl Semaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::Semaphore; /// /// let sem = Semaphore::new(4).unwrap(); - /// /// ``` pub fn new(permits: usize) -> Result { match SemaphoreInner::new(permits) { @@ -112,11 +113,9 @@ impl Semaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::Semaphore; /// let sem = Semaphore::new(4).unwrap(); /// assert_eq!(sem.current_permits(), 4); - /// /// ``` pub fn current_permits(&self) -> usize { self.inner.current_permits() @@ -127,14 +126,12 @@ impl Semaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::Semaphore; /// /// let sem = Semaphore::new(4).unwrap(); /// assert_eq!(sem.current_permits(), 4); /// sem.release(); /// assert_eq!(sem.current_permits(), 5); - /// /// ``` pub fn release(&self) { self.inner.release(); @@ -151,7 +148,6 @@ impl Semaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::Semaphore; /// /// let sem = Semaphore::new(4).unwrap(); @@ -160,7 +156,6 @@ impl Semaphore { /// assert_eq!(sem.current_permits(), 3); /// drop(permit); /// assert_eq!(sem.current_permits(), 3); - /// /// ``` pub fn try_acquire(&self) -> Result { match self.inner.try_acquire() { @@ -185,27 +180,25 @@ impl Semaphore { /// ylong_runtime::spawn(async move { /// let _permit2 = sem.acquire().await.unwrap(); /// }); - /// } - /// + /// } /// ``` pub async fn acquire(&self) -> Result { self.inner.acquire().await?; Ok(SemaphorePermit) } - /// Checks whether semaphore is closed. If so, the semaphore could not be acquired anymore. + /// Checks whether semaphore is closed. If so, the semaphore could not be + /// acquired anymore. /// /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::semaphore::Semaphore; /// /// let sem = Semaphore::new(4).unwrap(); /// assert!(!sem.is_closed()); /// sem.close(); /// assert!(sem.is_closed()); - /// /// ``` pub fn is_closed(&self) -> bool { self.inner.is_closed() @@ -217,14 +210,12 @@ impl Semaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::Semaphore; /// /// let sem = Semaphore::new(4).unwrap(); /// assert!(!sem.is_closed()); /// sem.close(); /// assert!(sem.is_closed()); - /// /// ``` pub fn close(&self) { self.inner.close(); @@ -237,11 +228,9 @@ impl AutoRelSemaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::AutoRelSemaphore; /// /// let sem = AutoRelSemaphore::new(4).unwrap(); - /// /// ``` pub fn new(number: usize) -> Result { match SemaphoreInner::new(number) { @@ -255,11 +244,9 @@ impl AutoRelSemaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::AutoRelSemaphore; /// let sem = AutoRelSemaphore::new(4).unwrap(); /// assert_eq!(sem.current_permits(), 4); - /// /// ``` pub fn current_permits(&self) -> usize { self.inner.current_permits() @@ -276,7 +263,6 @@ impl AutoRelSemaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::AutoRelSemaphore; /// /// let sem = AutoRelSemaphore::new(4).unwrap(); @@ -285,7 +271,6 @@ impl AutoRelSemaphore { /// assert_eq!(sem.current_permits(), 3); /// drop(permit); /// assert_eq!(sem.current_permits(), 4); - /// /// ``` pub fn try_acquire(&self) -> Result, SemaphoreError> { match self.inner.try_acquire() { @@ -304,7 +289,6 @@ impl AutoRelSemaphore { /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::AutoRelSemaphore; /// /// async fn io_func() { @@ -312,47 +296,42 @@ impl AutoRelSemaphore { /// ylong_runtime::spawn(async move { /// let _permit2 = sem.acquire().await.unwrap(); /// }); - /// } - /// + /// } /// ``` pub async fn acquire(&self) -> Result, SemaphoreError> { self.inner.acquire().await?; Ok(AutoRelSemaphorePermit { sem: self }) } - /// Checks whether the state of semaphore is closed, if so, the semaphore could not acquire - /// permits anymore. + /// Checks whether the state of semaphore is closed, if so, the semaphore + /// could not acquire permits anymore. /// /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::AutoRelSemaphore; /// /// let sem = AutoRelSemaphore::new(4).unwrap(); /// assert!(!sem.is_closed()); /// sem.close(); /// assert!(sem.is_closed()); - /// /// ``` pub fn is_closed(&self) -> bool { self.inner.is_closed() } - /// Turns the state of semaphore to be closed so that semaphore could not acquire - /// permits anymore, and notify all request in the waiting list. + /// Turns the state of semaphore to be closed so that semaphore could not + /// acquire permits anymore, and notify all request in the waiting list. /// /// # Examples /// /// ``` - /// /// use ylong_runtime::sync::AutoRelSemaphore; /// /// let sem = AutoRelSemaphore::new(4).unwrap(); /// assert!(!sem.is_closed()); /// sem.close(); /// assert!(sem.is_closed()); - /// /// ``` pub fn close(&self) { self.inner.close(); diff --git a/ylong_runtime/src/sync/semaphore_inner.rs b/ylong_runtime/src/sync/semaphore_inner.rs index 3af9061..3239ab8 100644 --- a/ylong_runtime/src/sync/semaphore_inner.rs +++ b/ylong_runtime/src/sync/semaphore_inner.rs @@ -11,7 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::sync::wake_list::WakerList; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::future::Future; @@ -21,6 +20,8 @@ use std::sync::atomic::Ordering::{AcqRel, Acquire, Release}; use std::task::Poll::{Pending, Ready}; use std::task::{Context, Poll}; +use crate::sync::wake_list::WakerList; + /// Maximum capacity of `Semaphore`. const MAX_PERMITS: usize = usize::MAX >> 1; /// The least significant bit that marks the number of permits. @@ -234,7 +235,7 @@ impl Future for Permit<'_> { impl Drop for Permit<'_> { fn drop(&mut self) { if self.enqueue { - //if `enqueue` is true, `waker_index` must be `Some(_)`. + // if `enqueue` is true, `waker_index` must be `Some(_)`. let _ = self.semaphore.waker_list.remove(self.waker_index.unwrap()); } } diff --git a/ylong_runtime/src/sync/waiter.rs b/ylong_runtime/src/sync/waiter.rs index bd66117..bff6152 100644 --- a/ylong_runtime/src/sync/waiter.rs +++ b/ylong_runtime/src/sync/waiter.rs @@ -24,18 +24,19 @@ use crate::sync::semaphore_inner::SemaphoreInner; /// /// ``` /// use std::sync::Arc; +/// /// use ylong_runtime::sync::waiter::Waiter; /// /// let waiter = Arc::new(Waiter::new()); /// let waiter2 = waiter.clone(); /// /// let _ = ylong_runtime::block_on(async { -/// let handle = ylong_runtime::spawn(async move { +/// let handle = ylong_runtime::spawn(async move { /// waiter2.wait().await; -/// }); -/// waiter.wake_one(); -/// let _ = handle.await; -/// }); +/// }); +/// waiter.wake_one(); +/// let _ = handle.await; +/// }); /// ``` pub struct Waiter { sem: SemaphoreInner, @@ -65,6 +66,7 @@ impl Waiter { /// /// ``` /// use std::sync::Arc; + /// /// use ylong_runtime::sync::waiter::Waiter; /// /// let waiter = Arc::new(Waiter::new()); @@ -75,7 +77,7 @@ impl Waiter { /// }); /// waiter.wake_one(); /// let _ = handle.await; - /// }); + /// }); /// ``` pub async fn wait(&self) { // The result of `acquire()` will be `Err()` only when the semaphore is closed. @@ -88,15 +90,16 @@ impl Waiter { /// If this method gets called when there is no task waiting on this Waiter, /// then the next task called `wait` on it will not get blocked. /// - /// If this method gets called multiple times, only one task will get passed straightly - /// when calling `wait`. Any other task still has to asynchronously wait for it to be - /// released. + /// If this method gets called multiple times, only one task will get passed + /// straightly when calling `wait`. Any other task still has to + /// asynchronously wait for it to be released. /// /// /// # Examples /// /// ``` /// use std::sync::Arc; + /// /// use ylong_runtime::sync::waiter::Waiter; /// /// let waiter = Arc::new(Waiter::new()); @@ -107,7 +110,7 @@ impl Waiter { /// }); /// waiter.wake_one(); /// let _ = handle.await; - /// }); + /// }); /// ``` pub fn wake_one(&self) { self.sem.release_notify(); @@ -115,8 +118,9 @@ impl Waiter { /// Notifies all tasks waiting on it. /// - /// Unlike `wake_one`, if this method gets called when there is no task waiting on this wake, - /// then the next task called `wait` on it will `still` get blocked. + /// Unlike `wake_one`, if this method gets called when there is no task + /// waiting on this wake, then the next task called `wait` on it will + /// `still` get blocked. /// /// # Examples /// diff --git a/ylong_runtime/src/sync/wake_list.rs b/ylong_runtime/src/sync/wake_list.rs index c676690..283c2a9 100644 --- a/ylong_runtime/src/sync/wake_list.rs +++ b/ylong_runtime/src/sync/wake_list.rs @@ -11,14 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::util::slots::Slots; -use crate::util::slots::SlotsError; use std::cell::UnsafeCell; use std::hint::spin_loop; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::task::Waker; +use crate::util::slots::{Slots, SlotsError}; + /// The first left most bit represents LOCKED state const LOCKED: usize = 1 << 0; /// The third left most bit represents NOTIFIABLE state @@ -34,9 +34,9 @@ pub(crate) struct WakerList { inner: UnsafeCell, } -/// Safety: `WakerList` is not `Sync` and `Send` because of `UnsafeCell`. However, -/// we lock `WakerList` first when we try to access it. So it is safe for `WakerList` to be sent -/// and borrowed across threads. +/// Safety: `WakerList` is not `Sync` and `Send` because of `UnsafeCell`. +/// However, we lock `WakerList` first when we try to access it. So it is safe +/// for `WakerList` to be sent and borrowed across threads. unsafe impl Sync for WakerList {} unsafe impl Send for WakerList {} @@ -64,17 +64,18 @@ impl WakerList { inner.wake_list.remove(key) } - /// Wakes up one more member, no matter whether someone is being waking up at the same time. - /// This method is an atomic operation. If a non-atomic operation is required, - /// call `lock` first and then call `notify_one`. + /// Wakes up one more member, no matter whether someone is being waking up + /// at the same time. This method is an atomic operation. If a + /// non-atomic operation is required, call `lock` first and then call + /// `notify_one`. #[inline] pub fn notify_one(&self) -> bool { self.notify(Notify::One) } /// Wakes up all members in the WakerList, and return the result. - /// This method is an atomic operation. If a non-atomic operation is required, - /// call `lock` first and then call `notify_all`. + /// This method is an atomic operation. If a non-atomic operation is + /// required, call `lock` first and then call `notify_all`. #[inline] pub fn notify_all(&self) -> bool { self.notify(Notify::All) @@ -89,7 +90,8 @@ impl WakerList { } } - /// Locks up the WakerList. If it has been already locked, spin loop until fetch the lock. + /// Locks up the WakerList. If it has been already locked, spin loop until + /// fetch the lock. pub fn lock(&self) -> Lock<'_> { // This condition will be false only if the flag is LOCKED. while self.flag.fetch_or(LOCKED, Ordering::Acquire) & LOCKED != 0 { @@ -115,7 +117,8 @@ impl Inner { is_wake } - /// Wakes up one more member, no matter whether someone is being waking up at the same time. + /// Wakes up one more member, no matter whether someone is being waking up + /// at the same time. #[inline] pub fn notify_one(&mut self) -> bool { self.notify(Notify::One) @@ -137,8 +140,8 @@ impl Drop for Lock<'_> { #[inline] fn drop(&mut self) { let mut flag = 0; - // If there're members that can be notified, set the third left most bit, which means to - // add NOTIFIABLE state to the flag. + // If there're members that can be notified, set the third left most bit, which + // means to add NOTIFIABLE state to the flag. if !self.wake_list.is_empty() { flag |= NOTIFIABLE; } @@ -172,12 +175,11 @@ enum Notify { mod tests { use super::*; - /// UT test for WakeList::new(). - /// # Title - /// ut_wakelist_new_01 + /// UT test cases for WakeList::new(). + /// /// # Brief - /// 1.Check the initial value of flag. - /// 2.Check the initial value of waiting_number. + /// 1. Check the initial value of flag. + /// 2. Check the initial value of waiting_number. #[test] fn ut_wakelist_new_01() { let wakelist = WakerList::new(); diff --git a/ylong_runtime/src/task/builder.rs b/ylong_runtime/src/task/builder.rs index 25fae4e..0ae177e 100644 --- a/ylong_runtime/src/task/builder.rs +++ b/ylong_runtime/src/task/builder.rs @@ -11,18 +11,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Builder to configure the task. Tasks that get spawned through [`TaskBuilder`] inherit all -//! attributes of this builder. +//! Builder to configure the task. Tasks that get spawned through +//! [`TaskBuilder`] inherit all attributes of this builder. //! //! A task has following attributes: //! - priority //! - task name -use crate::spawn::spawn_async; -use crate::spawn::spawn_blocking; +use std::future::Future; + +use crate::spawn::{spawn_async, spawn_blocking}; use crate::task::PriorityLevel; use crate::JoinHandle; -use std::future::Future; /// Tasks attribute #[derive(Clone)] @@ -99,7 +99,7 @@ impl TaskBuilder { } } -#[cfg(all(test))] +#[cfg(test)] mod test { use crate::task::{PriorityLevel, TaskBuilder}; @@ -111,19 +111,15 @@ mod test { ut_builder_insert_front(); ut_builder_stat(); } - /* - * @title Builder::new ut test - * @design No entry, no exception branch - * @precon After calling the Builder::new function, get its object - * @brief Describe test case execution - * 1、Checks if the object name property is None - * 2、Checks if the object pri property is None - * 3、Checks if the object worker_id property is None - * 4、Checks if the object is_stat property is false - * 5、Checks if the object is_insert_front property is false - * @expect The initialized parameters should correspond to the set ones - * @auto true - */ + + /// UT test cases for Builder::new + /// + /// # Brief + /// 1. Checks if the object name property is None + /// 2. Checks if the object pri property is None + /// 3. Checks if the object worker_id property is None + /// 4. Checks if the object is_stat property is false + /// 5. Checks if the object is_insert_front property is false fn ut_builder_new() { let builder = TaskBuilder::new(); assert_eq!(builder.name, None); @@ -132,15 +128,10 @@ mod test { assert!(!builder.is_insert_front); } - /* - * @title Builder::name ut test - * @design No invalid values, no abnormal branches - * @precon After calling the Builder::new function, get its object - * @brief Describe test case execution - * 1、Checks if the object name property is a modified value - * @expect Parameters and modified values should correspond to each other - * @auto true - */ + /// UT test cases for Builder::name + /// + /// # Brief + /// 1. Checks if the object name property is a modified value fn ut_builder_name() { let builder = TaskBuilder::new(); @@ -148,19 +139,14 @@ mod test { assert_eq!(builder.name(name.clone()).name.unwrap(), name); } - /* - * @title Builder::name ut test - * @design No invalid values, no abnormal branches - * @precon After calling the Builder::new function, get its object - * @brief Describe test case execution - * 1、pri set to AbsHigh, check return value - * 2、pri set to High, check return value - * 3、pri set to Low, check return value - * 4、pri set to AbsLow, check return value - * 5、pri set to Butt, check return value - * @expect Parameters and modified values should correspond to each other - * @auto true - */ + /// UT test cases for Builder::name + /// + /// # Brief + /// 1. pri set to AbsHigh, check return value + /// 2. pri set to High, check return value + /// 3. pri set to Low, check return value + /// 4. pri set to AbsLow, check return value + /// 5. pri set to Butt, check return value fn ut_builder_pri() { let builder = TaskBuilder::new(); let pri = PriorityLevel::AbsHigh; @@ -179,16 +165,11 @@ mod test { assert_eq!(builder.priority(pri).pri.unwrap(), pri); } - /* - * @title Builder::stat ut test - * @design No invalid values, no abnormal branches - * @precon After calling the Builder::new function, get its object - * @brief Describe test case execution - * 1、is_stat set to true, check return value - * 2、is_stat set to false, check return value - * @expect Parameters and modified values should correspond to each other - * @auto true - */ + /// UT test cases for Builder::stat + /// + /// # Brief + /// 1. is_stat set to true, check return value + /// 2. is_stat set to false, check return value fn ut_builder_stat() { let builder = TaskBuilder::new(); let is_stat = true; @@ -199,16 +180,11 @@ mod test { assert_eq!(builder.stat(is_stat).is_stat, is_stat); } - /* - * @title Builder::insert_front ut test - * @design No invalid values, no abnormal branches - * @precon After calling the Builder::new function, get its object - * @brief Describe test case execution - * 1、is_insert_front set to true, check return value - * 2、is_insert_front set to false, check return value - * @expect Parameters and modified values should correspond to each other - * @auto true - */ + /// UT test cases for Builder::insert_front + /// + /// # Brief + /// 1. is_insert_front set to true, check return value + /// 2. is_insert_front set to false, check return value fn ut_builder_insert_front() { let builder = TaskBuilder::new(); let is_insert_front = true; diff --git a/ylong_runtime/src/task/join_handle.rs b/ylong_runtime/src/task/join_handle.rs index b595480..ce45375 100644 --- a/ylong_runtime/src/task/join_handle.rs +++ b/ylong_runtime/src/task/join_handle.rs @@ -13,34 +13,36 @@ //! Joinhandle for asynchronous tasks. //! -//! [`JoinHandle`] is similar to a JoinHandle for a thread. It could be used to await an -//! asynchronous task to finish to get its result. +//! [`JoinHandle`] is similar to a JoinHandle for a thread. It could be used to +//! await an asynchronous task to finish to get its result. -use crate::error::ScheduleError; -use crate::task::raw::RawTask; -use crate::task::state; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll, Waker}; + #[cfg(feature = "ffrt")] use ylong_ffrt::FfrtTaskHandle; +use crate::error::ScheduleError; +use crate::task::raw::RawTask; +use crate::task::state; + /// A handle to the actual spawned task. /// /// This can be considered as the equivalent of [`std::thread::JoinHandle`] /// for a ylong task rather than a thread. /// /// It could be used to join the corresponding task or cancel it. -/// If a `JoinHandle` is dropped, then the task continues executing in the background -/// and its return value is lost. There is no way to join the task after its JoinHandle is -/// dropped. +/// If a `JoinHandle` is dropped, then the task continues executing in the +/// background and its return value is lost. There is no way to join the task +/// after its JoinHandle is dropped. /// /// # Examples /// /// ``` /// let handle = ylong_runtime::spawn(async { -/// let handle2 = ylong_runtime::spawn(async {1}); +/// let handle2 = ylong_runtime::spawn(async { 1 }); /// assert_eq!(handle2.await.unwrap(), 1); /// }); /// ylong_runtime::block_on(handle).unwrap(); @@ -61,10 +63,11 @@ impl JoinHandle { } } - /// Cancels the task associating with this JoinHandle. If the task has already finished, - /// this method does nothing. + /// Cancels the task associating with this JoinHandle. If the task has + /// already finished, this method does nothing. /// - /// When successfully canceled, `.await` on this JoinHandle will return a `TaskCanceled` error. + /// When successfully canceled, `.await` on this JoinHandle will return a + /// `TaskCanceled` error. pub fn cancel(&self) { unsafe { self.raw.cancel(); @@ -143,13 +146,14 @@ impl CancelHandle { /// Cancels the task associated with this handle. /// - /// If the task has been already finished or it is currently running and about to finish, - /// then this method will do nothing. + /// If the task has been already finished or it is currently running and + /// about to finish, then this method will do nothing. pub fn cancel(&self) { unsafe { self.raw.cancel() } } - /// Checks whether the task associated with this handle has finished executing. + /// Checks whether the task associated with this handle has finished + /// executing. pub fn is_finished(&self) -> bool { let state = self.raw.header().state.get_current_state(); state::is_finished(state) diff --git a/ylong_runtime/src/task/join_set.rs b/ylong_runtime/src/task/join_set.rs index 854b389..fae744e 100644 --- a/ylong_runtime/src/task/join_set.rs +++ b/ylong_runtime/src/task/join_set.rs @@ -11,10 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::spawn::spawn_async; -use crate::task::join_handle::CancelHandle; -use crate::task::PriorityLevel; -use crate::{JoinHandle, ScheduleError, TaskBuilder}; use std::cell::{RefCell, UnsafeCell}; use std::collections::{HashSet, LinkedList}; use std::future::Future; @@ -25,12 +21,17 @@ use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; +use crate::spawn::spawn_async; +use crate::task::join_handle::CancelHandle; +use crate::task::PriorityLevel; +use crate::{JoinHandle, ScheduleError, TaskBuilder}; + /// A collection of tasks get spawned on a Ylong runtime /// -/// A `JoinSet` will take over the `JoinHandle`s of the tasks when spawning, and it can -/// asynchronously wait for the completion of some or all of the tasks inside the set. -/// However, `JoinSet` is unordered, which means that tasks' results will be returned -/// in the order of their completion. +/// A `JoinSet` will take over the `JoinHandle`s of the tasks when spawning, and +/// it can asynchronously wait for the completion of some or all of the tasks +/// inside the set. However, `JoinSet` is unordered, which means that tasks' +/// results will be returned in the order of their completion. /// /// All the tasks spawned via a `JoinSet` must have the same return type. /// @@ -41,9 +42,7 @@ use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; /// /// async fn join_set_spawn() { /// let mut set = JoinSet::new(); -/// set.spawn(async move { -/// 0 -/// }); +/// set.spawn(async move { 0 }); /// let ret = set.join_next().await.unwrap().unwrap(); /// assert_eq!(ret, 0) /// } @@ -114,14 +113,16 @@ impl Hash for JoinEntry { } impl JoinEntry { - // When waking a JoinEntry, the entry will get popped out of the wait list and pushed into - // the ready list. The corresponding in_done flag will also be changed. - // Safety: it will take the list's lock before moving the entry, so it's concurrently safe. + // When waking a JoinEntry, the entry will get popped out of the wait list and + // pushed into the ready list. The corresponding in_done flag will also be + // changed. Safety: it will take the list's lock before moving the entry, so + // it's concurrently safe. fn wake_by_ref(entry: &Arc>) { let mut list = entry.list.lock().unwrap(); if !entry.in_done.replace(true) { - // We couldn't find the entry, meaning that the JoinSet has been dropped already. - // In this case, there is no need to push the entry back to the done list. + // We couldn't find the entry, meaning that the JoinSet has been dropped + // already. In this case, there is no need to push the entry back to + // the done list. if !list.wait_list.remove(entry) { return; } @@ -136,8 +137,8 @@ impl JoinEntry { } impl JoinSet { - /// Spawns a task via a `JoinSet` onto a Ylong runtime. The task will start immediately - /// when `spawn` is called. + /// Spawns a task via a `JoinSet` onto a Ylong runtime. The task will start + /// immediately when `spawn` is called. /// /// # Panics /// This method panics when calling outside of Ylong runtime. @@ -148,7 +149,7 @@ impl JoinSet { /// use ylong_runtime::task::JoinSet; /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); - /// let cancel_handle = set.spawn(async move {1}); + /// let cancel_handle = set.spawn(async move { 1 }); /// cancel_handle.cancel(); /// }); /// ``` @@ -186,7 +187,8 @@ impl JoinSet { cancel } - /// Waits until one task inside the `JoinSet` completes and returns its output. + /// Waits until one task inside the `JoinSet` completes and returns its + /// output. /// /// Returns `None` if there is no task inside the set. /// @@ -196,7 +198,7 @@ impl JoinSet { /// use ylong_runtime::task::JoinSet; /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); - /// set.spawn(async move {1}); + /// set.spawn(async move { 1 }); /// let ret = set.join_next().await.unwrap().unwrap(); /// assert_eq!(ret, 1); /// // no more task, so this `join_next` will return none @@ -225,15 +227,15 @@ impl JoinSet { /// Cancels every tasks inside the JoinSet. /// - /// If [`JoinSet::join_next`] is called after calling `cancel_all`, then it would return - /// `TaskCanceled` error. + /// If [`JoinSet::join_next`] is called after calling `cancel_all`, then it + /// would return `TaskCanceled` error. /// /// # Examples /// ``` /// use ylong_runtime::task::JoinSet; /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); - /// set.spawn(async move {1}); + /// set.spawn(async move { 1 }); /// set.cancel_all(); /// }); /// ``` @@ -254,7 +256,7 @@ impl JoinSet { /// use ylong_runtime::task::JoinSet; /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); - /// set.spawn(async move {1}); + /// set.spawn(async move { 1 }); /// set.shutdown(); /// }); /// ``` @@ -263,8 +265,8 @@ impl JoinSet { while self.join_next().await.is_some() {} } - /// Creates a builder that configures task attributes. This builder could spawn tasks - /// with its attributes onto the JoinSet. + /// Creates a builder that configures task attributes. This builder could + /// spawn tasks with its attributes onto the JoinSet. /// /// # Examples /// ``` @@ -272,7 +274,7 @@ impl JoinSet { /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); /// let mut builder = set.build_task().name("hello".into()); - /// builder.spawn(async move {1}); + /// builder.spawn(async move { 1 }); /// }); /// ``` pub fn build_task(&mut self) -> Builder<'_, R> { @@ -302,10 +304,11 @@ impl JoinSet { drop(list); let waker = entry_into_waker(&entry); let mut ctx = Context::from_waker(&waker); - // We have to dereference the JoinHandle from the UnsafeCell in order to poll it. - // The lifetime of the handle is valid here since it's wrapped by a ManuallyDrop. - // It will only get dropped when the task returns ready, and by the time, the entry - // is also dropped, and could never be popped from the done list once again. + // We have to dereference the JoinHandle from the UnsafeCell in order to poll + // it. The lifetime of the handle is valid here since it's wrapped + // by a ManuallyDrop. It will only get dropped when the task returns + // ready, and by the time, the entry is also dropped, and could + // never be popped from the done list once again. unsafe { match Pin::new(&mut **(entry.handle.get())).poll(&mut ctx) { Poll::Ready(res) => { @@ -353,7 +356,8 @@ impl<'a, R> Builder<'a, R> { } } - /// Sets the name for the tasks that are going to get spawned by this JoinSet Builder + /// Sets the name for the tasks that are going to get spawned by this + /// JoinSet Builder /// /// # Examples /// ``` @@ -361,7 +365,7 @@ impl<'a, R> Builder<'a, R> { /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); /// let mut builder = set.build_task().name("hello".into()); - /// builder.spawn(async move {1}); + /// builder.spawn(async move { 1 }); /// }); /// ``` pub fn name(self, name: String) -> Self { @@ -372,7 +376,8 @@ impl<'a, R> Builder<'a, R> { } } - /// Sets the priority for the tasks that are going to get spawned by this JoinSet Builder + /// Sets the priority for the tasks that are going to get spawned by this + /// JoinSet Builder /// /// # Examples /// ``` @@ -380,7 +385,7 @@ impl<'a, R> Builder<'a, R> { /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); /// let mut builder = set.build_task().priority(PriorityLevel::AbsHigh); - /// builder.spawn(async move {1}); + /// builder.spawn(async move { 1 }); /// }); /// ``` pub fn priority(self, pri_level: PriorityLevel) -> Self { @@ -391,8 +396,8 @@ impl<'a, R> Builder<'a, R> { } } - /// Spawns a task via a `JoinSet` onto a Ylong runtime. The task will start immediately - /// when `spawn` is called. + /// Spawns a task via a `JoinSet` onto a Ylong runtime. The task will start + /// immediately when `spawn` is called. /// /// # Panics /// This method panics when calling outside of Ylong runtime. @@ -402,7 +407,7 @@ impl<'a, R> Builder<'a, R> { /// ylong_runtime::block_on(async move { /// let mut set = JoinSet::new(); /// let mut builder = set.build_task(); - /// builder.spawn(async move {1}); + /// builder.spawn(async move { 1 }); /// }); /// ``` pub fn spawn(&mut self, task: T) -> CancelHandle diff --git a/ylong_runtime/src/task/mod.rs b/ylong_runtime/src/task/mod.rs index 6a73526..b321e91 100644 --- a/ylong_runtime/src/task/mod.rs +++ b/ylong_runtime/src/task/mod.rs @@ -21,17 +21,19 @@ pub(crate) mod state; mod task_handle; mod waker; pub(crate) mod yield_now; -use crate::executor::Schedule; -use crate::task::raw::{Header, RawTask, TaskMngInfo}; -pub use builder::TaskBuilder; -pub use join_handle::JoinHandle; -pub use join_set::JoinSet; use std::future::Future; use std::mem; use std::ptr::NonNull; use std::sync::Weak; + +pub use builder::TaskBuilder; +pub use join_handle::JoinHandle; +pub use join_set::JoinSet; pub use yield_now::yield_now; +use crate::executor::Schedule; +use crate::task::raw::{Header, RawTask, TaskMngInfo}; + pub(crate) enum VirtualTableType { Ylong, #[cfg(feature = "ffrt")] @@ -43,11 +45,11 @@ pub(crate) enum VirtualTableType { pub enum PriorityLevel { /// Highest priority, execute the task when get the chance. AbsHigh, - /// If there are low tasks and high tasks, a higher percentage of execution time will be - /// used towards high priority task. + /// If there are low tasks and high tasks, a higher percentage of execution + /// time will be used towards high priority task. High, - /// If there are low tasks and high tasks, a lower percentage of execution time will be - /// used towards low priority task. + /// If there are low tasks and high tasks, a lower percentage of execution + /// time will be used towards low priority task. Low, /// Only execute the task when there is no other task AbsLow, diff --git a/ylong_runtime/src/task/raw.rs b/ylong_runtime/src/task/raw.rs index 27e22d4..f1a1f21 100644 --- a/ylong_runtime/src/task/raw.rs +++ b/ylong_runtime/src/task/raw.rs @@ -11,12 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::executor::Schedule; -use crate::macros::cfg_ffrt; -use crate::task::state::TaskState; -use crate::task::task_handle::TaskHandle; -use crate::task::{TaskBuilder, VirtualTableType}; -use crate::ScheduleError; use std::cell::UnsafeCell; use std::future::Future; use std::mem; @@ -24,6 +18,14 @@ use std::pin::Pin; use std::ptr::NonNull; use std::sync::Weak; use std::task::{Context, Poll, Waker}; + +use crate::executor::Schedule; +use crate::macros::cfg_ffrt; +use crate::task::state::TaskState; +use crate::task::task_handle::TaskHandle; +use crate::task::{TaskBuilder, VirtualTableType}; +use crate::ScheduleError; + cfg_ffrt! { use ylong_ffrt::FfrtTaskHandle; use crate::ffrt::ffrt_task::FfrtTaskCtx; @@ -247,7 +249,8 @@ where } /// Manages task infos. -/// `repr(C)` is necessary because we cast a pointer of [`TaskMngInfo`] into a pointer of [`Header`]. +/// `repr(C)` is necessary because we cast a pointer of [`TaskMngInfo`] into a +/// pointer of [`Header`]. #[repr(C)] pub(crate) struct TaskMngInfo { /// a pointer to the heap-allocated task @@ -418,8 +421,8 @@ where S: Schedule, { /// Creates non-stackful task info. - // TODO: builder information currently is not used yet. Might use in the future (e.g. priority), - // so keep it now. + // TODO: builder information currently is not used yet. Might use in the future + // (e.g. priority), so keep it now. pub(crate) fn new( _builder: &TaskBuilder, scheduler: Weak, diff --git a/ylong_runtime/src/task/state.rs b/ylong_runtime/src/task/state.rs index 7399603..a01c9b8 100644 --- a/ylong_runtime/src/task/state.rs +++ b/ylong_runtime/src/task/state.rs @@ -11,12 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::error::ErrorKind; -use crate::macros::cfg_not_ffrt; -/// Task state, include SCHEDULED RUNNING COMPLETED CLOSED and so on and transform method +/// Task state, include SCHEDULED RUNNING COMPLETED CLOSED and so on and +/// transform method use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed}; +use crate::error::ErrorKind; +use crate::macros::cfg_not_ffrt; + /// Task is currently running const RUNNING: usize = 0b0001; /// Task is in the schedule list @@ -37,8 +39,8 @@ const RC_SHIFT: usize = RC_MASK.count_zeros() as usize; /// Reference count const REF_ONE: usize = 1 << RC_SHIFT; -/// Initial state contains two ref count, one is held by join_handle, another one is held by -/// task itself. +/// Initial state contains two ref count, one is held by join_handle, another +/// one is held by task itself. const INIT: usize = CARE_JOIN_HANDLE | SCHEDULING | (REF_ONE * 2); #[inline] @@ -75,8 +77,8 @@ pub(crate) fn is_running(cur: usize) -> bool { cur & RUNNING == RUNNING } -// A task need to satisfy these state requirements in order to get pushed back to -// the schedule list. +// A task need to satisfy these state requirements in order to get pushed back +// to the schedule list. pub(crate) fn need_enqueue(cur: usize) -> bool { (cur & SCHEDULING != SCHEDULING) && (cur & RUNNING != RUNNING) && (cur & FINISHED != FINISHED) } @@ -109,7 +111,8 @@ impl TaskState { /// Turns the task state into running. Contains CAS operations. /// - /// Fails when the task is already running, scheduling or is already finished. + /// Fails when the task is already running, scheduling or is already + /// finished. pub(crate) fn turning_to_running(&self) -> StateAction { let mut cur = self.get_current_state(); loop { @@ -279,7 +282,8 @@ impl TaskState { } } - /// Turns off the CARE_JOIN_HANDLE bit of the task state. Contains CAS operations. + /// Turns off the CARE_JOIN_HANDLE bit of the task state. Contains CAS + /// operations. /// /// Fails when the task is already finished. pub(crate) fn turn_to_un_join_handle(&self) -> Result { @@ -323,38 +327,30 @@ impl TaskState { } } -#[cfg(all(test))] +#[cfg(test)] mod test { + use std::sync::atomic::Ordering::{Acquire, Release}; + use crate::task::state::{ StateAction, TaskState, CANCELED, CARE_JOIN_HANDLE, FINISHED, INIT, JOIN_WAKER, REF_ONE, RUNNING, SCHEDULING, }; - use std::sync::atomic::Ordering::{Acquire, Release}; - /* - * @title TaskState::new() ut test - * @design No entry, no exception branch - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、Verify that the status of the initialized completed task is INIT - * @expect The modified task status attribute value should be INIT - * @auto true - */ + /// UT test cases for TaskState::new() + /// + /// # Brief + /// 1. Verify that the status of the initialized completed task is INIT #[test] fn ut_task_state_new() { let task_state = TaskState::new(); assert_eq!(task_state.0.load(Acquire), INIT); } - /* - * @title TaskState::dec_ref() ut test - * @design No entry, no exception branch - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、Verify that the status of the initialized completed task is INIT.wrapping_sub(REF_ONE) - * @expect The modified task status attribute value should be INIT.wrapping_sub(REF_ONE) - * @auto true - */ + /// UT test cases for TaskState::dec_ref() + /// + /// # Brief + /// 1. Verify that the status of the initialized completed task is + /// INIT.wrapping_sub(REF_ONE) value should be INIT.wrapping_sub(REF_ONE) #[test] fn ut_task_state_dec_ref() { let task_state = TaskState::new(); @@ -362,15 +358,11 @@ mod test { assert_eq!(task_state.0.load(Acquire), INIT.wrapping_sub(REF_ONE)) } - /* - * @title TaskState::inc_ref() ut test - * @design No entry, no exception branch - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、Verify that the status of the initialized completed task is INIT.wrapping_add(REF_ONE) - * @expect The modified task status attribute value should be INIT.wrapping_add(REF_ONE) - * @auto true - */ + /// UT test cases for TaskState::inc_ref() + /// + /// # Brief + /// 1. Verify that the status of the initialized completed task is + /// INIT.wrapping_add(REF_ONE) #[test] fn ut_task_state_inc_ref() { let task_state = TaskState::new(); @@ -378,34 +370,27 @@ mod test { assert_eq!(task_state.0.load(Acquire), INIT.wrapping_add(REF_ONE)); } - /* - * @title TaskState::get_current_state() ut test - * @design No entry, no exception branch - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、Verify that the status of the initialized completed task is INIT - * @expect The modified task status attribute value should be current task status value - * @auto true - */ + /// UT test cases for TaskState::get_current_state() + /// + /// # Brief + /// 1. Verify that the status of the initialized completed task is INIT #[test] fn ut_task_state_get_current_state() { let task_state = TaskState::new(); assert_eq!(task_state.get_current_state(), INIT); } - /* - * @title TaskState::turning_to_running() ut test - * @design No entry, exception branch exists - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、(cur & RUNNING == RUNNING) || (cur & FINISHED == FINISHED) == true, - * Represents the current state is already running state or has ended the state, the state does not information is not correct, directly return failure - * 2、(cur & RUNNING == RUNNING) || (cur & FINISHED == FINISHED) == false, - * cur & SCHEDULING != SCHEDULING == true, - * means the current state is not schedule state, and the status information is not correct, so it returns an error directly - * @expect Performing a state transition in an error state will return an error, but the correct situation should cause the state to be modified to RUNNING - * @auto true - */ + /// UT test cases for TaskState::turning_to_running() + /// + /// # Brief + /// 1. (cur & RUNNING == RUNNING) || (cur & FINISHED == FINISHED) == true, + /// represents the current state is already running state or has ended + /// the state, the state does not information is not correct, directly + /// return failure + /// 2. (cur & RUNNING == RUNNING) || (cur & FINISHED == FINISHED) == false, + /// cur & SCHEDULING != SCHEDULING == true, means the current state is + /// not schedule state, and the status information is not correct, so it + /// returns an error directly #[test] fn ut_task_state_turning_to_running() { let task_state = TaskState::new(); @@ -424,17 +409,15 @@ mod test { } } - /* - * @title TaskState::turning_to_finish() ut test - * @design No entry, exception branch exists - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、cur & FINISHED == FINISHED == true, Represents the current state is already the end state, the state does not information is not correct, directly return failure - * 2、cur & FINISHED == FINISHED == false, cur & RUNNING != RUNNING == true, - * means the current state is not running, and the status information is not correct, so the error is returned directly - * @expect Performing a state transition in an error state will return an error, but should cause the state to be modified to FINISHED in the correct case - * @auto true - */ + /// UT test cases for TaskState::turning_to_finish() + /// + /// # Brief + /// 1. cur & FINISHED == FINISHED == true, Represents the current state is + /// already the end state, the state does not information is not correct, + /// directly return failure + /// 2. cur & FINISHED == FINISHED == false, cur & RUNNING != RUNNING == + /// true, means the current state is not running, and the status + /// information is not correct, so the error is returned directly #[test] fn ut_task_state_turning_to_finish() { let task_state = TaskState::new(); @@ -448,31 +431,19 @@ mod test { assert!(task_state.turning_to_finish().is_err()); } - /* - * @title TaskState::turning_to_idle() ut test - * @design No entry, exception branch exists - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、cur & FINISHED == FINISHED == true, Represents the current state is already the end state, the state does not information is not correct, directly return failure - * 2、cur & CANCELLED == CANCELLED == false, cur & RUNNING != RUNNING == true, - * means that the current state is not running and the status information is not correct, directly panic - * 3、cur & CANCELLED == CANCELLED == false, - * cur & RUNNING != RUNNING == false, is_scheduling(next) == false - * @expect Performing a state transition in the wrong state will return an error, but the correct situation should cause the state to be modified to SCHEDULING - * @auto true - */ - - /// ut test for turning_to_idle + /// UT test cases for turning_to_idle /// /// # Brief /// 1. Create a TaskState, set it to Canceled & Running - /// 2. Call turning_to_idle, check if return value equals to StateAction::canceled + /// 2. Call turning_to_idle, check if return value equals to + /// StateAction::canceled /// 3. Create a TaskState, set it to init - /// 4. Call turning_to_idle, check if return value equals to StateAction::Failed + /// 4. Call turning_to_idle, check if return value equals to + /// StateAction::Failed /// 5. Create a TaskState, set it to Running and not scheduling - /// 6. Call turning_to_idle, check if return value equals to StateAction::Success + /// 6. Call turning_to_idle, check if return value equals to + /// StateAction::Success /// 7. Create a TaskState, set it to Running and scheduling - /// 8 #[test] fn ut_task_state_turning_to_idle() { let task_state = TaskState::new(); @@ -514,15 +485,10 @@ mod test { } } - /* - * @title TaskState::turn_to_scheduling() ut test - * @design No entry, no exception branch - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、Check if the state transition is SCHEDULING - * @expect The correct case should make the state modified to SCHEDULING - * @auto true - */ + /// UT test cases for TaskState::turn_to_scheduling() + /// + /// # Brief + /// 1. Check if the state transition is SCHEDULING #[test] fn ut_task_state_turning_to_scheduling() { let task_state = TaskState::new(); @@ -531,18 +497,16 @@ mod test { assert_eq!(task_state.turn_to_scheduling(), test_state); } - /* - * @title TaskState::turn_to_un_set_waker() ut test - * @design No entry, exception branch exists - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、!is_care_join_handle(cur) || !is_set_waker(cur) == true, means that the current state is neither focused on hooks nor set waker - * 2、!is_care_join_handle(cur) || !is_set_waker(cur) == false, cur & FINISHED == FINISHED == true, - * means the current status is FINISHED, directly return failure - * 3、!is_care_join_handle(cur) || !is_set_waker(cur) == false, cur & FINISHED == FINISHED == false - * @expect The correct case should make the status change to not set yet JOIN_WAKER - * @auto true - */ + /// UT test cases for TaskState::turn_to_un_set_waker() + /// + /// # Brief + /// 1. !is_care_join_handle(cur) || !is_set_waker(cur) == true, means that + /// the current state is neither focused on hooks nor set waker + /// 2. !is_care_join_handle(cur) || !is_set_waker(cur) == false, cur & + /// FINISHED == FINISHED == true, means the current status is FINISHED, + /// directly return failure + /// 3. !is_care_join_handle(cur) || !is_set_waker(cur) == false, cur & + /// FINISHED == FINISHED == false #[test] fn ut_task_state_turn_to_un_set_waker() { let task_state = TaskState::new(); @@ -569,17 +533,16 @@ mod test { assert!(task_state.turn_to_un_set_waker().is_ok()); } - /* - * @title TaskState::turn_to_set_waker() ut test - * @design No entry, exception branch exists - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、!is_care_join_handle(cur) || is_set_waker(cur) == true, means that the current state is neither concerned with hooks, has set waker - * 2、!is_care_join_handle(cur) || is_set_waker(cur) == false, cur & FINISHED == FINISHED == true, means the current status is FINISHED, directly return failure - * 3、!is_care_join_handle(cur) || is_set_waker(cur) == false, cur & FINISHED == FINISHED == false - * @expect The correct case should make the status change to JOIN_WAKER - * @auto true - */ + /// UT test cases for TaskState::turn_to_set_waker() + /// + /// # Brief + /// 1. !is_care_join_handle(cur) || is_set_waker(cur) == true, means that + /// the current state is neither concerned with hooks, has set waker + /// 2. !is_care_join_handle(cur) || is_set_waker(cur) == false, cur & + /// FINISHED == FINISHED == true, means the current status is FINISHED, + /// directly return failure + /// 3. !is_care_join_handle(cur) || is_set_waker(cur) == false, cur & + /// FINISHED == FINISHED == false #[test] fn ut_task_state_turn_to_set_waker() { let task_state = TaskState::new(); @@ -606,16 +569,12 @@ mod test { assert!(task_state.turn_to_set_waker().is_ok()); } - /* - * @title TaskState::turn_to_un_join_handle() ut test - * @design No entry, exception branch exists - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、cur & FINISHED == FINISHED == true, means the current state is FINISHED state, directly return failure - * 2、cur & FINISHED == FINISHED == false - * @expect The correct situation should make the status change to not set yet CARE_JOIN_HANDLE - * @auto true - */ + /// UT test cases for TaskState::turn_to_un_join_handle() + /// + /// # Brief + /// 1. cur & FINISHED == FINISHED == true, means the current state is + /// FINISHED state, directly return failure + /// 2. cur & FINISHED == FINISHED == false #[test] fn ut_task_state_turn_to_un_join_handle() { let task_state = TaskState::new(); @@ -631,15 +590,11 @@ mod test { assert!(task_state.turn_to_un_join_handle().is_ok()); } - /* - * @title TaskState::try_turning_to_un_join_handle() ut test - * @design No entry, no exception branch - * @precon After calling the TaskState::new() function, get its creation object - * @brief Describe test case execution - * 1、After calling this function, check if the status is modified to CARE_JOIN_HANDLE - * @expect The correct case should make the state modified to CARE_JOIN_HANDLE - * @auto true - */ + /// UT test cases for TaskState::try_turning_to_un_join_handle() + /// + /// # Brief + /// 1. After calling this function, check if the status is modified to + /// CARE_JOIN_HANDLE #[test] fn ut_task_state_turning_to_un_join_handle() { let task_state = TaskState::new(); diff --git a/ylong_runtime/src/task/task_handle.rs b/ylong_runtime/src/task/task_handle.rs index 941f7c2..f00566b 100644 --- a/ylong_runtime/src/task/task_handle.rs +++ b/ylong_runtime/src/task/task_handle.rs @@ -11,6 +11,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::future::Future; +use std::panic; +use std::ptr::NonNull; +use std::task::{Context, Poll, Waker}; + use crate::error::{ErrorKind, ScheduleError}; use crate::executor::Schedule; use crate::macros::{cfg_ffrt, cfg_not_ffrt}; @@ -18,10 +23,6 @@ use crate::task::raw::{Header, Inner, TaskMngInfo}; use crate::task::state::StateAction; use crate::task::waker::WakerRefHeader; use crate::task::{state, Task}; -use std::future::Future; -use std::panic; -use std::ptr::NonNull; -use std::task::{Context, Poll, Waker}; cfg_ffrt! { use std::ffi::c_void; use std::ptr::null_mut; @@ -250,8 +251,8 @@ where { pub(crate) unsafe fn shutdown(self) { self.header().state.set_cancel(); - // Check if the JoinHandle gets dropped already. If JoinHandle is still there, wakes - // the JoinHandle. + // Check if the JoinHandle gets dropped already. If JoinHandle is still there, + // wakes the JoinHandle. let cur = self.header().state.get_current_state(); if state::is_care_join_handle(cur) { let stage = self.inner().stage.get(); diff --git a/ylong_runtime/src/task/waker.rs b/ylong_runtime/src/task/waker.rs index 6b62f79..a025007 100644 --- a/ylong_runtime/src/task/waker.rs +++ b/ylong_runtime/src/task/waker.rs @@ -11,7 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::task::raw::Header; use std::future::Future; use std::marker::PhantomData; use std::mem::ManuallyDrop; @@ -19,6 +18,8 @@ use std::ops::Deref; use std::ptr::NonNull; use std::task::{RawWaker, RawWakerVTable, Waker}; +use crate::task::raw::Header; + unsafe fn get_header_by_raw_ptr(ptr: *const ()) -> NonNull

{ let header = ptr as *mut Header; let non_header = NonNull::new(header); @@ -65,7 +66,8 @@ where RawWaker::new(ptr, raw_waker_ref) } -/// Warps std::task::{RawWaker, RawWakerVTable, Waker} info, implements task notify and schedule +/// Warps std::task::{RawWaker, RawWakerVTable, Waker} info, implements task +/// notify and schedule pub(crate) struct WakerRefHeader<'a> { waker: ManuallyDrop, _field: PhantomData<&'a Header>, diff --git a/ylong_runtime/src/task/yield_now.rs b/ylong_runtime/src/task/yield_now.rs index dd89585..0eae577 100644 --- a/ylong_runtime/src/task/yield_now.rs +++ b/ylong_runtime/src/task/yield_now.rs @@ -12,21 +12,23 @@ // limitations under the License. //! Yields the current task and wakes it for a reschedule. -#[cfg(not(feature = "ffrt"))] -use crate::executor::worker; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; +#[cfg(not(feature = "ffrt"))] +use crate::executor::worker; + /// Yields the current task and wakes it for a reschedule. /// # Examples /// /// ``` /// use ylong_runtime::task::*; /// -/// let res = ylong_runtime::block_on( -/// ylong_runtime::spawn(async { yield_now().await; }) -/// ).unwrap(); +/// let res = ylong_runtime::block_on(ylong_runtime::spawn(async { +/// yield_now().await; +/// })) +/// .unwrap(); /// assert_eq!(res, ()); /// ``` pub async fn yield_now() { @@ -44,9 +46,10 @@ impl Future for YieldTask { self.0 = true; let ctx = worker::get_current_ctx(); - // Under worker context, we push the waker into the yielded list owned by the worker - // to avoid waking the waker immediately. This is because waking the waker in a worker - // context will put the task in the lifo slot, we don't want that. + // Under worker context, we push the waker into the yielded list owned by the + // worker to avoid waking the waker immediately. This is because + // waking the waker in a worker context will put the task in the + // lifo slot, we don't want that. if let Some(ctx) = ctx { match ctx { worker::WorkerContext::Multi(ctx) => { @@ -94,7 +97,7 @@ pub(crate) fn wake_yielded_tasks() { mod test { use crate::task::yield_now; - /// ut for yield. + /// UT test cases for yield. /// /// # Brief /// 1. Create two tasks that adds a number to 1000 diff --git a/ylong_runtime/src/time/driver.rs b/ylong_runtime/src/time/driver.rs index 03bc616..19dbe52 100644 --- a/ylong_runtime/src/time/driver.rs +++ b/ylong_runtime/src/time/driver.rs @@ -11,8 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::time::wheel::Wheel; -use crate::time::Clock; use std::convert::TryInto; use std::fmt::Error; use std::mem::MaybeUninit; @@ -21,6 +19,9 @@ use std::sync::{Mutex, Once}; use std::task::Waker; use std::time::Instant; +use crate::time::wheel::Wheel; +use crate::time::Clock; + // Timer Driver pub(crate) struct Driver { start_time: Instant, @@ -72,7 +73,8 @@ impl Driver { lock.set_last_elapsed(elapsed); // Unsafe access to clock_entry is only unsafe when Sleep Drop, - // but does not let `Sleep` go to `Ready` before access to clock_entry fetched by poll. + // but does not let `Sleep` go to `Ready` before access to clock_entry fetched + // by poll. let clock_handle = unsafe { clock_entry.as_mut() }; waker_list[waker_idx] = clock_handle.take_waker(); waker_idx += 1; diff --git a/ylong_runtime/src/time/mod.rs b/ylong_runtime/src/time/mod.rs index 620c20f..b9ce751 100644 --- a/ylong_runtime/src/time/mod.rs +++ b/ylong_runtime/src/time/mod.rs @@ -20,16 +20,17 @@ mod timeout; mod timer; mod wheel; +use std::ptr::{addr_of_mut, NonNull}; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::Relaxed; +use std::task::Waker; + pub(crate) use driver::Driver; pub use sleep::{sleep, sleep_until}; pub use timeout::timeout; pub use timer::{periodic_schedule, timer, timer_at, Timer}; use crate::util::link_list::{Link, Node}; -use std::ptr::{addr_of_mut, NonNull}; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::Relaxed; -use std::task::Waker; // Struct for timing and waking up corresponding tasks on the timing wheel. pub(crate) struct Clock { diff --git a/ylong_runtime/src/time/sleep.rs b/ylong_runtime/src/time/sleep.rs index 51031c3..ae1ab6e 100644 --- a/ylong_runtime/src/time/sleep.rs +++ b/ylong_runtime/src/time/sleep.rs @@ -11,8 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::time::Clock; -use crate::time::Driver; use std::convert::TryInto; use std::future::Future; use std::pin::Pin; @@ -20,6 +18,8 @@ use std::ptr::NonNull; use std::task::{Context, Poll}; use std::time::{Duration, Instant}; +use crate::time::{Clock, Driver}; + const TEN_YEARS: Duration = Duration::from_secs(86400 * 365 * 10); /// Waits until 'instant' has reached. @@ -51,6 +51,7 @@ pub fn sleep(duration: Duration) -> Sleep { /// /// ``` /// use std::time::Duration; +/// /// use ylong_runtime::time::sleep; /// /// async fn sleep_test() { @@ -138,24 +139,23 @@ impl Future for Sleep { impl Drop for Sleep { fn drop(&mut self) { // For some uses, for example, Timeout, - // `Sleep` enters the `Pending` state first and inserts the `TimerHandle` into the `DRIVER`, - // the future of timeout returns `Ready` in advance of the next polling, - // as a result, the `TimerHandle` pointer in the `DRIVER` is invalid. - // need to cancel the `TimerHandle` operation during `Sleep` drop. + // `Sleep` enters the `Pending` state first and inserts the `TimerHandle` into + // the `DRIVER`, the future of timeout returns `Ready` in advance of the + // next polling, as a result, the `TimerHandle` pointer in the `DRIVER` + // is invalid. need to cancel the `TimerHandle` operation during `Sleep` + // drop. self.cancel() } } #[cfg(test)] mod test { - use crate::time::sleep; - use crate::{block_on, spawn}; use std::time::Duration; - /// sleep ut test case. - /// - /// # Title - /// new_sleep + use crate::time::sleep; + use crate::{block_on, spawn}; + + /// UT test cases for new_sleep /// /// # Brief /// 1. Uses sleep to create a Sleep Struct. diff --git a/ylong_runtime/src/time/timeout.rs b/ylong_runtime/src/time/timeout.rs index 655e074..f0b177f 100644 --- a/ylong_runtime/src/time/timeout.rs +++ b/ylong_runtime/src/time/timeout.rs @@ -11,23 +11,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::time::error::TimerError; -use crate::time::sleep; -use crate::time::sleep::Sleep; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; +use crate::time::error::TimerError; +use crate::time::sleep; +use crate::time::sleep::Sleep; + /// Requires a future to be completed by a set deadline. /// /// # Examples /// /// ``` /// use std::time::Duration; +/// /// use ylong_runtime::time::timeout; /// -/// let handle = ylong_runtime::spawn(timeout(Duration::from_secs(1), async {1})); +/// let handle = ylong_runtime::spawn(timeout(Duration::from_secs(1), async { 1 })); /// let result = ylong_runtime::block_on(handle).unwrap().unwrap(); /// assert_eq!(result, 1); /// ``` @@ -77,14 +79,12 @@ where #[cfg(test)] mod test { - use crate::time::timeout; - use crate::{block_on, spawn}; use std::time::Duration; - /// timeout ut test case. - /// - /// # Title - /// ut_timeout_test + use crate::time::timeout; + use crate::{block_on, spawn}; + + /// UT test cases for timeout /// /// # Brief /// 1. Use timeout to create a Timeout Struct. @@ -118,10 +118,7 @@ mod test { assert!(!result); } - /// timeout ut test case. - /// - /// # Title - /// ut_timeout_test_002 + /// UT test cases for timeout /// /// # Brief /// 1. Use timeout to create a Timeout Struct. diff --git a/ylong_runtime/src/time/timer.rs b/ylong_runtime/src/time/timer.rs index 82e5fd2..fb3251b 100644 --- a/ylong_runtime/src/time/timer.rs +++ b/ylong_runtime/src/time/timer.rs @@ -11,29 +11,34 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::futures::poll_fn; -use crate::time::sleep::{sleep_until, Sleep}; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::{Duration, Instant}; +use crate::futures::poll_fn; +use crate::time::sleep::{sleep_until, Sleep}; + const TEN_YEARS: Duration = Duration::from_secs(86400 * 365 * 10); -/// Creates new [`Timer`] that yields with interval of `period`. The first task starts immediately. +/// Creates new [`Timer`] that yields with interval of `period`. The first task +/// starts immediately. /// /// # Examples /// /// ``` /// use std::time::Duration; +/// /// use ylong_runtime::time; /// /// async fn timer_test() { /// let mut timer = time::timer(Duration::from_millis(10)); -/// -/// timer.next_period().await; // ticks immediately -/// timer.next_period().await; // ticks after 10 ms -/// timer.next_period().await; // ticks after 10 ms +/// // ticks immediately +/// timer.next_period().await; +/// // ticks after 10 ms +/// timer.next_period().await; +/// // ticks after 10 ms +/// timer.next_period().await; /// } /// /// let handle = ylong_runtime::spawn(timer_test()); @@ -50,17 +55,20 @@ pub fn timer(period: Duration) -> Timer { /// /// ``` /// use std::time::{Duration, Instant}; +/// /// use ylong_runtime::time; /// /// async fn timer_at_test() { /// let mut timer = time::timer_at( /// Instant::now() + Duration::from_millis(10), -/// Duration::from_millis(30) +/// Duration::from_millis(30), /// ); -/// -/// timer.next_period().await; // ticks after 10 ms -/// timer.next_period().await; // ticks after 30 ms -/// timer.next_period().await; // ticks after 30 ms +/// // ticks after 10 ms +/// timer.next_period().await; +/// // ticks after 30 ms +/// timer.next_period().await; +/// // ticks after 30 ms +/// timer.next_period().await; /// } /// /// let handle = ylong_runtime::spawn(timer_at_test()); @@ -77,15 +85,16 @@ pub fn timer_at(start: Instant, period: Duration) -> Timer { /// # Examples /// /// ``` -/// use std::time::{Duration, Instant}; -/// use ylong_runtime::{spawn, block_on, time}; /// use std::sync::{Arc, Mutex}; +/// use std::time::{Duration, Instant}; +/// +/// use ylong_runtime::{block_on, spawn, time}; /// /// let x = Arc::new(Mutex::new(0)); /// let xc = x.clone(); /// /// let closure = move || { -/// let mut a = xc.lock().unwrap(); +/// let mut a = xc.lock().unwrap(); /// *a = *a + 1; /// }; /// @@ -159,15 +168,13 @@ impl Timer { #[cfg(test)] mod test { - use crate::time::sleep; - use crate::{block_on, spawn, time}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; - /// time ut test case. - /// - /// # Title - /// new_timer + use crate::time::sleep; + use crate::{block_on, spawn, time}; + + /// UT test cases for new_timer /// /// # Brief /// 1. Uses time to create a Timer Struct. @@ -183,10 +190,7 @@ mod test { }); } - /// time ut test case. - /// - /// # Title - /// new_timer_base + /// UT test cases for new_timer_base /// /// # Brief /// 1. Uses timer_at to create a Timer Struct. @@ -210,10 +214,7 @@ mod test { block_on(handle).unwrap(); } - /// time ut test case. - /// - /// # Title - /// new_timer_timeout + /// UT test cases for new_timer_timeout /// /// # Brief /// 1. Uses time to create a Timer Struct. @@ -239,10 +240,7 @@ mod test { block_on(handle).unwrap(); } - /// time ut test case. - /// - /// # Title - /// new_timer_schedule + /// UT test cases for new_timer_schedule /// /// # Brief /// 1. Creates a closure. diff --git a/ylong_runtime/src/time/wheel.rs b/ylong_runtime/src/time/wheel.rs index 2657d9e..727480f 100644 --- a/ylong_runtime/src/time/wheel.rs +++ b/ylong_runtime/src/time/wheel.rs @@ -11,13 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::time::Clock; -use crate::util::link_list::LinkedList; use std::fmt::Error; use std::mem; use std::mem::MaybeUninit; use std::ptr::NonNull; +use crate::time::Clock; +use crate::util::link_list::LinkedList; + // In a slots, the number of slot. const SLOTS_NUM: usize = 64; @@ -110,7 +111,8 @@ impl Wheel { significant / 6 } - // Insert the corresponding TimerHandle into the specified position in the timing wheel. + // Insert the corresponding TimerHandle into the specified position in the + // timing wheel. pub(crate) fn insert(&mut self, mut clock_entry: NonNull) -> Result { let expiration = unsafe { clock_entry.as_ref().expiration() }; @@ -136,7 +138,8 @@ impl Wheel { let level = unsafe { clock_entry.as_ref().level() }; self.levels[level].cancel(clock_entry); - // Caller has unique access to the linked list and the node is not in any other linked list. + // Caller has unique access to the linked list and the node is not in any other + // linked list. unsafe { LinkedList::remove(clock_entry); } @@ -251,7 +254,8 @@ impl Level { let slot = ((duration >> (self.level * LEVELS_NUM)) % SLOTS_NUM as u64) as usize; - // Caller has unique access to the linked list and the node is not in any other linked list. + // Caller has unique access to the linked list and the node is not in any other + // linked list. unsafe { LinkedList::remove(clock_entry); } @@ -303,7 +307,8 @@ fn slot_range(level: usize) -> u64 { SLOTS_NUM.pow(level as u32) as u64 } -// All the slots before this level(including this level) add up to approximately. +// All the slots before this level(including this level) add up to +// approximately. fn level_range(level: usize) -> u64 { SLOTS_NUM as u64 * slot_range(level) } @@ -320,10 +325,7 @@ mod test { use std::time::Duration; ); - /// Wheel::new ut test case. - /// - /// # Title - /// ut_wheel_new_test + /// UT test cases for Wheel::new /// /// # Brief /// 1. Use Wheel::new to create a Wheel Struct. @@ -336,15 +338,14 @@ mod test { assert_eq!(wheel.levels.len(), LEVELS_NUM); } - /// Sleep Drop. - /// - /// # Title - /// ut_sleep_drop + /// UT test cases for Sleep drop. /// /// # Brief /// 1. Use timeout to create a Timeout Struct. - /// 2. Enable the Sleep Struct corresponding to the Timeout Struct to enter the Pending state. - /// 3. Verify the change of the internal TimerHandle during Sleep Struct drop. + /// 2. Enable the Sleep Struct corresponding to the Timeout Struct to enter + /// the Pending state. + /// 3. Verify the change of the internal TimerHandle during Sleep Struct + /// drop. #[test] #[cfg(feature = "net")] fn ut_sleep_drop() { diff --git a/ylong_runtime/src/util/bit.rs b/ylong_runtime/src/util/bit.rs index 7d41836..6e07489 100644 --- a/ylong_runtime/src/util/bit.rs +++ b/ylong_runtime/src/util/bit.rs @@ -15,7 +15,8 @@ /// Mask, representing a segment of consecutive binary bits, e.g. /// -/// When using the mask with a binary number for **and** operations, the value at the mask position of the binary number can be obtained. +/// When using the mask with a binary number for **and** operations, the value +/// at the mask position of the binary number can be obtained. /// /// For example: 0000_1111(mask) & 1010_1010(target number) = 0000_1010 /// @@ -25,7 +26,6 @@ /// /// // On a 64-bit machine, you can get the mask 0xf /// let mask = Mask::new(4, 0); -/// /// ``` #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Mask { @@ -34,7 +34,8 @@ pub struct Mask { } impl Mask { - /// Creates a mask. Generates a mask based on the length of consecutive binary bits + an offset. + /// Creates a mask. Generates a mask based on the length of consecutive + /// binary bits + an offset. /// /// # Parameter /// width: Length of consecutive binary bits @@ -56,7 +57,8 @@ impl Mask { /// let mask = Mask::new(width, shift); /// // Get mask as 0xf0 /// ``` - /// When width >= machine word length, a mask of all 1's is returned regardless of the shift. + /// When width >= machine word length, a mask of all 1's is returned + /// regardless of the shift. /// ```rust /// use ylong_runtime::util::bit::Mask; /// @@ -74,15 +76,16 @@ impl Mask { /// let mask = Mask::new(width, shift); /// // On a 64-bit machine, the mask is 0x0 /// ``` - /// When width < machine word length and width + shift > machine word length, it will ensure that width remains unchanged and shift becomes machine word length - width. - /// ```rust + /// When width < machine word length and width + shift > machine word + /// length, it will ensure that width remains unchanged and shift becomes + /// machine word length - width. ```rust /// use ylong_runtime::util::bit::Mask; /// /// let width = 32; /// let shift = 64; /// let mask = Mask::new(width, shift); - /// // On a 64-bit machine, the mask is 0xffff_ffff_0000_0000, the offset becomes 32. - /// ``` + /// // On a 64-bit machine, the mask is 0xffff_ffff_0000_0000, the offset + /// becomes 32. ``` pub const fn new(width: u32, shift: u32) -> Self { const USIZE_LEN: u32 = 0usize.wrapping_sub(1).count_ones(); if width >= USIZE_LEN { @@ -104,12 +107,15 @@ impl Mask { } } -/// Bit is used for some binary processing. A usize type can be converted to a Bit type to get a part of it by concatenating it with a Mask type. +/// Bit is used for some binary processing. A usize type can be converted to a +/// Bit type to get a part of it by concatenating it with a Mask type. /// -/// Uses the get_by_mask method to get the value of the specified bit from the Bit. Uses set_by_mask to add the value of the specified bit to the bit. +/// Uses the get_by_mask method to get the value of the specified bit from the +/// Bit. Uses set_by_mask to add the value of the specified bit to the bit. /// -/// For example, divides a usize type into different meanings according to each bit, uses Mask to get the mask in the corresponding position, -/// and then uses Bit set_by_mask\get_by_mask to modify the specified bit. +/// For example, divides a usize type into different meanings according to each +/// bit, uses Mask to get the mask in the corresponding position, and then uses +/// Bit set_by_mask\get_by_mask to modify the specified bit. /// /// # Example /// ```not run @@ -171,12 +177,13 @@ impl Bit { /// Overwrites a usize data to the specified mask position of the bit. /// - /// If the binary length of the given usize data is greater than the binary bit length of the mask, it will be truncated. + /// If the binary length of the given usize data is greater than the binary + /// bit length of the mask, it will be truncated. /// /// # Example /// When Mask binary length >= val binary length (excluding leading zeros) /// ```rust - /// use ylong_runtime::util::bit::{Mask, Bit}; + /// use ylong_runtime::util::bit::{Bit, Mask}; /// /// // mask's length 16 /// const MASK: Mask = Mask::new(16, 0); @@ -186,11 +193,11 @@ impl Bit { /// let val = 0x1234usize; /// bits.set_by_mask(MASK, val); /// assert_eq!(bits, Bit::from_usize(0x1234)); - /// /// ``` - /// When Mask binary length < val binary length (excluding leading zeros), val is truncated and only the low bit is retained. + /// When Mask binary length < val binary length (excluding leading zeros), + /// val is truncated and only the low bit is retained. /// ```rust - /// use ylong_runtime::util::bit::{Mask, Bit}; + /// use ylong_runtime::util::bit::{Bit, Mask}; /// /// // mask's length 16 /// const MASK: Mask = Mask::new(16, 0); @@ -243,7 +250,7 @@ impl Bit { /// /// # Example /// ```rust - /// use ylong_runtime::util::bit::{Mask, Bit}; + /// use ylong_runtime::util::bit::{Bit, Mask}; /// /// let base = 0xffffusize; /// let mut bits = Bit::from_usize(base); @@ -255,23 +262,13 @@ impl Bit { } } -/* -* @title mask new function ut test -* @design Conditions of use override -* @precon None -* @brief 1. Get the current machine word length -* 2. Call the new function according to the machine word length, pass in the parameters, and create the Mask -* 3. Check return value -* @expect 1. On a 64-bit machine, width >= 64, get width = 64, shift = 0 -* 2. On a 64-bit machine, width == 0, get width = 0, shift = 0 -* 3. On a 64-bit machine, 0 < width < 64, width + shift >= 64, get width = input width, shift = 64 - input width -* 4. On a 64-bit machine, 0 < width < 64, width + shift < 64, call width = input width, shift = input shift -* 5. On a 32-bit machine, width >= 32, call new, get width = 32, shift = 0 -* 6. On a 32-bit machine, width == 0, call new, get width = 0, shift = 0 -* 7. On a 32-bit machine, 0 < width < 32, width + shift >= 32, get width = input width, shift = 32 - input width -* 8. On a 32-bit machine, 0 < width < 32, width + shift < 32, get width = input width, shift = input width -* @auto Yes -*/ +/// UT test cases for mask new function +/// +/// # Brief +/// 1. Get the current machine word length. +/// 2. Call the new function according to the machine word length, pass in the +/// parameters, and create the Mask. +/// 3. Check return value. #[test] fn ut_mask_new() { const USIZE_LEN: u32 = 0usize.wrapping_sub(1).count_ones(); @@ -658,14 +655,10 @@ fn ut_mask_new() { } } -/* -* @title bit from_usize function ut test -* @design Conditions of use override -* @precon None -* @brief None -* @expect 1. Pass in any usize, call from_usize, and check the return value -* @auto Yes -*/ +/// UT test cases for bit from_usize function +/// +/// # Brief +/// 1. Pass in any usize, call from_usize, and check the return value. #[test] fn ut_bit_from_usize() { const USIZE_MAX: usize = 0usize.wrapping_sub(1); @@ -676,16 +669,12 @@ fn ut_bit_from_usize() { assert_eq!(Bit::from_usize(USIZE_MAX), Bit(USIZE_MAX)); } -/* -* @title bit as_usize function ut test -* @design Conditions of use override -* @precon None -* @brief 1. Creating a Bit Instance -* 2. Call as_usize -* 3. Check return value -* @expect 1. Get the bit internal usize -* @auto Yes -*/ +/// UT test cases for bit as_usize function +/// +/// # Brief +/// 1. Creating a Bit Instance. +/// 2. Call as_usize. +/// 3. Check return value. #[test] fn ut_bit_as_usize() { const USIZE_MAX: usize = 0usize.wrapping_sub(1); @@ -696,16 +685,12 @@ fn ut_bit_as_usize() { assert_eq!(Bit::from_usize(USIZE_MAX).as_usize(), USIZE_MAX); } -/* -* @title bit set function ut test -* @design Conditions of use override -* @precon None -* @brief 1. Creating a Bit Instance -* 2. Call the set function and pass in a new usize -* 3. Check return value -* @expect 1. Bit Internal value becomes the new usize passed in -* @auto Yes -*/ +/// UT test cases for bit set function +/// +/// # Brief +/// 1. Creating a Bit Instance. +/// 2. Call the set function and pass in a new usize. +/// 3. Check return value. #[test] fn ut_bit_set() { const USIZE_MAX: usize = 0usize.wrapping_sub(1); @@ -724,16 +709,12 @@ fn ut_bit_set() { assert_eq!(b.as_usize(), 0xf0f0); } -/* -* @title bit clear function ut test -* @design Conditions of use override -* @precon None -* @brief 1. Creating a Bit Instance -* 2. Call clear() -* 3. Calibrate the instance -* @expect 1. The internal value of this Bit instance is cleared to zero -* @auto Yes -*/ +/// UT test cases for bit clear function +/// +/// # Brief +/// 1. Creating a Bit Instance. +/// 2. Call clear(). +/// 3. Calibrate the instance. #[test] fn ut_bit_clear() { const USIZE_MAX: usize = 0usize.wrapping_sub(1); @@ -752,17 +733,12 @@ fn ut_bit_clear() { assert_eq!(b.as_usize(), 0); } -/* -* @title bit set_by_mask function ut test -* @design Conditions of use override -* @precon None -* @brief 1. Create a Bit instance, create a Mask instance -* 2. Call set_by_mask() -* 3. Verify the Bit instance -* @expect 1. Mask length < val valid value length, the truncated part of the valid value is overwritten into the Bit instance -* 2. Mask length >= val valid value length, the complete part of the valid value is overwritten into the Bit instance -* @auto Yes -*/ +/// UT test cases for bit set_by_mask function +/// +/// # Brief +/// 1. Create a Bit instance, create a Mask instance. +/// 2. Call set_by_mask(). +/// 3. Verify the Bit instance. #[test] fn ut_bit_set_by_mask() { const USIZE_LEN: u32 = 0usize.wrapping_sub(1).count_ones(); @@ -918,16 +894,12 @@ fn ut_bit_set_by_mask() { } } -/* -* @title bit get_by_mask function ut test -* @design Conditions of use override -* @precon None -* @brief 1. Create a Bit instance, create a Mask instance -* 2. Call get_by_mask() -* 3. Check return value -* @expect 1. Gets the value of the Bit instance on the corresponding Mask bit -* @auto Yes -*/ +/// UT test cases for bit get_by_mask function +/// +/// # Brief +/// 1. Create a Bit instance, create a Mask instance. +/// 2. Call get_by_mask(). +/// 3. Check return value. #[test] fn ut_bit_get_by_mask() { const USIZE_LEN: u32 = 0usize.wrapping_sub(1).count_ones(); diff --git a/ylong_runtime/src/util/core_affinity/linux.rs b/ylong_runtime/src/util/core_affinity/linux.rs index e63d24d..75a903d 100644 --- a/ylong_runtime/src/util/core_affinity/linux.rs +++ b/ylong_runtime/src/util/core_affinity/linux.rs @@ -13,12 +13,13 @@ //! Wraps Linux core-affinity syscalls. -use crate::util::num_cpus::get_cpu_num; -use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET}; -use std::io::Error; -use std::io::Result; +use std::io::{Error, Result}; use std::mem::{size_of, zeroed}; +use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET}; + +use crate::util::num_cpus::get_cpu_num; + /// Sets the tied core cpu of the current thread. /// /// sched_setaffinity function under linux @@ -50,7 +51,7 @@ pub fn set_current_affinity(cpu: usize) -> Result<()> { /// ```rust /// use ylong_runtime::util::core_affinity; /// -/// let cpus:Vec = core_affinity::get_current_affinity(); +/// let cpus: Vec = core_affinity::get_current_affinity(); /// assert!(cpus.len() > 0); /// ``` /// # Example 2 @@ -60,7 +61,7 @@ pub fn set_current_affinity(cpu: usize) -> Result<()> { /// /// let ret = core_affinity::set_current_affinity(0).is_ok(); /// assert!(ret); -/// let cpus:Vec = core_affinity::get_current_affinity(); +/// let cpus: Vec = core_affinity::get_current_affinity(); /// assert_eq!(cpus.len(), 1); /// ``` pub fn get_current_affinity() -> Vec { @@ -78,7 +79,8 @@ pub fn get_current_affinity() -> Vec { } } -/// Gets the cores bound to the specified thread, or return all available cpu's if no cores are bound +/// Gets the cores bound to the specified thread, or return all available cpu's +/// if no cores are bound /// /// sched_setaffinity function under linux pub fn get_other_thread_affinity(pid: i32) -> Vec { diff --git a/ylong_runtime/src/util/core_affinity/windows.rs b/ylong_runtime/src/util/core_affinity/windows.rs index 35f2882..6a7c5dd 100644 --- a/ylong_runtime/src/util/core_affinity/windows.rs +++ b/ylong_runtime/src/util/core_affinity/windows.rs @@ -13,8 +13,7 @@ //! Wraps Windows core-affinity syscalls. -use std::io::Error; -use std::io::Result; +use std::io::{Error, Result}; use std::os::windows::raw::HANDLE; extern "system" { @@ -37,10 +36,11 @@ extern "system" { /// let ret = core_affinity::set_current_affinity(0).is_ok(); /// ``` pub fn set_current_affinity(cpu: usize) -> Result<()> { - // In Windows, dwThreadAffinityMask is start from 1, so we have to +1 to align with linux. + // In Windows, dwThreadAffinityMask is start from 1, so we have to +1 to align + // with linux. let cpu = cpu + 1; - // If the function succeeds, the return value is the thread's previous affinity mask. - // If the function fails, the return value is 0. + // If the function succeeds, the return value is the thread's previous affinity + // mask. If the function fails, the return value is 0. let res = unsafe { let handle = GetCurrentThread(); SetThreadAffinityMask(handle, cpu) as i32 @@ -50,15 +50,4 @@ pub fn set_current_affinity(cpu: usize) -> Result<()> { 0 => Err(Error::last_os_error()), _ => Ok(()), } -} - -// TODO: -// Gets the cores tied to the current thread, or return all available cpu's if no cores are tied -// pub fn get_current_affinity() -> Vec { -// return vec![0 as usize]; -// } -// TODO: -// Gets the cores tied to other threads, or return all available cpu's if no cores have been tied -// pub fn get_other_thread_affinity(_pid: i32) -> Vec { -// return vec![0 as usize]; -// } +} \ No newline at end of file diff --git a/ylong_runtime/src/util/link_list.rs b/ylong_runtime/src/util/link_list.rs index d7e0094..5e2db43 100644 --- a/ylong_runtime/src/util/link_list.rs +++ b/ylong_runtime/src/util/link_list.rs @@ -11,11 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This linked list does not have ownership of nodes, and it treats the structure passed -//! in by the user as a node for storage, so the `clear` operation does not release memory, -//! and the `remove` operation needs to ensure that the node is in any linked list held by -//! a caller to ensure the memory validity of pointers within the node. Users need to manage -//! the memory of the instances associated with each node themselves. +//! This linked list does not have ownership of nodes, and it treats the +//! structure passed in by the user as a node for storage, so the `clear` +//! operation does not release memory, and the `remove` operation needs to +//! ensure that the node is in any linked list held by a caller to ensure the +//! memory validity of pointers within the node. Users need to manage the memory +//! of the instances associated with each node themselves. use std::ptr::NonNull; @@ -68,7 +69,8 @@ unsafe impl Sync for LinkedList {} /// /// # Safety /// -/// The implementation must ensure that the inserted data does not move in memory. +/// The implementation must ensure that the inserted data does not move in +/// memory. pub(crate) unsafe trait Link { unsafe fn node(ptr: NonNull) -> NonNull> where @@ -122,8 +124,9 @@ impl LinkedList { /// /// # Safety /// - /// This method can be safely used when the node is in a linked list that the caller has - /// unique access to or the node is not in any linked list. + /// This method can be safely used when the node is in a linked list that + /// the caller has unique access to or the node is not in any linked + /// list. #[allow(dead_code)] pub(crate) unsafe fn remove(node: NonNull) -> Option> { Node::remove_node(node) @@ -158,9 +161,10 @@ impl Drop for LinkedList { #[cfg(test)] mod tests { - use crate::util::link_list::{Link, LinkedList, Node}; use std::ptr::{addr_of_mut, NonNull}; + use crate::util::link_list::{Link, LinkedList, Node}; + #[derive(Default)] struct Entry { val: usize, @@ -195,15 +199,13 @@ mod tests { } } - /// UT test for `is_empty()` and `clear()`. - /// - /// # Title - /// ut_link_list_is_empty_and_clear + /// UT test cases for `is_empty()` and `clear()`. /// /// # Brief - /// 1.Create a linked list. - /// 2.Check if the list is empty before and after pushing nodes into the list. - /// 3.Check if the list is empty before and after clear the list. + /// 1. Create a linked list. + /// 2. Check if the list is empty before and after pushing nodes into the + /// list. + /// 3. Check if the list is empty before and after clear the list. #[test] fn ut_link_list_is_empty_and_clear() { let mut list = LinkedList::::new(); @@ -222,15 +224,12 @@ mod tests { assert!(list.is_empty()); } - /// UT test for `push_front()` and `pop_back()`. - /// - /// # Title - /// ut_link_list_push_and_pop + /// UT test cases for `push_front()` and `pop_back()`. /// /// # Brief - /// 1.Create a linked list. - /// 2.Push nodes into the list. - /// 3.Pop nodes from the list and check the value. + /// 1. Create a linked list. + /// 2. Push nodes into the list. + /// 3. Pop nodes from the list and check the value. #[test] fn ut_link_list_push_and_pop() { let mut list = LinkedList::::new(); @@ -252,17 +251,14 @@ mod tests { assert!(list.is_empty()); } - /// UT test for `push_front()` and `remove()`. - /// - /// # Title - /// ut_link_list_remove + /// UT test cases for `push_front()` and `remove()`. /// /// # Brief - /// 1.Create a linked list. - /// 2.Push nodes into the list. - /// 3.Remove the first node from the list and check the list. - /// 4.Remove the second node from the list and check the list. - /// 5.Remove the third node from the list and check the list. + /// 1. Create a linked list. + /// 2. Push nodes into the list. + /// 3. Remove the first node from the list and check the list. + /// 4. Remove the second node from the list and check the list. + /// 5. Remove the third node from the list and check the list. #[test] fn ut_link_list_remove() { let mut list = LinkedList::::new(); diff --git a/ylong_runtime/src/util/num_cpus/linux.rs b/ylong_runtime/src/util/num_cpus/linux.rs index ca2cfb9..dd61065 100644 --- a/ylong_runtime/src/util/num_cpus/linux.rs +++ b/ylong_runtime/src/util/num_cpus/linux.rs @@ -13,9 +13,10 @@ //! num_cpu linux wrapping -use libc::{sysconf, _SC_NPROCESSORS_CONF, _SC_NPROCESSORS_ONLN}; use std::os::raw::c_long; +use libc::{sysconf, _SC_NPROCESSORS_CONF, _SC_NPROCESSORS_ONLN}; + /// Gets the number of CPU cores via linux syscall /// /// # Example 2 @@ -25,12 +26,13 @@ use std::os::raw::c_long; /// /// #[cfg(target_os = "linux")] /// let cpus = num_cpus::linux::get_cpu_num_online(); -///``` +/// ``` pub fn get_cpu_num_online() -> c_long { unsafe { sysconf(_SC_NPROCESSORS_ONLN) } } -/// Gets the number of CPU cores via linux syscall, including disabled cpu states +/// Gets the number of CPU cores via linux syscall, including disabled cpu +/// states /// /// # Example 2 /// @@ -39,7 +41,7 @@ pub fn get_cpu_num_online() -> c_long { /// /// #[cfg(target_os = "linux")] /// let cpus = num_cpus::linux::get_cpu_num_configured(); -///``` +/// ``` pub fn get_cpu_num_configured() -> c_long { unsafe { sysconf(_SC_NPROCESSORS_CONF) } } diff --git a/ylong_runtime/src/util/num_cpus/mod.rs b/ylong_runtime/src/util/num_cpus/mod.rs index 7fe5297..fa82caa 100644 --- a/ylong_runtime/src/util/num_cpus/mod.rs +++ b/ylong_runtime/src/util/num_cpus/mod.rs @@ -23,16 +23,16 @@ pub mod linux; #[cfg(target_os = "windows")] pub mod windows; +#[cfg(target_os = "linux")] +use crate::util::num_cpus::linux::get_cpu_num_online; #[cfg(target_os = "windows")] use crate::util::num_cpus::windows::get_cpu_num_online; -#[cfg(target_os = "linux")] -use crate::util::num_cpus::linux::get_cpu_num_online; - -/// The get_cpu_num function is the external interface, which will automatically call the underlying functions for different operating systems. -/// Linux, using sysconf() function, which gets the number of cpu cores in the available state by default. -/// Windows, using GetSystemInfo() function, which gets the number of cpu cores in the available state by default. -/// # Example +/// The get_cpu_num function is the external interface, which will automatically +/// call the underlying functions for different operating systems. Linux, using +/// sysconf() function, which gets the number of cpu cores in the available +/// state by default. Windows, using GetSystemInfo() function, which gets the +/// number of cpu cores in the available state by default. # Example /// /// ```rust /// use ylong_runtime::util::num_cpus; diff --git a/ylong_runtime/src/util/num_cpus/windows.rs b/ylong_runtime/src/util/num_cpus/windows.rs index ea40af8..8d8c045 100644 --- a/ylong_runtime/src/util/num_cpus/windows.rs +++ b/ylong_runtime/src/util/num_cpus/windows.rs @@ -12,7 +12,6 @@ // limitations under the License. //! num_cpu windows wrapping -//! use std::os::raw::c_long; // Get the current number of available cpu cores on Windows platform diff --git a/ylong_runtime/src/util/slab.rs b/ylong_runtime/src/util/slab.rs index dc980c9..e87bc4b 100644 --- a/ylong_runtime/src/util/slab.rs +++ b/ylong_runtime/src/util/slab.rs @@ -30,7 +30,8 @@ //! //! When a piece of data in `slab` is no longer in use and is freed, //! the space where the current data store is located should be reused, -//! and this operation will be used in conjunction with the allocation operation. +//! and this operation will be used in conjunction with the allocation +//! operation. //! //! ### Allocate //! @@ -63,18 +64,20 @@ const NUM_PAGES: usize = 19; const PAGE_INITIAL_SIZE: usize = 32; const PAGE_INDEX_SHIFT: u32 = PAGE_INITIAL_SIZE.trailing_zeros() + 1; -/// trait bounds mechanism, so that the binder must implement the `Entry` and `Default` trait methods +/// trait bounds mechanism, so that the binder must implement the `Entry` and +/// `Default` trait methods pub trait Entry: Default { /// Resets the entry. fn reset(&self); } -// ################################################################################################# + /// Reference to data stored in `slab` pub struct Ref { value: *const Value, } -/// Release operation of data stored in `slab` for reuse in the next allocated space +/// Release operation of data stored in `slab` for reuse in the next allocated +/// space impl Drop for Ref { fn drop(&mut self) { unsafe { @@ -94,7 +97,6 @@ impl Deref for Ref { unsafe impl Sync for Ref {} unsafe impl Send for Ref {} -// ################################################################################################# /// The Address of the stored data. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -122,11 +124,11 @@ impl Address { Address(src) } } -// ################################################################################################# /// Amortized allocation for homogeneous data types. pub struct Slab { - /// Essentially a two-dimensional array, the constituent units in the container + /// Essentially a two-dimensional array, the constituent units in the + /// container pages: [Arc>; NUM_PAGES], } @@ -143,9 +145,11 @@ impl Slab { pages: Default::default(), }; - // The minimum number of `slots` that can fit in a `page` at initialization, where the default value is 32 + // The minimum number of `slots` that can fit in a `page` at initialization, + // where the default value is 32 let mut len = PAGE_INITIAL_SIZE; - // The sum of the lengths of all `pages` before this `page`, i.e. the sum of `len` + // The sum of the lengths of all `pages` before this `page`, i.e. the sum of + // `len` let mut prev_len: usize = 0; for page in &mut slab.pages { @@ -170,8 +174,11 @@ impl Slab { /// Space allocation for containers /// /// # Safety - /// 1. The essence of space allocation to the container is actually to allocate each page of the container for the operation - /// 2. Before allocating each page of the container, we will try to get lock permission to prevent multiple threads from having permission to modify the state + /// 1. The essence of space allocation to the container is actually to + /// allocate each page of the container for the operation + /// 2. Before allocating each page of the container, we will try to get lock + /// permission to prevent multiple threads from having permission to + /// modify the state /// /// Using pointers pub unsafe fn allocate(&self) -> Option<(Address, Ref)> { @@ -226,18 +233,28 @@ impl Slab { } } - /// Used to clean up the resources in the `Slab` container after a specific number of loops, which is one of the most important uses of this container + /// Used to clean up the resources in the `Slab` container after a specific + /// number of loops, which is one of the most important uses of this + /// container /// /// # Safety - /// Releasing resources here does not release resources that are being used or have not yet been allocated - /// 1. The release of each page will initially determine if the resources on the current page are being used or if the current page has not been allocated - /// 2. Next, it will determine whether the `slots` of the current page are owned by other threads to prevent its resources from changing to the used state - /// 3. Finally, the checks are performed again, with the same checks as in the first step, to prevent state changes and ensure that no errors or invalid releases are made + /// Releasing resources here does not release resources that are being used + /// or have not yet been allocated + /// 1. The release of each page will initially determine if the resources on + /// the current page are being used or if the current page has not been + /// allocated + /// 2. Next, it will determine whether the `slots` of the current page are + /// owned by other threads to prevent its resources from changing to the + /// used state + /// 3. Finally, the checks are performed again, with the same checks as in + /// the first step, to prevent state changes and ensure that no errors or + /// invalid releases are made /// /// Using atomic variables pub unsafe fn compact(&mut self) { for (_, page) in (self.pages[1..]).iter().enumerate() { - // The `slots` of the current `page` are being used, or the current `page` is not allocated and not cleaned up. + // The `slots` of the current `page` are being used, or the current `page` is + // not allocated and not cleaned up. if page.used.load(Relaxed) != 0 || !page.allocated.load(Relaxed) { continue; } @@ -248,7 +265,8 @@ impl Slab { _ => continue, }; - // Check again, if the `slots` of the current `page` are being used, or if the current `page` is not allocated, do not clean up. + // Check again, if the `slots` of the current `page` are being used, or if the + // current `page` is not allocated, do not clean up. if slots.used > 0 || slots.slots.capacity() == 0 { continue; } @@ -263,7 +281,7 @@ impl Slab { } } } -// ################################################################################################# + struct Page { // Number of `slots` currently being used pub used: AtomicUsize, @@ -271,7 +289,8 @@ struct Page { pub allocated: AtomicBool, // The number of `slots` that `page` can hold pub len: usize, - // The sum of the lengths of all `pages` before the `page`, i.e. the sum of the number of `slots` + // The sum of the lengths of all `pages` before the `page`, i.e. the sum of the number of + // `slots` pub prev_len: usize, // `Slots` pub slots: Mutex>, @@ -281,7 +300,8 @@ unsafe impl Sync for Page {} unsafe impl Send for Page {} impl Page { - // Get the location of the `slot` in the current `page` based on the current `Address`. + // Get the location of the `slot` in the current `page` based on the current + // `Address`. fn slot(&self, addr: Address) -> usize { addr.0 - self.prev_len } @@ -364,7 +384,7 @@ impl Default for Page { } } } -// ################################################################################################# + struct Slots { pub slots: Vec>, pub head: usize, @@ -407,7 +427,7 @@ impl Slots { // } } } -// ################################################################################################# + #[derive(Debug)] struct Slot { pub value: UnsafeCell>, @@ -423,7 +443,7 @@ impl Slot { Ref { value } } } -// ################################################################################################# + #[derive(Debug)] struct Value { pub value: T, @@ -438,12 +458,13 @@ impl Value { } } -#[cfg(all(test))] +#[cfg(test)] mod test { - use crate::util::slab::{Address, Entry, Slab, NUM_PAGES, PAGE_INITIAL_SIZE}; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; + use crate::util::slab::{Address, Entry, Slab, NUM_PAGES, PAGE_INITIAL_SIZE}; + struct Foo { cnt: AtomicUsize, id: AtomicUsize, @@ -464,15 +485,11 @@ mod test { } } - /* - * @title Slab::new() ut test - * @design The function has no input, no exception branch, direct check function, return value - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Check the parameters for completion of initialization, such as the number of pages to be checked, the length of each page - * @expect 1、The initialization of the completed parameters should be the same as the expected value - * @auto true - */ + /// UT test cases for Slab::new() + /// + /// # Brief + /// 1. Check the parameters for completion of initialization, such as the + /// number of pages to be checked, the length of each page. #[test] fn ut_slab_new() { let slab = Slab::::new(); @@ -483,15 +500,11 @@ mod test { } } - /* - * @title Slab::for_each() ut test - * @design The function has no invalid input, no exception branch, direct check function, return value - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、To deposit data into the container, call this function to verify that the data is correctly deposited - * @expect 1、The data is correctly stored and can be matched one by one - * @auto true - */ + /// UT test cases for Slab::for_each() + /// + /// # Brief + /// 1. To deposit data into the container, call this function to verify that + /// the data is correctly deposited stored and can be matched one by one. #[test] fn ut_slab_for_each() { let mut slab = Slab::::new(); @@ -518,19 +531,12 @@ mod test { }); } - /* - * @title Slab::get() ut test - * @design The function has no invalid input, there is an exception branch, direct check function, return value - * 1、No space has been allocated for the current address - * 2、Space is allocated at the current address - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Allocate container space and deposit data, get the data address, and see if the data can be fetched - * 2、Create invalid data address to see if data can be obtained - * @expect 1、Valid data addresses can correctly acquire data - * 2、Invalid data address does not acquire data correctly - * @auto true - */ + /// UT test cases for Slab::get() + /// + /// # Brief + /// 1. Allocate container space and deposit data, get the data address,and + /// see if the data can be fetched. + /// 2. Create invalid data address to see if data can be obtained. #[test] fn ut_slab_get() { let mut slab = Slab::::new(); @@ -544,18 +550,13 @@ mod test { } } - /* - * @title Slab::compact() ut test - * @design The function has no invalid input, there is an exception branch, direct check function, return value - * 1、No space has been allocated for the current address - * 2、Space is allocated at the current address - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Pages with allocated space on the first page are not set to unallocated even if they are not used. - * 2、Pages other than the first page, once assigned and unused, will be set to unassigned status - * @expect Whether it is set to unassigned or not is related to the page assignment status and usage status - * @auto true - */ + /// UT test cases for Slab::compact() + /// + /// # Brief + /// 1. Pages with allocated space on the first page are not set to + /// unallocated even if they are not used. + /// 2. Pages other than the first page, once assigned and unused, will be + /// set to unassigned status. #[test] fn ut_slab_compact() { let mut slab = Slab::::new(); diff --git a/ylong_runtime/src/util/slots.rs b/ylong_runtime/src/util/slots.rs index 811143c..f60c276 100644 --- a/ylong_runtime/src/util/slots.rs +++ b/ylong_runtime/src/util/slots.rs @@ -14,12 +14,12 @@ //! Slots container, similar to [`std::collections::LinkedList`] use std::error::Error; -use std::fmt; use std::fmt::{Debug, Display, Formatter}; -use std::ops; use std::option::Option::Some; +use std::{fmt, ops}; -//Index tag of empty slot, vector will panic if the new capacity exceeds isize::MAX bytes. +// Index tag of empty slot, vector will panic if the new capacity exceeds +// isize::MAX bytes. const NULL: usize = usize::MAX; #[derive(Debug, Eq, PartialEq)] @@ -103,7 +103,6 @@ impl Slots { /// /// # Examples /// ``` - /// /// use ylong_runtime::util::slots::Slots; /// /// let mut slots = Slots::new(); @@ -125,10 +124,11 @@ impl Slots { /// /// Two situations: /// - /// 1.The next slot is exactly the next position of the array. Insert the data into the vector, - /// increase the length, and calculate the next insertion position. - /// - /// 2.The next slot is the recycled slot. Update the index of `next` and then insert the data. + /// 1. The next slot is exactly the next position of the array. Insert the + /// data into the vector, increase the length, and calculate the next + /// insertion position. + /// 2. The next slot is the recycled slot. Update the index of `next` and + /// then insert the data. /// /// # Examples /// @@ -208,7 +208,7 @@ impl Slots { head.prev = NULL; } } - //Update linked-list information. + // Update linked-list information. self.len -= 1; self.next = curr; return val; @@ -237,7 +237,8 @@ impl Slots { // At the next insertion, update the next insertion position entry.prev = NULL; entry.next = self.next; - //If this node is the header node, update the header node; otherwise, update the `next` of the previous node. + // If this node is the header node, update the header node; otherwise, update + // the `next` of the previous node. match self.entries.get_mut(prev) { None => { self.head = next; @@ -246,7 +247,8 @@ impl Slots { slot.next = next; } } - //If this node is the tail node, update the tail node; otherwise, update the `prev` of the next node. + // If this node is the tail node, update the tail node; otherwise, update the + // `prev` of the next node. match self.entries.get_mut(next) { None => { self.tail = prev; @@ -255,7 +257,7 @@ impl Slots { slot.prev = prev; } } - //Update linked-list information. + // Update linked-list information. self.len -= 1; self.next = key; return Ok(val); @@ -264,7 +266,8 @@ impl Slots { Err(SlotsError) } - /// Get the reference of the element in the container according to the index. + /// Get the reference of the element in the container according to the + /// index. /// /// # Examples /// @@ -287,7 +290,8 @@ impl Slots { } } - /// Get the mutable reference of the element in the container according to the index. + /// Get the mutable reference of the element in the container according to + /// the index. /// /// # Examples /// @@ -311,7 +315,8 @@ impl Slots { } } - /// Check whether the index is valid and whether there is an element at the index in the container. + /// Check whether the index is valid and whether there is an element at the + /// index in the container. /// /// # Examples /// @@ -331,7 +336,8 @@ impl Slots { } } - /// Create an immutable iterator for the container to poll all elements int the order of insertion. + /// Create an immutable iterator for the container to poll all elements int + /// the order of insertion. /// /// # Examples /// @@ -346,7 +352,6 @@ impl Slots { /// for (key, element) in slots.iter() { /// assert_eq!(slots.get(key).unwrap(), element); /// } - /// /// ``` pub fn iter(&self) -> SlotsIter { SlotsIter { @@ -475,7 +480,7 @@ impl<'a, T> Iterator for SlotsIter<'a, T> { } } -#[cfg(all(test))] +#[cfg(test)] mod test { use crate::util::slots::Slots; @@ -490,11 +495,11 @@ mod test { } } - /// UT test for Slots::new(). - /// # Title - /// ut_slots_new + /// UT test cases for Slots::new(). + /// /// # Brief - /// 1.Verify the parameters after initialization, which should be consistent with the initial value. + /// 1. Verify the parameters after initialization, which should be + /// consistent with the initial value. #[test] fn ut_slots_new() { let slots: Slots = Slots::new(); @@ -503,11 +508,11 @@ mod test { assert_eq!(slots.entries, Vec::with_capacity(0)); } - /// UT test for Slots::with_capacity(). - /// # Title - /// ut_slots_with_capacity + /// UT test cases for Slots::with_capacity(). + /// /// # Brief - /// 1.Verify the parameters after initialization, which should be consistent with the initial value. + /// 1. Verify the parameters after initialization, which should be + /// consistent with the initial value. #[test] fn ut_slots_with_capacity() { let slots_new: Slots = Slots::new(); @@ -515,11 +520,10 @@ mod test { assert_eq!(slots_new, slots_with_capacity); } - /// UT test for Slots::len(). - /// # Title - /// ut_slots_len + /// UT test cases for Slots::len(). + /// /// # Brief - /// 1.Inserting a certain number of data into the container. + /// 1. Inserting a certain number of data into the container. #[test] fn ut_slots_len() { let mut slots = Slots::new(); @@ -531,11 +535,11 @@ mod test { assert_eq!(slots.len(), 1000); } - /// UT test for Slots::clear(). - /// # Title - /// ut_slots_clear + /// UT test cases for Slots::clear(). + /// /// # Brief - /// 1.Empty the container to make it exactly the same as the initialized container. + /// 1. Empty the container to make it exactly the same as the initialized + /// container. #[test] fn ut_slots_clear() { let mut slots = Slots::new(); @@ -548,13 +552,14 @@ mod test { assert_eq!(slots, Slots::new()); } - /// UT test for Slots::insert(). - /// # Title - /// ut_slots_push_back + /// UT test cases for Slots::insert(). + /// /// # Brief - /// 1.The next slot is exactly the next position of the array. Insert the data into the vector, - /// increase the length, and calculate the next insertion position. - /// 2.The next slot is the recycled slot. Update the index of `next` and then insert the data. + /// 1. The next slot is exactly the next position of the array. Insert the + /// data into the vector, increase the length, and calculate the next + /// insertion position. + /// 2. The next slot is the recycled slot. Update the index of `next` and + /// then insert the data. #[test] fn ut_slots_push_back() { let mut slots = Slots::new(); @@ -609,11 +614,10 @@ mod test { } } - /// UT test for Slots::pop_front() - /// # Title - /// ut_slots_pop_front + /// UT test cases for Slots::pop_front() + /// /// # Brief - /// 1.Pop the slot from the head of container. + /// 1. Pop the slot from the head of container. #[test] fn ut_slots_pop_front() { let mut slots = Slots::new(); @@ -636,13 +640,12 @@ mod test { assert_eq!(slots.len(), 0); } - /// UT test for Slots::remove(). - /// # Title - /// ut_slots_remove + /// UT test cases for Slots::remove(). + /// /// # Brief - /// 1.Get the invalid data location. - /// 2.Get the valid data location, and it stores data. - /// 3.Get the valid data location, and it doesn't store data. + /// 1. Get the invalid data location. + /// 2. Get the valid data location, and it stores data. + /// 3. Get the valid data location, and it doesn't store data. #[test] fn ut_slots_remove() { let mut slots = Slots::new(); @@ -655,12 +658,11 @@ mod test { assert_eq!(slots.remove(0), Ok(0)); } - /// UT test for Slots::get(). - /// # Title - /// ut_slots_get + /// UT test cases for Slots::get(). + /// /// # Brief - /// 1.Enter the location that stores data. - /// 2.Enter the location that doesn't store data. + /// 1. Enter the location that stores data. + /// 2. Enter the location that doesn't store data. #[test] fn ut_slots_get() { let mut slots = Slots::new(); @@ -670,12 +672,11 @@ mod test { assert_eq!(slots.get(123), None); } - /// UT test for Slots::get_mut(). - /// # Title - /// ut_slots_get_mut + /// UT test cases for Slots::get_mut(). + /// /// # Brief - /// 1.Enter the location that stores data. - /// 2.Enter the location that doesn't store data. + /// 1. Enter the location that stores data. + /// 2. Enter the location that doesn't store data. #[test] fn ut_slots_get_mut() { let mut slots = Slots::new(); @@ -686,13 +687,14 @@ mod test { assert_eq!(slots.get(123), None); } - /// UT test for Slots::contains(). - /// # Title - /// ut_slots_contains + /// UT test cases for Slots::contains(). + /// /// # Brief - /// 1.The container exists the location and there are data at that location. - /// 2.The container exists the location and there are no data at that location. - /// 3.The container doesn't exist the location. + /// 1. The container exists the location and there are data at that + /// location. + /// 2. The container exists the location and there are no data at that + /// location. + /// 3. The container doesn't exist the location. #[test] fn ut_slots_contains() { let mut slots = Slots::new(); @@ -706,11 +708,10 @@ mod test { assert!(!slots.contains(key)); } - /// UT test for Slots::iter(). - /// # Title - /// ut_slots_iter + /// UT test cases for Slots::iter(). + /// /// # Brief - /// 1.Validate elements through iterators. + /// 1. Validate elements through iterators. #[test] fn ut_slots_iter() { let mut slots = Slots::new(); @@ -724,12 +725,11 @@ mod test { } } - /// UT test for Slots::is_empty(). - /// # Title - /// ut_slots_is_empty + /// UT test cases for Slots::is_empty(). + /// /// # Brief - /// 1.Verify empty container, the result is true. - /// 2.Verify non-empty container, the result is false. + /// 1. Verify empty container, the result is true. + /// 2. Verify non-empty container, the result is false. #[test] fn ut_slots_is_empty() { let mut slots = Slots::new(); @@ -739,12 +739,11 @@ mod test { assert!(!slots.is_empty()); } - /// UT test for Slots::capacity(). - /// # Title - /// ut_slots_capacity + /// UT test cases for Slots::capacity(). + /// /// # Brief - /// 1.Verify the container that is initialized. - /// 2.Verify the container that is initialized with specific capacity. + /// 1. Verify the container that is initialized. + /// 2. Verify the container that is initialized with specific capacity. #[test] fn ut_slots_capacity() { let slots: Slots = Slots::new(); diff --git a/ylong_runtime/tests/async_buf_read.rs b/ylong_runtime/tests/async_buf_read.rs index d670c2c..54a799c 100644 --- a/ylong_runtime/tests/async_buf_read.rs +++ b/ylong_runtime/tests/async_buf_read.rs @@ -13,17 +13,19 @@ use std::fs; use std::io::SeekFrom; + use ylong_runtime::fs::File; use ylong_runtime::io::{ AsyncBufReadExt, AsyncBufReader, AsyncReadExt, AsyncSeekExt, AsyncWriteExt, }; use ylong_runtime::net::{TcpListener, TcpStream}; -/// SDV test for AsyncBufReader `read_util` +/// SDV test cases for AsyncBufReader `read_util` /// /// # Brief /// 1. Establish an asynchronous tcp connection. -/// 2. The client sends some data to the server. The message contains a `:` character. +/// 2. The client sends some data to the server. The message contains a `:` +/// character. /// 3. The server wraps the TcpStream inside a AsyncBufReader /// 4. The server calls `read_until` with a delimiter ':'. /// 5. Check the read buf. @@ -62,11 +64,12 @@ fn sdv_buf_reader_read_until() { ylong_runtime::block_on(client).unwrap(); } -/// SDV test for AsyncBufReader `read_line` +/// SDV test cases for AsyncBufReader `read_line` /// /// # Brief /// 1. Establish an asynchronous tcp connection. -/// 2. The client sends some data to the server. The message contains the `\n` byte. +/// 2. The client sends some data to the server. The message contains the `\n` +/// byte. /// 3. The server wraps the TcpStream inside a AsyncBufReader /// 4. The server calls `read_line` with a delimiter '\n'. /// 5. Check the read buf. @@ -103,14 +106,15 @@ fn sdv_buf_reader_read_line() { ylong_runtime::block_on(client).unwrap(); } -/// SDV test for AsyncBufReader `split` +/// SDV test cases for AsyncBufReader `split` /// /// # Brief /// 1. Establish an asynchronous tcp connection. -/// 2. The client sends some data to the server. The message contains a `-` character. +/// 2. The client sends some data to the server. The message contains a `-` +/// character. /// 3. The server wraps the TcpStream inside a AsyncBufReader -/// 4. The server calls `split` to get segments and calls `next` with a delimiter -/// '-' for several times. +/// 4. The server calls `split` to get segments and calls `next` with a +/// delimiter '-' for several times. /// 5. Check the read buf. #[test] fn sdv_buf_reader_split() { @@ -141,14 +145,15 @@ fn sdv_buf_reader_split() { ylong_runtime::block_on(client).unwrap(); } -/// SDV test for AsyncBufReader `lines` +/// SDV test cases for AsyncBufReader `lines` /// /// # Brief /// 1. Establish an asynchronous tcp connection. -/// 2. The client sends some data to the server. The message contains the `\n` byte. +/// 2. The client sends some data to the server. The message contains the `\n` +/// byte. /// 3. The server wraps the TcpStream inside a AsyncBufReader -/// 4. The server calls `lines` to get segments and calls `next_line` with a delimiter -/// '\n' for several times. +/// 4. The server calls `lines` to get segments and calls `next_line` with a +/// delimiter '\n' for several times. /// 5. Check the read buf. #[test] fn sdv_buf_reader_lines() { @@ -188,13 +193,13 @@ fn sdv_buf_reader_lines() { ylong_runtime::block_on(client).unwrap(); } -/// SDV test for AsyncBufReader `seek` +/// SDV test cases for AsyncBufReader `seek` /// /// # Brief /// 1. Create a file and write data. /// 2. Open the file and call `read_until` with a delimiter '-'. /// 3. Seek to three different positions in the file and read data. -/// 5. Check the read buf. +/// 4. Check the read buf. #[test] fn sdv_buf_reader_seek() { let handle = ylong_runtime::spawn(async move { diff --git a/ylong_runtime/tests/async_buf_write.rs b/ylong_runtime/tests/async_buf_write.rs index 19e3fe2..9ee233e 100644 --- a/ylong_runtime/tests/async_buf_write.rs +++ b/ylong_runtime/tests/async_buf_write.rs @@ -13,17 +13,19 @@ use std::fs; use std::io::{IoSlice, SeekFrom}; + use ylong_runtime::fs::File; use ylong_runtime::io::{AsyncBufWriter, AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; use ylong_runtime::net::{TcpListener, TcpStream}; -/// SDV test for AsyncBufWriter `write` +/// SDV test cases for AsyncBufWriter `write` /// /// # Brief /// 1. Establish an asynchronous tcp connection. -/// 2. The client wraps the TcpStream inside a AsyncBufWriter and calls `write` to send some data. -/// 4. The server receives data. -/// 5. Check the read buf. +/// 2. The client wraps the TcpStream inside a AsyncBufWriter and calls `write` +/// to send some data. +/// 3. The server receives data. +/// 4. Check the read buf. #[test] fn sdv_buf_writer_write() { let server = ylong_runtime::spawn(async move { @@ -55,14 +57,14 @@ fn sdv_buf_writer_write() { ylong_runtime::block_on(client).unwrap(); } -/// SDV test for AsyncBufWriter `write_vectored` +/// SDV test cases for AsyncBufWriter `write_vectored` /// /// # Brief /// 1. Establish an asynchronous tcp connection. -/// 2. The client wraps the TcpStream inside a AsyncBufWriter and calls `write_vectored` -/// to send segmented data. -/// 4. The server receives data. -/// 5. Check the read buf. +/// 2. The client wraps the TcpStream inside a AsyncBufWriter and calls +/// `write_vectored` to send segmented data. +/// 3. The server receives data. +/// 4. Check the read buf. #[test] fn sdv_buf_writer_write_vectored() { let server = ylong_runtime::spawn(async move { @@ -97,12 +99,13 @@ fn sdv_buf_writer_write_vectored() { ylong_runtime::block_on(client).unwrap(); } -/// SDV test for AsyncBufWriter `seek` +/// SDV test cases for AsyncBufWriter `seek` /// /// # Brief /// 1. Create a file and write data. -/// 2. Open the file, seek to three different positions in the file and read data. -/// 5. Check the read buf. +/// 2. Open the file, seek to three different positions in the file and read +/// data. +/// 3. Check the read buf. #[test] fn sdv_buf_writer_seek() { let handle = ylong_runtime::spawn(async move { diff --git a/ylong_runtime/tests/async_dir.rs b/ylong_runtime/tests/async_dir.rs index 135c59f..2722c9d 100644 --- a/ylong_runtime/tests/async_dir.rs +++ b/ylong_runtime/tests/async_dir.rs @@ -13,16 +13,13 @@ use ylong_runtime::fs::{create_dir, create_dir_all, read_dir, remove_dir, remove_dir_all, File}; -/// SDV test for directory operations. -/// -/// # Title -/// sdv_async_dir +/// SDV test cases for directory operations. /// /// # Brief -/// 1.Create a new directory. -/// 2.Create two files to read. -/// 3.Read the directory and check the name of files. -/// 4.Delete the directory and files in it. +/// 1. Create a new directory. +/// 2. Create two files to read. +/// 3. Read the directory and check the name of files. +/// 4. Delete the directory and files in it. #[test] fn sdv_async_dir() { let handle = ylong_runtime::spawn(async move { @@ -45,21 +42,19 @@ fn sdv_async_dir() { ylong_runtime::block_on(handle).unwrap(); } -/// SDV test for creating and removing directories. -/// -/// # Title -/// sdv_async_dir_create_remove +/// SDV test cases for creating and removing directories. /// /// # Brief -/// 1.Create a new directory at the given path. -/// 2.Create a new directory at the given path that is used. -/// 3.Create a new directory at the given path and whose parent directory is missing. -/// 4.Create a new directory and all of its parents. -/// 5.Remove a directory at the given path. -/// 6.Remove a directory that does not exist. -/// 7.Remove a directory that is not a directory. -/// 8.Remove a directory that is not empty. -/// 9.Remove a directory and all of its contents. +/// 1. Create a new directory at the given path. +/// 2. Create a new directory at the given path that is used. +/// 3. Create a new directory at the given path and whose parent directory is +/// missing. +/// 4. Create a new directory and all of its parents. +/// 5. Remove a directory at the given path. +/// 6. Remove a directory that does not exist. +/// 7. Remove a directory that is not a directory. +/// 8. Remove a directory that is not empty. +/// 9. Remove a directory and all of its contents. #[test] fn sdv_async_dir_create_remove() { let handle = ylong_runtime::spawn(async move { diff --git a/ylong_runtime/tests/async_fs.rs b/ylong_runtime/tests/async_fs.rs index 841d24a..d193c19 100644 --- a/ylong_runtime/tests/async_fs.rs +++ b/ylong_runtime/tests/async_fs.rs @@ -13,21 +13,17 @@ use std::fs; use std::io::SeekFrom; + use ylong_runtime::builder::RuntimeBuilder; use ylong_runtime::fs::{File, OpenOptions}; use ylong_runtime::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; -/* -* @title Asynchronous file writing sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Write to an array of length 5 -* 3. Start another task to read and write the same data as you read -* @expect Write success, read success -* @auto true -*/ +/// SDV test cases for asynchronous file writing +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Write to an array of length 5. +/// 3. Start another task to read and write the same data as you read. #[test] fn sdv_async_fs_write() { let runtime = RuntimeBuilder::new_multi_thread() @@ -55,17 +51,12 @@ fn sdv_async_fs_write() { fs::remove_file("./tests/tmp_file").unwrap(); } -/* -* @title Asynchronous file reading sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Write to an array of length 5 -* 3. Start two tasks to read, write and read the same data -* @expect Read and write data successfully -* @auto true -*/ +/// SDV test cases for asynchronous file reading +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Write to an array of length 5. +/// 3. Start two tasks to read, write and read the same data. #[test] fn sdv_async_fs_read() { let runtime = RuntimeBuilder::new_multi_thread() @@ -99,17 +90,12 @@ fn sdv_async_fs_read() { fs::remove_file("./tests/tmp_file2").unwrap(); } -/* -* @title Asynchronous file multi-threaded read and write sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Start a task to perform a write operation -* 3. Start another task to perform a read operation -* @expect Read and write data successfully -* @auto true -*/ +/// SDV test cases for asynchronous file multi-threaded read and write +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Start a task to perform a write operation. +/// 3. Start another task to perform a read operation. #[test] fn sdv_async_fs_rw() { let runtime = RuntimeBuilder::new_multi_thread() @@ -177,17 +163,12 @@ fn sdv_async_fs_rw() { fs::remove_file("./tests/tmp_file3").unwrap(); } -/* -* @title Asynchronous file multi-threaded read and write sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Start a task to write a large amount of data -* 3. Start another task for reading large amounts of data -* @expect Read and write data successfully -* @auto true -*/ +/// SDV test cases for Asynchronous file multi-threaded read and write +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Start a task to write a large amount of data. +/// 3. Start another task for reading large amounts of data. #[test] fn sdv_async_fs_read_to_end() { let runtime = RuntimeBuilder::new_multi_thread().build().unwrap(); @@ -208,17 +189,12 @@ fn sdv_async_fs_read_to_end() { fs::remove_file("./tests/tmp_file7").unwrap(); } -/* -* @title Asynchronous file Seek sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Start a task to perform a write operation -* 3. Start another task for seek and read operations -* @expect Seek read successfully -* @auto true -*/ +/// SDV test cases for asynchronous file Seek +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Start a task to perform a write operation. +/// 3. Start another task for seek and read operations. #[test] fn sdv_async_fs_seek() { let runtime = RuntimeBuilder::new_multi_thread() @@ -280,17 +256,12 @@ fn sdv_async_fs_seek() { fs::remove_file("./tests/tmp_file4").unwrap(); } -/* -* @title Asynchronous file set permission sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Asynchronously get the permissions of the file -* 3. Change the permission to read only, set it to this file -* @expect Set up successfully -* @auto true -*/ +/// SDV test cases for Asynchronous file set permission +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Asynchronously get the permissions of the file. +/// 3. Change the permission to read only, set it to this file. #[test] fn sdv_async_fs_set_permission() { let runtime = RuntimeBuilder::new_multi_thread() @@ -314,16 +285,11 @@ fn sdv_async_fs_set_permission() { fs::remove_file("./tests/tmp_file5").unwrap(); } -/* -* @title Asynchronous file sync sdv test -* @design Statement Override -* @precon None -* @brief Describe test case execution -* 1. Generate an asynchronous file IO with create -* 2. Call sync_all and sync_data after asynchronous write -* @expect Sync successfully -* @auto true -*/ +/// SDV test cases for asynchronous file sync +/// +/// # Brief +/// 1. Generate an asynchronous file IO with create. +/// 2. Call sync_all and sync_data after asynchronous write. #[test] fn sdv_async_fs_sync_all() { let runtime = RuntimeBuilder::new_multi_thread() diff --git a/ylong_runtime/tests/async_pool.rs b/ylong_runtime/tests/async_pool.rs index f0e0df5..96928a0 100644 --- a/ylong_runtime/tests/async_pool.rs +++ b/ylong_runtime/tests/async_pool.rs @@ -12,9 +12,10 @@ // limitations under the License. #![cfg(target_os = "linux")] #![cfg(not(feature = "ffrt"))] -use libc::getpid; use std::ffi::OsString; use std::fs; + +use libc::getpid; use ylong_runtime::builder::RuntimeBuilder; #[cfg(target_os = "linux")] use ylong_runtime::util::core_affinity::linux::get_other_thread_affinity; @@ -71,25 +72,18 @@ unsafe fn name_of_pid(pid: &str) -> Option { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 1 - * 2、Whether to tie the core is_affinity set to true - * 3、The thread name is set to "1" - * 4、The thread stack size is set to 10 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools create only one thread and are named in a specific form - * 2、The thread binds the core and you can see the binding core location - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. ASYNCHRONOUS THREAD POOL CAPACITY TOTAL SET TO 1. +/// 2. WHETHER TO TIE THE CORE IS_AFFINITY SET TO TRUE. +/// 3. THE THREAD NAME IS SET TO "1". +/// 4. THE THREAD STACK SIZE IS SET TO 10. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_001() { let total = 1; @@ -138,25 +132,18 @@ fn sdv_async_pool_001() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 64 - * 2、Whether to tie the core is_affinity set to true - * 3、The thread name is set to "1" - * 4、The thread stack size is set to 20 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools create a maximum number of 64 threads and are named in a specific form - * 2、Thread bound cores and can see where the bound cores are located - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. Asynchronous thread pool capacity total set to 64. +/// 2. Whether to tie the core is_affinity set to true. +/// 3. The thread name is set to "1". +/// 4. The thread stack size is set to 20. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_002() { let total = 64; @@ -205,25 +192,18 @@ fn sdv_async_pool_002() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 0 - * 2、Whether to tie the core is_affinity set to true - * 3、The thread name is set to "2" - * 4、The thread stack size is set to 10 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools create only one thread and are named in a specific form - * 2、Thread bound cores and can see where the bound cores are located - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. Asynchronous thread pool capacity total set to 0. +/// 2. Whether to tie the core is_affinity set to true. +/// 3. The thread name is set to "2". +/// 4. The thread stack size is set to 10. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_003() { let total = 0; @@ -272,25 +252,18 @@ fn sdv_async_pool_003() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 65 - * 2、Whether to tie the core is_affinity set to true - * 3、The thread name is set to "2" - * 4、The thread stack size is set to 10 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、The maximum number of threads created by the asynchronous thread pool is 64, and the naming is of a specific form - * 2、Thread bound cores and can see where the bound cores are located - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. Asynchronous thread pool capacity total set to 65. +/// 2. Whether to tie the core is_affinity set to true. +/// 3. The thread name is set to "2". +/// 4. The thread stack size is set to 10. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_004() { let total = 65; @@ -339,25 +312,18 @@ fn sdv_async_pool_004() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 1 - * 2、Whether to tie the core is_affinity set to false - * 3、The thread name is set to "1" - * 4、The thread stack size is set to 10 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools create only one thread and are named in a specific form - * 2、Threads are bound to the core and can be seen without binding the core location - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. Asynchronous thread pool capacity total set to 1. +/// 2. Whether to tie the core is_affinity set to false. +/// 3. The thread name is set to "1". +/// 4. The thread stack size is set to 10. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_005() { let total = 1; @@ -406,25 +372,18 @@ fn sdv_async_pool_005() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 64 - * 2、Whether to tie the core is_affinity set to false - * 3、The thread name is set to "1" - * 4、The thread stack size is set to 20 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools are created with a maximum number of 64 threads and named in a specific form - * 2、Threads are bound to the core and can be seen without binding the core location - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. Asynchronous thread pool capacity total set to 64. +/// 2. Whether to tie the core is_affinity set to false. +/// 3. The thread name is set to "1". +/// 4. The thread stack size is set to 20. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_006() { let total = 64; @@ -473,25 +432,18 @@ fn sdv_async_pool_006() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 0 - * 2、Whether to tie the core is_affinity set to false - * 3、The thread name is set to "2" - * 4、The thread stack size is set to 10 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools create only one thread and are named in a specific form - * 2、Threads are bound to the core and can be seen without binding the core location - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment +/// 1. Asynchronous thread pool capacity total set to 0. +/// 2. Whether to tie the core is_affinity set to false. +/// 3. The thread name is set to "2". +/// 4. The thread stack size is set to 10. +/// 2. Asynchronous tasks +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_007() { let total = 0; @@ -540,25 +492,18 @@ fn sdv_async_pool_007() { } } -/* - * @title SDV Asynchronous Thread Pool Testing - * @design Set different parameter factors to check if the result is the same as expected - * @precon Use RuntimeBuilder::new_multi_thread(), get the runtime object it created - * @brief Describe test case execution - * 1、Constructed environment: - * 1、Asynchronous thread pool capacity total set to 65 - * 2、Whether to tie the core is_affinity set to false - * 3、The thread name is set to "2" - * 4、The thread stack size is set to 20 - * 2、Asynchronous tasks: - * 1、Simple asynchronous tasks - * 2、Complex asynchronous tasks - * 3、Multi-level nested asynchronous tasks - * @expect 1、Asynchronous thread pools are created with a maximum number of 64 threads and named in a specific form - * 2、Threads are bound to the core and can be seen without binding the core location - * 3、All three asynchronous tasks are able to get the results and the results are correct - * @auto true - */ +/// SDV test cases for asynchronous thread pool +/// +/// # Brief +/// 1. Constructed environment: +/// 1. Asynchronous thread pool capacity total set to 65. +/// 2. Whether to tie the core is_affinity set to false. +/// 3. The thread name is set to "2". +/// 4. The thread stack size is set to 20. +/// 2. Asynchronous tasks: +/// 1. Simple asynchronous tasks. +/// 2. Complex asynchronous tasks. +/// 3. Multi-level nested asynchronous tasks. #[test] fn sdv_async_pool_008() { let total = 65; diff --git a/ylong_runtime/tests/async_read.rs b/ylong_runtime/tests/async_read.rs index ad66453..27733a1 100644 --- a/ylong_runtime/tests/async_read.rs +++ b/ylong_runtime/tests/async_read.rs @@ -19,11 +19,11 @@ use ylong_runtime::net::{TcpListener, TcpStream}; /// SDV for &[u8]::poll_read. /// /// # Brief -/// 1. use global runtime to spawn a task -/// 2. construct a buf and a slice, buf's length is greater than the slice -/// 3. call AsyncReadExt::read on them, check the returns are correct -/// 4. construct another buf and slice, buf's length is smaller than the slice -/// 5. call AsyncReadExt::read on them, check the returns are correct +/// 1. use global runtime to spawn a task. +/// 2. construct a buf and a slice, buf's length is greater than the slice. +/// 3. call AsyncReadExt::read on them, check the returns are correct. +/// 4. construct another buf and slice, buf's length is smaller than the slice. +/// 5. call AsyncReadExt::read on them, check the returns are correct. #[test] fn sdv_async_read_slice() { ylong_runtime::block_on(async move { diff --git a/ylong_runtime/tests/block_on.rs b/ylong_runtime/tests/block_on.rs index f47a51b..bc04168 100644 --- a/ylong_runtime/tests/block_on.rs +++ b/ylong_runtime/tests/block_on.rs @@ -15,17 +15,35 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::thread::sleep; + use ylong_runtime::builder::RuntimeBuilder; -//pidstat -p `pidof block_on-0fd2269f774d8981` -t 1 -//cargo test --release test_test_schedule(fuzzy matching test name) -- --nocapture -//cargo test --color=always Run all use cases (with comments) under the current workspace -//cargo test --color=always --package ylong_runtime Run all test cases of a crate/package -//cargo test --color=always --package ylong_runtime --test block_on Run all use cases in block_on.rs -//cargo test --color=always --package ylong_runtime --test block_on single2_block_on Run a single use case for block_on.rs -//cargo test --color=always --package ylong_runtime --test block_on single2_block_on --nocapture --no-fail-fast Print and ignore failures -//cargo test --color=always --package ylong_runtime --test block_on single2_block_on -- --exact Run accurately and solve scenarios of the same name -//cargo test -p ylong_runtime Select the module you want to test, the test case you want to test and the sample of how to write the cargo doc +// pidstat -p `pidof block_on-0fd2269f774d8981` -t 1 +// +// cargo test --release test_test_schedule(fuzzy matching test name) -- +// --nocapture +// +// cargo test --color=always Run all use cases (with comments) under the +// current workspace +// +// cargo test --color=always --package ylong_runtime Run all test cases of a +// crate/package +// +// cargo test --color=always --package ylong_runtime --test block_on Run all +// use cases in block_on.rs +// +// cargo test --color=always --package ylong_runtime --test block_on +// single2_block_on Run a single use case for block_on.rs +// +// cargo test --color=always --package ylong_runtime --test block_on +// single2_block_on --nocapture --no-fail-fast Print and ignore failures +// +// cargo test --color=always --package ylong_runtime --test block_on +// single2_block_on -- --exact Run accurately and solve scenarios of the same +// name +// +// cargo test -p ylong_runtime Select the module you want to test, the test +// case you want to test and the sample of how to write the cargo doc #[test] fn sdv_single1_block_on() { @@ -240,8 +258,12 @@ fn sdv_block_on_nest_await_spawn() { assert_eq!(res, 100 * 1000); } -// Problem 1: When all the above use cases run concurrently with the following use cases, there is a segment error. The simple analysis is that someone pops at the same time when stealing, which causes the fetching task to be empty, resulting in a segment error. -// Problem 2: When there are many concurrent use cases, such as more than 1000, it is impossible to wake up the thread where block_on is located. +// Problem 1: When all the above use cases run concurrently with the following +// use cases, there is a segment error. The simple analysis is that someone pops +// at the same time when stealing, which causes the fetching task to be empty, +// resulting in a segment error. Problem 2: When there are many concurrent use +// cases, such as more than 1000, it is impossible to wake up the thread where +// block_on is located. #[test] fn sdv_block_on_nest_await_spawn_bug_test() { async fn task() -> usize { diff --git a/ylong_runtime/tests/builder.rs b/ylong_runtime/tests/builder.rs index e0c624f..60a1471 100644 --- a/ylong_runtime/tests/builder.rs +++ b/ylong_runtime/tests/builder.rs @@ -12,6 +12,7 @@ // limitations under the License. use std::sync::{Arc, Mutex}; + use ylong_runtime::builder::RuntimeBuilder; // async task @@ -19,16 +20,13 @@ async fn test_future(num: usize) -> usize { num } -/// SDV test for `after_start()`. -/// -/// # Title -/// sdv_set_builder_after_start +/// SDV test cases for `after_start()`. /// /// # Brief -/// 1.Create Runtime. -/// 2.Sender calls after_start() to set variable x to 1. -/// 3.Executing an async task. -/// 4.Check if the test results are correct. +/// 1. Create Runtime. +/// 2. Sender calls after_start() to set variable x to 1. +/// 3. Executing an async task. +/// 4. Check if the test results are correct. #[test] fn sdv_set_builder_after_start() { let x = Arc::new(Mutex::new(0)); @@ -51,16 +49,13 @@ fn sdv_set_builder_after_start() { assert_eq!(*a, 1); } -/// SDV test for `before_stop()`. -/// -/// # Title -/// sdv_set_builder_before_stop +/// SDV test cases for `before_stop()`. /// /// # Brief -/// 1.Create Runtime. -/// 2.Sender calls after_start() to set variable x to 1. -/// 3.Executing an async task. -/// 4.Check if the test results are correct. +/// 1. Create Runtime. +/// 2. Sender calls after_start() to set variable x to 1. +/// 3. Executing an async task. +/// 4. Check if the test results are correct. #[test] fn sdv_set_builder_before_stop() { let x = Arc::new(Mutex::new(0)); diff --git a/ylong_runtime/tests/core_affinity.rs b/ylong_runtime/tests/core_affinity.rs index 9bd3fc1..78bc0e1 100644 --- a/ylong_runtime/tests/core_affinity.rs +++ b/ylong_runtime/tests/core_affinity.rs @@ -13,6 +13,7 @@ #![cfg(target_os = "linux")] use std::thread; + use ylong_runtime::util::core_affinity::linux::{get_current_affinity, set_current_affinity}; use ylong_runtime::util::num_cpus::get_cpu_num; diff --git a/ylong_runtime/tests/join_set.rs b/ylong_runtime/tests/join_set.rs index 9103012..8649cb6 100644 --- a/ylong_runtime/tests/join_set.rs +++ b/ylong_runtime/tests/join_set.rs @@ -17,24 +17,21 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; use std::task::{Context, Poll}; -use ylong_runtime::task::{JoinSet, PriorityLevel}; - #[cfg(feature = "time")] use std::time::Duration; + #[cfg(feature = "time")] use ylong_runtime::error::ErrorKind; +use ylong_runtime::task::{JoinSet, PriorityLevel}; #[cfg(feature = "time")] use ylong_runtime::time::sleep; -/// SDV test for spawning and waiting for a simple future. -/// -/// # Title -/// join_set_spawn_simple +/// SDV test cases for spawning and waiting for a simple future. /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn a simple future that returns 1 immediately -/// 3. Asynchronously wait the task to finish using `join_next` +/// 1. Create a JoinSet. +/// 2. Spawn a simple future that returns 1 immediately. +/// 3. Asynchronously wait the task to finish using `join_next`. /// 4. Check the return value. #[test] fn sdv_join_set_spawn_simple() { @@ -64,15 +61,14 @@ impl Future for TestFuture { } } -/// SDV test for spawning and waiting for a future that returns pending once. -/// -/// # Title -/// join_set_spawn_pending +/// SDV test cases for spawning and waiting for a future that returns pending +/// once. /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn a future that returns pending during first poll and ready for second poll -/// 3. Asynchronously wait the task to finish using `join_next` +/// 1. Create a JoinSet. +/// 2. Spawn a future that returns pending during first poll and ready for +/// second poll. +/// 3. Asynchronously wait the task to finish using `join_next`. /// 4. Check the return value. #[test] fn sdv_join_set_spawn_pending() { @@ -82,14 +78,14 @@ fn sdv_join_set_spawn_pending() { assert_eq!(ret, 1); } -/// SDV test for spawning and waiting for two io tasks +/// SDV test cases for spawning and waiting for two io tasks /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn a task as a tcp client -/// 3. Spawn a task as a tcp server -/// 3. Asynchronously wait the tasks to finish using `join_next` -/// 4. Check the return value. +/// 1. Create a JoinSet. +/// 2. Spawn a task as a tcp client. +/// 3. Spawn a task as a tcp server. +/// 4. Asynchronously wait the tasks to finish using `join_next`. +/// 5. Check the return value. #[cfg(feature = "net")] #[test] fn sdv_join_set_spawn_io() { @@ -129,12 +125,12 @@ fn sdv_join_set_spawn_io() { ylong_runtime::block_on(handle).unwrap(); } -/// SDV test for spawning and waiting for multiple tasks +/// SDV test cases for spawning and waiting for multiple tasks /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn 100 task that returns pending once -/// 3. Asynchronously wait all the tasks to finish using `join_next` +/// 1. Create a JoinSet. +/// 2. Spawn 100 task that returns pending once. +/// 3. Asynchronously wait all the tasks to finish using `join_next`. /// 4. Check the return value. #[test] fn sdv_join_set_spawn_multiple() { @@ -151,12 +147,12 @@ fn sdv_join_set_spawn_multiple() { ylong_runtime::block_on(handle).unwrap(); } -/// SDV test for join_all +/// SDV test cases for join_all /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn 100 tasks that fetch_add an atomic value for 10 times -/// 3. Call join_all() +/// 1. Create a JoinSet. +/// 2. Spawn 100 tasks that fetch_add an atomic value for 10 times. +/// 3. Call join_all(). /// 4. Check the atomic value. #[test] fn sdv_join_set_join_all() { @@ -180,14 +176,14 @@ fn sdv_join_set_join_all() { }); } -/// SDV test for CancelHandle +/// SDV test cases for CancelHandle /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn a task that sleeps a very long time -/// 4. Cancel the task via its CancelHandle -/// 5. Call join_next -/// 6. Check the return error +/// 1. Create a JoinSet. +/// 2. Spawn a task that sleeps a very long time. +/// 3. Cancel the task via its CancelHandle. +/// 4. Call join_next. +/// 5. Check the return error. #[cfg(feature = "time")] #[test] fn sdv_join_set_cancel_one() { @@ -207,14 +203,14 @@ fn sdv_join_set_cancel_one() { } } -/// SDV test for CancelHandle +/// SDV test cases for CancelHandle /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn 100 tasks that sleep a very long time -/// 4. Cancel every task using cancel_all() -/// 5. Call join_next() -/// 6. Check the return error +/// 1. Create a JoinSet. +/// 2. Spawn 100 tasks that sleep a very long time. +/// 3. Cancel every task using cancel_all(). +/// 4. Call join_next(). +/// 5. Check the return error. #[test] #[cfg(feature = "time")] fn sdv_join_set_cancel_all() { @@ -235,13 +231,13 @@ fn sdv_join_set_cancel_all() { }); } -/// SDV test for CancelHandle +/// SDV test cases for CancelHandle /// /// # Brief -/// 1. Create a JoinSet -/// 2. Create a Builder -/// 3. Spawn 10 tasks via the Builder -/// 4. check return value +/// 1. Create a JoinSet. +/// 2. Create a Builder. +/// 3. Spawn 10 tasks via the Builder. +/// 4. check return value. #[test] fn sdv_join_set_builder() { let mut set = JoinSet::::new(); @@ -260,14 +256,14 @@ fn sdv_join_set_builder() { }); } -/// SDV test for CancelHandle +/// SDV test cases for CancelHandle /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn 100 tasks that sleep a very long time -/// 4. Shutdown the JoinSet -/// 5. Call join_next() -/// 6. Check the return error +/// 1. Create a JoinSet. +/// 2. Spawn 100 tasks that sleep a very long time. +/// 3. Shutdown the JoinSet. +/// 4. Call join_next(). +/// 5. Check the return error. #[cfg(feature = "time")] #[test] fn sdv_join_set_shutdown() { @@ -284,12 +280,12 @@ fn sdv_join_set_shutdown() { }) } -/// SDV test for JoinSet Drop to check memory leak +/// SDV test cases for JoinSet Drop to check memory leak /// /// # Brief -/// 1. Create a JoinSet -/// 2. Spawn 100 tasks that sleep a very long time -/// 3. Drop the set before tasks complete +/// 1. Create a JoinSet. +/// 2. Spawn 100 tasks that sleep a very long time. +/// 3. Drop the set before tasks complete. /// 4. Check asan for memory leak #[cfg(feature = "time")] #[test] diff --git a/ylong_runtime/tests/mpsc_test.rs b/ylong_runtime/tests/mpsc_test.rs index b9c2565..c407546 100644 --- a/ylong_runtime/tests/mpsc_test.rs +++ b/ylong_runtime/tests/mpsc_test.rs @@ -12,20 +12,17 @@ // limitations under the License. use std::time::Duration; -use ylong_runtime::sync::mpsc::bounded_channel; -use ylong_runtime::sync::mpsc::unbounded_channel; + +use ylong_runtime::sync::mpsc::{bounded_channel, unbounded_channel}; use ylong_runtime::sync::{RecvError, SendError}; use ylong_runtime::task::JoinHandle; -/// SDV test for `UnboundedSender`. -/// -/// # Title -/// sdv_unbounded_send_recv_test +/// SDV test cases for `UnboundedSender`. /// /// # Brief -/// 1.Create a unbounded mpsc channel. -/// 2.Send two values to the receiver then drop. -/// 3.Receive two values successfully and then receive error. +/// 1. Create a unbounded mpsc channel. +/// 2. Send two values to the receiver then drop. +/// 3. Receive two values successfully and then receive error. #[test] fn sdv_unbounded_send_recv_test() { let (tx, mut rx) = unbounded_channel(); @@ -40,15 +37,12 @@ fn sdv_unbounded_send_recv_test() { let _ = ylong_runtime::block_on(handle); } -/// SDV test for `UnboundedSender`. -/// -/// # Title -/// sdv_unbounded_send_try_recv_test +/// SDV test cases for `UnboundedSender`. /// /// # Brief -/// 1.Create a unbounded mpsc channel. -/// 2.Try receiving before and after sender sends a value. -/// 3.Try receiving after sender has been dropped. +/// 1. Create a unbounded mpsc channel. +/// 2. Try receiving before and after sender sends a value. +/// 3. Try receiving after sender has been dropped. #[test] fn sdv_unbounded_send_try_recv_test() { let (tx, mut rx) = unbounded_channel(); @@ -59,15 +53,12 @@ fn sdv_unbounded_send_try_recv_test() { assert_eq!(rx.try_recv(), Err(RecvError::Closed)); } -/// SDV test for `UnboundedSender`. -/// -/// # Title -/// sdv_unbounded_send_recv_timeout_test +/// SDV test cases for `UnboundedSender`. /// /// # Brief -/// 1.Create a unbounded mpsc channel. -/// 2.Send a value to the receiver. -/// 3.Receive the value in the limited time twice. +/// 1. Create a unbounded mpsc channel. +/// 2. Send a value to the receiver. +/// 3. Receive the value in the limited time twice. #[test] fn sdv_unbounded_send_recv_timeout_test() { let (tx, mut rx) = unbounded_channel(); @@ -82,15 +73,12 @@ fn sdv_unbounded_send_recv_timeout_test() { let _ = ylong_runtime::block_on(handle); } -/// SDV test for `BoundedSender`. -/// -/// # Title -/// sdv_bounded_send_recv_test +/// SDV test cases for `BoundedSender`. /// /// # Brief -/// 1.Create a bounded mpsc channel with capacity. -/// 2.Send two value to the receiver. -/// 3.Receive two values successfully and then receive error. +/// 1. Create a bounded mpsc channel with capacity. +/// 2. Send two value to the receiver. +/// 3. Receive two values successfully and then receive error. #[test] fn sdv_bounded_send_recv_test() { let (tx, mut rx) = bounded_channel::(1); @@ -107,17 +95,14 @@ fn sdv_bounded_send_recv_test() { let _ = ylong_runtime::block_on(handle); } -/// SDV test for `BoundedSender`. -/// -/// # Title -/// sdv_bounded_try_send_try_recv_test +/// SDV test cases for `BoundedSender`. /// /// # Brief -/// 1.Create a bounded mpsc channel with capacity. -/// 2.Try receiving and fails. -/// 3.Try sending two values and one succeeds and one fails. -/// 4.Try receiving and succeeds. -/// 5.Drop the sender and then receiver fails to receive. +/// 1. Create a bounded mpsc channel with capacity. +/// 2. Try receiving and fails. +/// 3. Try sending two values and one succeeds and one fails. +/// 4. Try receiving and succeeds. +/// 5. Drop the sender and then receiver fails to receive. #[test] fn sdv_bounded_try_send_try_recv_test() { let (tx, mut rx) = bounded_channel::(1); @@ -129,15 +114,14 @@ fn sdv_bounded_try_send_try_recv_test() { assert_eq!(rx.try_recv(), Err(RecvError::Closed)); } -/// SDV test for `BoundedSender`. -/// -/// # Title -/// sdv_bounded_send_timeout_recv_timeout_test +/// SDV test cases for `BoundedSender`. /// /// # Brief -/// 1.Create a bounded mpsc channel with capacity. -/// 2.Send two values to the receiver in the limited time and one succeeds and one fails. -/// 3.Receive two values from the sender in the limited time and one succeeds and one fails. +/// 1. Create a bounded mpsc channel with capacity. +/// 2. Send two values to the receiver in the limited time and one succeeds and +/// one fails. +/// 3. Receive two values from the sender in the limited time and one succeeds +/// and one fails. #[test] fn sdv_bounded_send_timeout_recv_timeout_test() { let (tx, mut rx) = bounded_channel(1); @@ -153,16 +137,15 @@ fn sdv_bounded_send_timeout_recv_timeout_test() { let _ = ylong_runtime::block_on(handle); } -/// SDV test for `BoundedSender` and `UnboundedSender`. -/// -/// # Title -/// sdv_is_closed +/// SDV test cases for `BoundedSender` and `UnboundedSender`. /// /// # Brief -/// 1.Create a unbounded mpsc channel. -/// 2.Check the close state of unbounded channel before and after the receiver is dropped. -/// 3.Create a bounded mpsc channel with capacity. -/// 3.Check the close state of bounded channel before and after the receiver is dropped. +/// 1. Create a unbounded mpsc channel. +/// 2. Check the close state of unbounded channel before and after the receiver +/// is dropped. +/// 3. Create a bounded mpsc channel with capacity. +/// 4. Check the close state of bounded channel before and after the receiver is +/// dropped. #[test] fn sdv_mpsc_is_closed() { let (tx, rx) = unbounded_channel::(); @@ -178,16 +161,13 @@ fn sdv_mpsc_is_closed() { assert!(tx.try_send(1).is_err()); } -/// SDV test for `BoundedSender` and `UnboundedSender`. -/// -/// # Title -/// sdv_is_same +/// SDV test cases for `BoundedSender` and `UnboundedSender`. /// /// # Brief -/// 1.Create two unbounded mpsc channels. -/// 2.Check whether senders have the same source. -/// 3.Create two bounded mpsc channels with capacity. -/// 2.Check whether senders have the same source. +/// 1. Create two unbounded mpsc channels. +/// 2. Check whether senders have the same source. +/// 3. Create two bounded mpsc channels with capacity. +/// 4. Check whether senders have the same source. #[test] fn sdv_mpsc_is_same() { let (tx, _) = unbounded_channel::(); @@ -203,16 +183,13 @@ fn sdv_mpsc_is_same() { assert!(tx.is_same(&tx)); } -/// SDV test for `BoundedSender` and `UnboundedSender`. -/// -/// # Title -/// sdv_len +/// SDV test cases for `BoundedSender` and `UnboundedSender`. /// /// # Brief -/// 1.Create two unbounded mpsc channels. -/// 2.Check the correctness of length of channel. -/// 3.Create two bounded mpsc channels with capacity. -/// 2.Check the correctness of length of channel. +/// 1. Create two unbounded mpsc channels. +/// 2. Check the correctness of length of channel. +/// 3. Create two bounded mpsc channels with capacity. +/// 4. Check the correctness of length of channel. #[test] fn sdv_mpsc_len() { let (tx, mut rx) = unbounded_channel(); @@ -244,16 +221,13 @@ fn sdv_mpsc_len() { assert_eq!(rx.len(), 0); } -/// SDV test for `BoundedSender` and `UnboundedSender`. -/// -/// # Title -/// sdv_multi_send_recv_test +/// SDV test cases for `BoundedSender` and `UnboundedSender`. /// /// # Brief -/// 1.Create a unbounded mpsc channel. -/// 2.Send and receive for many times. -/// 3.Create a bounded mpsc channel with capacity. -/// 2.Send and receive for many times. +/// 1. Create a unbounded mpsc channel. +/// 2. Send and receive for many times. +/// 3. Create a bounded mpsc channel with capacity. +/// 4. Send and receive for many times. #[test] fn sdv_multi_send_recv_test() { let (tx, mut rx) = unbounded_channel(); diff --git a/ylong_runtime/tests/mutex.rs b/ylong_runtime/tests/mutex.rs index f0d339b..351e492 100644 --- a/ylong_runtime/tests/mutex.rs +++ b/ylong_runtime/tests/mutex.rs @@ -11,11 +11,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Now `sdv_mutex` only has one test. In this test, `sleep` is called, requiring to initialize -//! time driver by `driver::Driver::get_mut_driver()`. This initialization will only be called -//! in `RuntimeBuilder::build()` when `net` feature is open. Therefore, -//! temporarily mark the whole test file so that it will only run when these features are open. -//! If more tests are added in the future, this conditionally compiling macro should be moved to +//! Now `sdv_mutex` only has one test. In this test, `sleep` is called, +//! requiring to initialize time driver by `driver::Driver::get_mut_driver()`. +//! This initialization will only be called in `RuntimeBuilder::build()` when +//! `net` feature is open. Therefore, temporarily mark the whole test file so +//! that it will only run when these features are open. If more tests are added +//! in the future, this conditionally compiling macro should be moved to //! mark the test `sdv_mutex_lock_hold_longtime`. #![cfg(all(feature = "sync", feature = "time"))] @@ -23,21 +24,20 @@ use std::sync::Arc; use std::thread; use std::time::Duration; + use ylong_runtime::sync::Mutex; use ylong_runtime::time; -/* - * @title UT test case for Mutex::lock() interface - * @design The design of this use case is carried out by the conditional coverage test method. - * @precon None - * @brief Test case execution steps: - * 1. Create a Concurrent Mutual Exclusion Lock - * 2. Make a concurrent process obtain a concurrent mutex lock and sleep after obtaining it to hold the lock for a long time - * 3. The main thread creates a new concurrent thread to perform the locking operation, and then modifies the value in the lock after obtaining the lock - * 4. Check the value in the lock - * @expect data is 12 - * @auto Yes - */ +/// UT test cases for Mutex::lock() interface +/// +/// # Brief +/// 1. Create a Concurrent Mutual Exclusion Lock. +/// 2. Make a concurrent process obtain a concurrent mutex lock and sleep after +/// obtaining it to hold the lock for a long time. +/// 3. The main thread creates a new concurrent thread to perform the locking +/// operation, and then modifies the value in the lock after obtaining the +/// lock. +/// 4. Check the value in the lock. #[test] fn sdv_mutex_lock_hold_longtime() { let mutex = Arc::new(Mutex::new(10)); diff --git a/ylong_runtime/tests/par_iter.rs b/ylong_runtime/tests/par_iter.rs index 2cd3345..322a384 100644 --- a/ylong_runtime/tests/par_iter.rs +++ b/ylong_runtime/tests/par_iter.rs @@ -12,12 +12,12 @@ // limitations under the License. use std::collections::{HashMap, HashSet}; -/// SDV test for par_iter -/// # Title -/// sdv_par_iter + +/// SDV test cases for par_iter +/// /// # Brief -/// 1.Creates a parallel iterator and adds elements together.. -/// 2.Checks the correctness of the answer. +/// 1. Creates a parallel iterator and adds elements together. +/// 2. Checks the correctness of the answer. use ylong_runtime::iter::prelude::*; #[test] fn sdv_par_iter_test() { diff --git a/ylong_runtime/tests/semaphore_test.rs b/ylong_runtime/tests/semaphore_test.rs index 0994a48..d539780 100644 --- a/ylong_runtime/tests/semaphore_test.rs +++ b/ylong_runtime/tests/semaphore_test.rs @@ -13,19 +13,17 @@ #![cfg(feature = "sync")] use std::sync::Arc; + use ylong_runtime::sync::{AutoRelSemaphore, Semaphore}; use ylong_runtime::task::JoinHandle; -/// SDV test for `AutoRelSemaphore::acquire()`. -/// -/// # Title -/// auto_release_sem_acquire_test +/// SDV test cases for `AutoRelSemaphore::acquire()`. /// /// # Brief -/// 1.Create a counting auto-release-semaphore with an initial capacity. -/// 2.Acquire an auto-release-permit. -/// 3.Asynchronously acquires a permit. -/// 4.Check the number of permits in every stage. +/// 1. Create a counting auto-release-semaphore with an initial capacity. +/// 2. Acquire an auto-release-permit. +/// 3. Asynchronously acquires a permit. +/// 4. Check the number of permits in every stage. #[test] fn auto_release_sem_acquire_test() { let sem = Arc::new(AutoRelSemaphore::new(1).unwrap()); @@ -38,16 +36,14 @@ fn auto_release_sem_acquire_test() { assert_eq!(sem.current_permits(), 1); } -/// SDV test for `AutoRelSemaphore::try_acquire()`. -/// -/// # Title -/// auto_release_sem_try_acquire_test +/// SDV test cases for `AutoRelSemaphore::try_acquire()`. /// /// # Brief -/// 1.Create a counting auto-release-semaphore with an initial capacity. -/// 2.Acquire an auto-release-permit. -/// 3.Fail to acquire an auto-release-permit. -/// 4.Acquire an auto-release-permit successfully after the last one is recycled. +/// 1. Create a counting auto-release-semaphore with an initial capacity. +/// 2. Acquire an auto-release-permit. +/// 3. Fail to acquire an auto-release-permit. +/// 4. Acquire an auto-release-permit successfully after the last one is +/// recycled. #[test] fn auto_release_sem_try_acquire_test() { let sem = AutoRelSemaphore::new(1).unwrap(); @@ -60,15 +56,12 @@ fn auto_release_sem_try_acquire_test() { assert!(permit3.is_ok()); } -/// SDV test for `Semaphore::release()`. -/// -/// # Title -/// release_test +/// SDV test cases for `Semaphore::release()`. /// /// # Brief -/// 1.Create a counting semaphore with an initial capacity. -/// 2.Call `Semaphore::release()` to add a permit to the semaphore. -/// 3.Check the number of permits before and after releasing. +/// 1. Create a counting semaphore with an initial capacity. +/// 2. Call `Semaphore::release()` to add a permit to the semaphore. +/// 3. Check the number of permits before and after releasing. #[test] fn release_test() { let sem = Semaphore::new(2).unwrap(); @@ -77,15 +70,12 @@ fn release_test() { assert_eq!(sem.current_permits(), 3); } -/// SDV test for `AutoRelSemaphore::close()`. -/// -/// # Title -/// auto_release_sem_close_test +/// SDV test cases for `AutoRelSemaphore::close()`. /// /// # Brief -/// 1.Create a counting auto-release-semaphore with an initial capacity. -/// 2.Close the semaphore. -/// 3.Fail to acquire an auto-release-permit. +/// 1. Create a counting auto-release-semaphore with an initial capacity. +/// 2. Close the semaphore. +/// 3. Fail to acquire an auto-release-permit. #[test] fn auto_release_sem_close_test() { let sem = Arc::new(AutoRelSemaphore::new(2).unwrap()); @@ -102,15 +92,12 @@ fn auto_release_sem_close_test() { ylong_runtime::block_on(handle).expect("block_on failed"); } -/// Stress test for `AutoRelSemaphore::acquire()`. -/// -/// # Title -/// auto_release_sem_stress_test +/// Stress test cases for `AutoRelSemaphore::acquire()`. /// /// # Brief -/// 1.Create a counting auto-release-semaphore with an initial capacity. -/// 2.Repeating acquiring an auto-release-permit for a huge number of times. -/// 3.Check the correctness of function of semaphore. +/// 1. Create a counting auto-release-semaphore with an initial capacity. +/// 2. Repeating acquiring an auto-release-permit for a huge number of times. +/// 3. Check the correctness of function of semaphore. #[test] fn auto_release_sem_stress_test() { let sem = Arc::new(AutoRelSemaphore::new(5).unwrap()); @@ -138,15 +125,14 @@ fn auto_release_sem_stress_test() { assert!(sem.try_acquire().is_err()); } -/// Stress test for `AutoRelSemaphore::acquire()` and `AutoRelSemaphore::drop()`. -/// -/// # Title -/// async_stress_test +/// Stress test cases for `AutoRelSemaphore::acquire()` and +/// `AutoRelSemaphore::drop()`. /// /// # Brief -/// 1.Create a counting auto-release-semaphore with an initial capacity. -/// 2.Repeating acquiring a pair of auto-release-permit for a huge number of times. -/// 3.Check the correctness of the future of `Permit`. +/// 1. Create a counting auto-release-semaphore with an initial capacity. +/// 2. Repeating acquiring a pair of auto-release-permit for a huge number of +/// times. +/// 3. Check the correctness of the future of `Permit`. #[test] fn async_stress_test() { let mut tasks: Vec> = Vec::new(); @@ -166,15 +152,12 @@ fn async_stress_test() { } } -/// SDV test for `Semaphore::try_acquire()`. -/// -/// # Title -/// try_acquire_test +/// SDV test cases for `Semaphore::try_acquire()`. /// /// # Brief -/// 1.Create a counting semaphore with an initial capacity. -/// 2.Acquire permits successfully. -/// 3.Fail to acquire a permit when all permits are consumed. +/// 1. Create a counting semaphore with an initial capacity. +/// 2. Acquire permits successfully. +/// 3. Fail to acquire a permit when all permits are consumed. #[test] fn try_acquire_test() { let sem = Semaphore::new(2).unwrap(); @@ -190,16 +173,13 @@ fn try_acquire_test() { assert!(permit3.is_err()); } -/// SDV test for `Semaphore::acquire()`. -/// -/// # Title -/// acquire_test +/// SDV test cases for `Semaphore::acquire()`. /// /// # Brief -/// 1.Create a counting semaphore with an initial capacity. -/// 2.Acquire a permit. -/// 3.Asynchronously acquires a permit. -/// 4.Check the number of permits in every stage. +/// 1. Create a counting semaphore with an initial capacity. +/// 2. Acquire a permit. +/// 3. Asynchronously acquires a permit. +/// 4. Check the number of permits in every stage. #[test] fn acquire_test() { let sem = Arc::new(Semaphore::new(0).unwrap()); diff --git a/ylong_runtime/tests/singleton_runtime.rs b/ylong_runtime/tests/singleton_runtime.rs index 67b1055..4d76adb 100644 --- a/ylong_runtime/tests/singleton_runtime.rs +++ b/ylong_runtime/tests/singleton_runtime.rs @@ -15,16 +15,13 @@ mod helpers; use helpers::*; use ylong_runtime::builder::RuntimeBuilder; use ylong_runtime::task::TaskBuilder; - #[cfg(feature = "time")] use ylong_runtime::time; const SPAWN_NUM: usize = 100; const THREAD_NUM: usize = 10; -/// SDV test for concurrently spawning tasks on the singleton runtime, through runtime instance. -/// -/// # Title -/// sdv_concurrently_runtime_spawn_async_in_async_task +/// SDV test cases for concurrently spawning tasks on the singleton runtime, +/// through runtime instance. /// /// # Brief /// 1. Spawn multiple threads and build runtime together. @@ -51,10 +48,8 @@ fn sdv_concurrently_runtime_spawn_async_in_async_task() { } } -/// SDV test for concurrently spawning tasks on the singleton runtime, through ylong_runtime::spawn. -/// -/// # Title -/// sdv_concurrently_spawn_async_in_async_task +/// SDV test cases for concurrently spawning tasks on the singleton runtime, +/// through ylong_runtime::spawn. /// /// # Brief /// 1. Spawn multiple threads and build runtime together. @@ -81,10 +76,8 @@ fn sdv_concurrently_spawn_async_in_async_task() { } } -/// SDV test for concurrently spawning tasks on the singleton runtime, through task builder instance. -/// -/// # Title -/// sdv_concurrently_task_builder_spawn_async_in_async_task +/// SDV test cases for concurrently spawning tasks on the singleton runtime, +/// through task builder instance. /// /// # Brief /// 1. Spawn multiple threads and build runtime together. @@ -112,12 +105,13 @@ fn sdv_concurrently_task_builder_spawn_async_in_async_task() { } } -/// SDV test for blocking on a time sleep without initializing the runtime. +/// SDV test cases for blocking on a time sleep without initializing the +/// runtime. /// /// # Brief -/// 1. Construct a future that calls time::sleep -/// 2. Use ylong_runtime::block_on to await this future to completion -/// 3. Check future's return value +/// 1. Construct a future that calls time::sleep. +/// 2. Use ylong_runtime::block_on to await this future to completion. +/// 3. Check future's return value. #[cfg(feature = "time")] #[test] fn sdv_global_block_on() { @@ -131,9 +125,9 @@ fn sdv_global_block_on() { /// SDV for setting the global runtime after starting the runtime /// /// # Brief -/// 1. Use global runtime to spawn a task -/// 2. Configures the global runtime -/// 3. Check the error +/// 1. Use global runtime to spawn a task. +/// 2. Configures the global runtime. +/// 3. Check the error. #[test] fn sdv_build_global_failed() { let _ = ylong_runtime::block_on(ylong_runtime::spawn(async move { 1 })); diff --git a/ylong_runtime/tests/slab.rs b/ylong_runtime/tests/slab.rs index 9147e36..2aa329b 100644 --- a/ylong_runtime/tests/slab.rs +++ b/ylong_runtime/tests/slab.rs @@ -15,6 +15,7 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::sync::{Arc, Mutex}; use std::thread; + use ylong_runtime::util::slab::{Entry, Slab}; struct TestEntry { @@ -37,18 +38,13 @@ impl Entry for TestEntry { } } -/* - * @title Slab SDV test - * @design The entire Slab as a container, the use of scenarios are mainly add, delete, change and check - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Inserting large amounts of data into a container - * 2、Make changes to these inserted data - * 3、Modified data by address verification - * 4、Multiplexing mechanism after calibration is released - * @expect Data validation successful - * @auto true -// */ +/// SDV test cases for Slab +/// +/// # Brief +/// 1. Inserting large amounts of data into a container. +/// 2. Make changes to these inserted data. +/// 3. Modified data by address verification. +/// 4. Multiplexing mechanism after calibration is released. #[test] fn sdv_slab_insert_move() { let mut slab = Slab::::new(); @@ -76,7 +72,8 @@ fn sdv_slab_insert_move() { assert_eq!(1, slab.get(addr1).unwrap().id.load(SeqCst)); - // Allocate again, but then the allocated `slot` should use the previously destructured `slot` + // Allocate again, but then the allocated `slot` should use the previously + // destructured `slot` let (addr3, test_entry3) = alloc.allocate().unwrap(); // Comparison, equal is successful assert_eq!(addr3, addr1); @@ -95,20 +92,16 @@ fn sdv_slab_insert_move() { } } -/* - * @title Slab SDV test - * @design The entire Slab as a container, the use of scenarios are mainly add, delete, change and check - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Inserting large amounts of data into a container - * 2、Verify by address that the data is in the correct location - * @expect Data validation successful - * @auto true - */ +/// SDV test cases for Slab +/// +/// # Brief +/// 1. Inserting large amounts of data into a container +/// 2. Verify by address that the data is in the correct location #[test] fn sdv_slab_insert_many() { unsafe { - // Verify that `page` is being allocated properly in the case of a large number of inserts. + // Verify that `page` is being allocated properly in the case of a large number + // of inserts. let mut slab = Slab::::new(); let alloc = slab.handle(); let mut entries = vec![]; @@ -139,16 +132,11 @@ fn sdv_slab_insert_many() { } } -/* - * @title Slab SDV test - * @design The entire Slab as a container, the use of scenarios are mainly add, delete, change and check - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Inserting large amounts of data into a container - * 2、Verify by address that the data is in the correct location - * @expect Data validation successful - * @auto true - */ +/// SDV test cases for Slab +/// +/// # Brief +/// 1. Inserting large amounts of data into a container +/// 2. Verify by address that the data is in the correct location #[test] fn sdv_slab_insert_drop_reverse() { unsafe { @@ -175,15 +163,11 @@ fn sdv_slab_insert_drop_reverse() { } } -/* - * @title Slab SDV test - * @design The entire Slab as a container, the use of scenarios are mainly add, delete, change and check - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Multi-threaded allocation of container space, inserting data into it, and verifying that the function is correct - * @expect Data validation successful - * @auto true - */ +/// SDV test cases for Slab +/// +/// # Brief +/// 1. Multi-threaded allocation of container space, inserting data into it, and +/// verifying that the function is correct #[test] fn sdv_slab_multi_allocate() { // Multi-threaded either allocating space, or modifying values. @@ -241,21 +225,19 @@ fn sdv_slab_multi_allocate() { } } -/* - * @title Slab SDV test - * @design The entire Slab as a container, the use of scenarios are mainly add, delete, change and check - * @precon After calling Slab::new() to initialize the container, get its object - * @brief Describe test case execution - * 1、Multi-threaded allocation of container space, inserting data into it, and verifying that the function is correct - * 2、Free up some of the data space and check if the data is reused in the multi-threaded case - * @expect Data validation successful - * @auto true - */ +/// SDV test cases for Slab +/// +/// # Brief +/// 1. Multi-threaded allocation of container space, inserting data into it, and +/// verifying that the function is correct +/// 2. Free up some of the data space and check if the data is reused in the +/// multi-threaded case #[test] fn sdv_slab_multi_allocate_drop() { // allocate space and free the used `slot` in the multi-threaded case. // retaining the address of the freed `slot` and allocating it again. - // the address after reallocation is the same as the address of the previously freed `slot`. + // the address after reallocation is the same as the address of the previously + // freed `slot`. let slab = Slab::::new(); let thread_one_alloc = slab.handle(); let thread_two_alloc = slab.handle(); diff --git a/ylong_runtime/tests/slots.rs b/ylong_runtime/tests/slots.rs index 8db098a..981f2ae 100644 --- a/ylong_runtime/tests/slots.rs +++ b/ylong_runtime/tests/slots.rs @@ -13,12 +13,11 @@ use ylong_runtime::util::slots::Slots; -/// SDV test for Slots -/// # Title -/// sdv_huge_data_push_back +/// SDV test cases for Slots +/// /// # Brief -/// 1.Push a large amount of data into the initialized container. -/// 2.Check the correctness of inserted data iteratively. +/// 1. Push a large amount of data into the initialized container. +/// 2. Check the correctness of inserted data iteratively. #[test] fn sdv_slots_huge_data_push_back() { let mut slots = Slots::new(); @@ -34,14 +33,13 @@ fn sdv_slots_huge_data_push_back() { } } -/// SDV test for Slots -/// # Title -/// sdv_huge_data_remove +/// SDV test cases for Slots +/// /// # Brief -/// 1.Push a large amount of data into the initialized container. -/// 2.Remove the first half of the container. -/// 3.Push new data into the container again. -/// 4.Check the correctness of data sequence and values. +/// 1. Push a large amount of data into the initialized container. +/// 2. Remove the first half of the container. +/// 3. Push new data into the container again. +/// 4. Check the correctness of data sequence and values. #[test] fn sdv_slots_huge_data_remove() { let mut slots = Slots::new(); @@ -68,14 +66,13 @@ fn sdv_slots_huge_data_remove() { } } -/// SDV test for Slots -/// # Title -/// sdv_remove_and_pop +/// SDV test cases for Slots +/// /// # Brief -/// 1.Push data into the initialized container. -/// 2.Remove slots that have been popped. -/// 3.Remove slots at wrong index. -/// 4.Pop the remaining data. +/// 1. Push data into the initialized container. +/// 2. Remove slots that have been popped. +/// 3. Remove slots at wrong index. +/// 4. Pop the remaining data. #[test] fn sdv_slots_remove_and_pop() { let mut slots = Slots::new(); @@ -106,12 +103,11 @@ fn sdv_slots_remove_and_pop() { assert!(slots.pop_front().is_none()); } -/// SDV test for Slots -/// # Title -/// sdv_huge_data_find +/// SDV test cases for Slots +/// /// # Brief -/// 1.Push a large amount of data into the initialized container. -/// 2.Find data through key-value pairs. +/// 1. Push a large amount of data into the initialized container. +/// 2. Find data through key-value pairs. #[test] fn sdv_slots_huge_data_find() { let mut slots = Slots::new(); @@ -127,14 +123,13 @@ fn sdv_slots_huge_data_find() { } } -/// SDV test for Slots -/// # Title -/// sdv_huge_data_pop_front +/// SDV test cases for Slots +/// /// # Brief -/// 1.Push a large amount of data into the initialized container. -/// 2.Pop the first half of the container. -/// 3.Push new data into the container again. -/// 4.Pop all of the data and check correctness of data sequence and values. +/// 1. Push a large amount of data into the initialized container. +/// 2. Pop the first half of the container. +/// 3. Push new data into the container again. +/// 4. Pop all of the data and check correctness of data sequence and values. #[test] fn sdv_slots_huge_data_pop_front() { let mut slots = Slots::new(); diff --git a/ylong_runtime/tests/spawn.rs b/ylong_runtime/tests/spawn.rs index 7b4d1ea..372db39 100644 --- a/ylong_runtime/tests/spawn.rs +++ b/ylong_runtime/tests/spawn.rs @@ -177,7 +177,8 @@ fn sdv_multi_future_in_async() { } } -// Calling other `async` blocks within an `async` block has a multiple call relationship +// Calling other `async` blocks within an `async` block has a multiple call +// relationship #[test] fn sdv_multi_async_in_async() { let core_pool_size = 4; diff --git a/ylong_runtime/tests/spawn_blocking.rs b/ylong_runtime/tests/spawn_blocking.rs index 272ce82..f6a7297 100644 --- a/ylong_runtime/tests/spawn_blocking.rs +++ b/ylong_runtime/tests/spawn_blocking.rs @@ -13,6 +13,7 @@ use std::thread::sleep; use std::time; + use ylong_runtime::builder::RuntimeBuilder; use ylong_runtime::executor::Runtime; use ylong_runtime::task::TaskBuilder; diff --git a/ylong_runtime/tests/sync.rs b/ylong_runtime/tests/sync.rs index 8a1dddf..bc8f3da 100644 --- a/ylong_runtime/tests/sync.rs +++ b/ylong_runtime/tests/sync.rs @@ -11,20 +11,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::{Arc, Mutex}; -use ylong_runtime::sync::Mutex as YlongMutex; - use std::future::Future; use std::pin::Pin; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::{Acquire, Release}; +use std::sync::{Arc, Mutex}; use std::task::{Context, Poll}; use std::thread; use std::thread::sleep; use std::time::Duration; -use ylong_runtime::sync::Waiter; -use ylong_runtime::sync::RwLock; +use ylong_runtime::sync::{Mutex as YlongMutex, RwLock, Waiter}; const NUM: usize = 200; @@ -54,16 +51,13 @@ async fn test_future() -> usize { create_new(1000).await } -/// SDV test for `Mutex`. -/// -/// # Title -/// sdv_concurrency_with_mutex1 +/// SDV test cases for `Mutex`. /// /// # Brief -/// 1.Create Runtime. -/// 2.Create a variable of Mutex. -/// 3.Executing an async task and change the variable. -/// 4.Check if the test results are correct. +/// 1. Create Runtime. +/// 2. Create a variable of Mutex. +/// 3. Executing an async task and change the variable. +/// 4. Check if the test results are correct. #[test] fn sdv_concurrency_with_mutex1() { ylong_runtime::block_on(async { @@ -115,16 +109,13 @@ fn sdv_concurrency_with_mutex1() { }); } -/// SDV test for `Mutex`. -/// -/// # Title -/// sdv_concurrency_with_mutex2 +/// SDV test cases for `Mutex`. /// /// # Brief -/// 1.Create Runtime. -/// 2.Create a variable of Mutex. -/// 3.Executing an async task and change the variable for 100 times. -/// 4.Check if the test results are correct. +/// 1. Create Runtime. +/// 2. Create a variable of Mutex. +/// 3. Executing an async task and change the variable for 100 times. +/// 4. Check if the test results are correct. #[test] fn sdv_concurrency_with_mutex2() { ylong_runtime::block_on(async { @@ -144,15 +135,12 @@ fn sdv_concurrency_with_mutex2() { }); } -/// SDV test for `Mutex`. -/// -/// # Title -/// sdv_concurrency_with_mutex3 +/// SDV test cases for `Mutex`. /// /// # Brief -/// 1.Create Runtime. -/// 2.Executing async tasks and Change the variable for 5 times -/// 3.Check if the test results are correct. +/// 1. Create Runtime. +/// 2. Executing async tasks and Change the variable for 5 times +/// 3. Check if the test results are correct. #[test] fn sdv_concurrency_with_mutex3() { ylong_runtime::block_on(async { @@ -178,27 +166,24 @@ fn sdv_concurrency_with_mutex3() { }); } -/// SDV test for `Mutex`. -/// -/// # Title -/// sdv_concurrency_with_mutex4 +/// SDV test cases for `Mutex`. /// /// # Brief -/// 1.Create Runtime. -/// 2.Executing an async task which contains an async task and locking -/// 3.Check if the test results are correct. +/// 1. Create Runtime. +/// 2. Executing an async task which contains an async task and locking +/// 3. Check if the test results are correct. #[test] fn sdv_concurrency_with_mutex4() { let mutex1 = Arc::new(YlongMutex::new(0)); - // If test_future().await and the lock operation are put together to form a future, - // there is a sequential relationship between the two futures, + // If test_future().await and the lock operation are put together to form a + // future, there is a sequential relationship between the two futures, let mut handlers1 = Vec::with_capacity(NUM); let mut handlers2 = Vec::with_capacity(NUM); for _ in 0..200 { let mutex = mutex1.clone(); handlers1.push(ylong_runtime::spawn(async move { - //test_future() and locking do not exist concurrently. + // test_future() and locking do not exist concurrently. test_future().await; let mut n = mutex.lock().await; *n += 1; @@ -207,7 +192,7 @@ fn sdv_concurrency_with_mutex4() { for _ in 0..200 { handlers2.push(ylong_runtime::spawn( - //test_future() and locking exist concurrently. + // test_future() and locking exist concurrently. test_future(), )); } @@ -226,16 +211,13 @@ fn sdv_concurrency_with_mutex4() { }); } -/// SDV test for RwLock. -/// -/// # Title -/// sdv_rwlock_multi_threads +/// SDV test cases for RwLock. /// /// # Brief -/// 1.Create producer_lock. -/// 2.Write for 100000 times. -/// 3.Two read thread to read for 100000 times. -/// 4.Check if the test results are correct. +/// 1. Create producer_lock. +/// 2. Write for 100000 times. +/// 3. Two read thread to read for 100000 times. +/// 4. Check if the test results are correct. #[test] fn sdv_rwlock_multi_threads() { // Put the counter initial value into a read/write lock encapsulated @@ -283,16 +265,13 @@ fn sdv_rwlock_multi_threads() { assert_eq!(*mutex.lock().unwrap(), 110000); } -/// SDV test for RwLock read. -/// -/// # Title -/// sdv_rwlock_with_read1 +/// SDV test cases for RwLock read. /// /// # Brief -/// 1.Create a variable of Rwlock. -/// 2.Create Runtime. -/// 3.Executing an async task for 200 times. -/// 4.Check if the test results are correct. +/// 1. Create a variable of Rwlock. +/// 2. Create Runtime. +/// 3. Executing an async task for 200 times. +/// 4. Check if the test results are correct. #[test] fn sdv_rwlock_with_read1() { let rwlock = Arc::new(RwLock::new(5)); @@ -317,16 +296,13 @@ fn sdv_rwlock_with_read1() { } } -/// SDV test for read lock. -/// -/// # Title -/// sdv_rwlock_with_read2 +/// SDV test cases for read lock. /// /// # Brief -/// 1.Create a variable of Rwlock. -/// 2.Create Runtime. -/// 3.Read for 200 times. -/// 4.Check if the test results are correct. +/// 1. Create a variable of Rwlock. +/// 2. Create Runtime. +/// 3. Read for 200 times. +/// 4. Check if the test results are correct. #[test] fn sdv_rwlock_with_read2() { let rwlock = Arc::new(RwLock::new(5)); @@ -344,17 +320,14 @@ fn sdv_rwlock_with_read2() { } } -/// SDV test for read-write lock. -/// -/// # Title -/// sdv_rwlock_read_and_write +/// SDV test cases for read-write lock. /// /// # Brief -/// 1.Create a variable of Rwlock. -/// 2.Create Runtime. -/// 3.Executing an async task. -/// 3.Read and write for 200 times. -/// 4.Check if the test results are correct. +/// 1. Create a variable of Rwlock. +/// 2. Create Runtime. +/// 3. Executing an async task. +/// 4. Read and write for 200 times. +/// 5. Check if the test results are correct. #[test] fn sdv_rwlock_read_and_write() { let rwlock = Arc::new(RwLock::new(5)); @@ -389,16 +362,13 @@ fn sdv_rwlock_read_and_write() { }); } -/// SDV test for Rwlock. -/// -/// # Title -/// sdv_rwlock_with_write1 +/// SDV test cases for Rwlock. /// /// # Brief -/// 1.Create a variable of Rwlock. -/// 2.Create Runtime. -/// 3.Write and execute another task for 200 times. -/// 4.Check if the test results are correct. +/// 1. Create a variable of Rwlock. +/// 2. Create Runtime. +/// 3. Write and execute another task for 200 times. +/// 4. Check if the test results are correct. #[test] fn sdv_rwlock_with_write1() { let rwlock = Arc::new(RwLock::new(5)); @@ -428,16 +398,13 @@ fn sdv_rwlock_with_write1() { }); } -/// SDV test for Rwlock. -/// -/// # Title -/// sdv_rwlock_with_write2 +/// SDV test cases for Rwlock. /// /// # Brief -/// 1.Create a variable of Rwlock. -/// 2.Create Runtime. -/// 3.Write for 200 times. -/// 4.Check if the test results are correct. +/// 1. Create a variable of Rwlock. +/// 2. Create Runtime. +/// 3. Write for 200 times. +/// 4. Check if the test results are correct. #[test] fn sdv_rwlock_with_write2() { let rwlock = Arc::new(RwLock::new(5)); @@ -460,14 +427,11 @@ fn sdv_rwlock_with_write2() { }); } -/// SDV test for `Waiter::wake_one()`. -/// -/// # Title -/// sdv_waiter_with_wake_one +/// SDV test cases for `Waiter::wake_one()`. /// /// # Brief -/// 1.Call `wake_one` before a task calling `wait`. -/// 2.Call `wake_one` after a task calling `wait`. +/// 1. Call `wake_one` before a task calling `wait`. +/// 2. Call `wake_one` after a task calling `wait`. #[test] fn sdv_waiter_with_wake_one() { let waiter = Arc::new(Waiter::new()); @@ -494,13 +458,10 @@ fn sdv_waiter_with_wake_one() { let _ = ylong_runtime::block_on(handle3); } -/// SDV test for `Waiter::wake_all()`. -/// -/// # Title -/// sdv_waiter_with_wake_all +/// SDV test cases for `Waiter::wake_all()`. /// /// # Brief -/// 1.Call `wake_all` after some tasks calling `wait`. +/// 1. Call `wake_all` after some tasks calling `wait`. #[test] fn sdv_waiter_with_wake_all() { let waiter = Arc::new(Waiter::new()); diff --git a/ylong_runtime/tests/task_cancel.rs b/ylong_runtime/tests/task_cancel.rs index 3cf596a..e2ca9a8 100644 --- a/ylong_runtime/tests/task_cancel.rs +++ b/ylong_runtime/tests/task_cancel.rs @@ -17,13 +17,11 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; + use ylong_runtime::error::ErrorKind; use ylong_runtime::time::sleep; -/// SDV test for canceling a task. -/// -/// # Title -/// sdv_task_cancel_simple +/// SDV test cases for canceling a task. /// /// # Brief /// 1. Configure the RuntimeBuilder and start the runtime @@ -45,10 +43,7 @@ fn sdv_task_cancel_simple() { ylong_runtime::block_on(handle).unwrap(); } -/// SDV test for canceling a task after its finished -/// -/// # Title -/// sdv_task_cancel_failed +/// SDV test cases for canceling a task after its finished /// /// # Brief /// 1. Configure the RuntimeBuilder and start the runtime @@ -88,7 +83,7 @@ impl Future for TestFuture { } } -/// SDV test for multi cancel. +/// SDV test cases for multi cancel. /// /// # Brief /// 1. In a loop, create a long-time task and then cancel it. diff --git a/ylong_runtime/tests/tcp_test.rs b/ylong_runtime/tests/tcp_test.rs index 1d51e85..14a15d7 100644 --- a/ylong_runtime/tests/tcp_test.rs +++ b/ylong_runtime/tests/tcp_test.rs @@ -12,6 +12,7 @@ // limitations under the License. use std::thread; + use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; use ylong_runtime::net::{TcpListener, TcpStream}; diff --git a/ylong_runtime/tests/timer_test.rs b/ylong_runtime/tests/timer_test.rs index fb49b3a..d4966d3 100644 --- a/ylong_runtime/tests/timer_test.rs +++ b/ylong_runtime/tests/timer_test.rs @@ -14,6 +14,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; + use ylong_runtime::time::sleep; type AppId = usize; @@ -90,14 +91,11 @@ async fn simulate() { } } -/// SDV test for multi time create. -/// -/// # Title -/// test_multi_timer +/// SDV test cases for multi time create. /// /// # Brief -/// 1.Creates multi threads and multi timers. -/// 2.Checks if the test results are correct. +/// 1. Creates multi threads and multi timers. +/// 2. Checks if the test results are correct. #[test] fn test_multi_timer() { ylong_runtime::block_on(simulate()); diff --git a/ylong_runtime/tests/udp_test.rs b/ylong_runtime/tests/udp_test.rs index 9b72bfd..8989227 100644 --- a/ylong_runtime/tests/udp_test.rs +++ b/ylong_runtime/tests/udp_test.rs @@ -12,18 +12,16 @@ // limitations under the License. use std::{io, thread}; + use ylong_runtime::net::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 sdv_udp_send_recv() { let sender_addr = "127.0.0.1:8081".parse().unwrap(); @@ -73,16 +71,13 @@ fn sdv_udp_send_recv() { ylong_runtime::block_on(handle).expect("block_on failed"); } -/// 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 sdv_udp_send_to_recv_from() { let sender_addr = "127.0.0.1:8085".parse().unwrap(); @@ -149,16 +144,14 @@ fn sdv_udp_send() { ylong_runtime::block_on(handle).expect("block_on failed"); } -/// SDV test for functions in a multithreaded environment. -/// -/// # Title -/// test_thread_func +/// SDV test cases for functions in a multithreaded environment. /// /// # Brief -/// 1.Create sender and receiver threads, bind their new UdpSockets and connect to each other. -/// 2.Sender send message in sender thread. -/// 3.Receiver receives message in receiver thread. -/// 4.Check if the test results are correct. +/// 1. Create sender and receiver threads, bind their new UdpSockets and connect +/// to each other. +/// 2. Sender send message in sender thread. +/// 3. Receiver receives message in receiver thread. +/// 4. Check if the test results are correct. #[test] fn sdv_udp_recv() { let sender_addr = "127.0.0.1:8089".parse().unwrap(); @@ -186,13 +179,14 @@ fn sdv_udp_recv() { ylong_runtime::block_on(handle).expect("block_on failed"); } -/// SDV test for `try_send_to()` and `try_recv_from()`. +/// SDV test cases for `try_send_to()` and `try_recv_from()`. /// /// # Brief -/// 1.Create UdpSocket. -/// 2.Sender tries to send message to the specified address. -/// 3.Receiver tries to receive message and return the address the message from. -/// 4.Check if the test results are correct. +/// 1. Create UdpSocket. +/// 2. Sender tries to send message to the specified address. +/// 3. Receiver tries to receive message and return the address the message +/// from. +/// 4. Check if the test results are correct. #[test] fn sdv_udp_try_recv_from() { let sender_addr = "127.0.0.1:8091".parse().unwrap(); @@ -272,13 +266,16 @@ fn sdv_udp_try_send() { ylong_runtime::block_on(handle).expect("block_on failed"); } -/// SDV test for try_send and try_recv +/// SDV test cases for try_send and try_recv /// /// # Brief -/// 1.Create sender and receiver threads, bind their new UdpSockets and connect to each other. -/// 2.Sender waits for writable events and attempts to send message in sender thread. -/// 3.Receiver waits for readable events and attempts to receive message in receiver thread. -/// 4.Check if the test results are correct. +/// 1. Create sender and receiver threads, bind their new UdpSockets and connect +/// to each other. +/// 2. Sender waits for writable events and attempts to send message in sender +/// thread. +/// 3. Receiver waits for readable events and attempts to receive message in +/// receiver thread. +/// 4. Check if the test results are correct. #[test] fn sdv_udp_try_recv() { let sender_addr = "127.0.0.1:8093".parse().unwrap(); diff --git a/ylong_runtime_macros/examples/macro_tuple_form.rs b/ylong_runtime_macros/examples/macro_tuple_form.rs index 0b1d241..c9ad63b 100644 --- a/ylong_runtime_macros/examples/macro_tuple_form.rs +++ b/ylong_runtime_macros/examples/macro_tuple_form.rs @@ -24,7 +24,8 @@ fn main() { // tuple's length = number of `x`'s round brackets - 2 // tuple's default element = `A` // tuple's except element = `B` - // tuple's except element's index = `y`'s TokenTree count, in addition to the parentheses + // tuple's except element's index = `y`'s TokenTree count, in addition to the + // parentheses let tuple = ylong_runtime_macros::tuple_form!(( (((0)+1)+1) ) with Out::Fail except Out::Finish at ( ) ); assert_eq!(tuple, (Out::Finish, Out::Fail)); diff --git a/ylong_runtime_macros/src/entry.rs b/ylong_runtime_macros/src/entry.rs index ee437df..1f2ebb8 100644 --- a/ylong_runtime_macros/src/entry.rs +++ b/ylong_runtime_macros/src/entry.rs @@ -14,10 +14,11 @@ use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; -use syn::{ - parse::Parser, punctuated::Punctuated, spanned::Spanned, token::Comma, Error, ItemFn, - MetaNameValue, Result, -}; +use syn::parse::Parser; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::Comma; +use syn::{Error, ItemFn, MetaNameValue, Result}; fn stream_with_error(mut stream: TokenStream2, errors: Option) -> TokenStream2 { if let Some(error) = errors { @@ -218,11 +219,12 @@ fn build_stream(mut async_fn: ItemFn, mut config: Config) -> TokenStream2 { #[cfg(test)] mod test { use super::*; - /// UT test cases for `build_stream` in main procedural macro. + /// UT test cases for cases for `build_stream` in main procedural macro. /// /// # Brief /// 1. Creates an `async_fn` using `quote!`. - /// 2. Creates an `output` by calling `build_stream` with different `config`. + /// 2. Creates an `output` by calling `build_stream` with different + /// `config`. /// 3. Checks if the result is correct. #[test] fn ut_build_stream_main() { @@ -251,7 +253,7 @@ mod test { let res: ItemFn = syn::parse2(res).unwrap(); assert_eq!(res, output); - //current + // current let args = quote! { flavor = "current" }; @@ -277,7 +279,8 @@ mod test { /// /// # Brief /// 1. Creates an `async_fn` using `quote!`. - /// 2. Creates an `output` by calling `build_stream` with different `config`. + /// 2. Creates an `output` by calling `build_stream` with different + /// `config`. /// 3. Checks if the result is correct. #[test] fn ut_build_stream_test() { @@ -288,7 +291,7 @@ mod test { }; let async_fn: ItemFn = syn::parse2(item).unwrap(); - //default config for test procedural macro, where the flavor is `current`. + // default config for test procedural macro, where the flavor is `current`. let args = quote! {}; let config = build_config(args, true).unwrap(); @@ -309,7 +312,7 @@ mod test { let res: ItemFn = syn::parse2(res).unwrap(); assert_eq!(res, output); - //current + // current let args = quote! { flavor = "current" diff --git a/ylong_runtime_macros/src/lib.rs b/ylong_runtime_macros/src/lib.rs index d05c5e7..1d7b6be 100644 --- a/ylong_runtime_macros/src/lib.rs +++ b/ylong_runtime_macros/src/lib.rs @@ -62,11 +62,15 @@ pub fn tuple_form(input: TokenStream) -> TokenStream { /// Mark the async fn to execute with the selected runtime. /// -/// You can set the runtime by adding attributes after the main ident in a parentheses. Attributes that can be set include runtime flavor , .... +/// You can set the runtime by adding attributes after the main ident in a +/// parentheses. Attributes that can be set include runtime flavor , .... /// -/// Note: This procedural macro is just to simplify the setup of ylong runtime. If you need more complex and specific settings. You should directly invoke the runtime builder function. +/// Note: This procedural macro is just to simplify the setup of ylong runtime. +/// If you need more complex and specific settings. You should directly invoke +/// the runtime builder function. /// -/// Note: Please make sure that the corresponding feature is enabled, otherwise it will show that the corresponding function cannot be found. +/// Note: Please make sure that the corresponding feature is enabled, otherwise +/// it will show that the corresponding function cannot be found. /// /// ## Usage /// diff --git a/ylong_runtime_macros/src/select.rs b/ylong_runtime_macros/src/select.rs index 51adf05..70a662a 100644 --- a/ylong_runtime_macros/src/select.rs +++ b/ylong_runtime_macros/src/select.rs @@ -52,8 +52,9 @@ pub(crate) fn tuple_parser(input: TokenStream) -> TupleParser { } TokenTree::Group(group) => { if !flag_with && !flag_except && !flag_at { - // The tuple length is obtained by calculating the number of parenthesis layers of ((0 + 1) + 1). - // Actually the '0' also has a parenthesis wrapped around it, So here have to -1. + // The tuple length is obtained by calculating the number of parenthesis layers + // of ((0 + 1) + 1). Actually the '0' also has a parenthesis wrapped around it, + // So here have to -1. len = group_num(group.stream()) - 1; idx += 1; continue;