benchmark补全

Signed-off-by: MingyuChen <chenmingyu4@huawei.com>
This commit is contained in:
MingyuChen 2024-05-21 19:58:48 +08:00
parent c22b209a74
commit fef055fd82
60 changed files with 1792 additions and 546 deletions

View File

@ -69,3 +69,46 @@ impl ops::BitOr for Interest {
self.add(other)
}
}
#[cfg(test)]
mod test {
/// UT cases for `into_io_event`.
///
/// # Brief
/// 1. Create different kinds of Interest
/// 2. Turn the Interest into IO Event
#[cfg(target_os = "linux")]
#[test]
fn ut_interest_to_io_event() {
use std::num::NonZeroU8;
use libc::c_int;
use crate::Interest;
#[allow(clippy::init_numbered_fields)]
let interest = Interest {
0: NonZeroU8::new(4).unwrap(),
};
let event = interest.into_io_event();
assert_eq!(event as c_int, libc::EPOLLET);
let interest = Interest::READABLE;
let event = interest.into_io_event();
assert_eq!(
event as c_int,
libc::EPOLLET | libc::EPOLLIN | libc::EPOLLRDHUP
);
let interest = Interest::WRITABLE;
let event = interest.into_io_event();
assert_eq!(event as c_int, libc::EPOLLET | libc::EPOLLOUT);
let interest = Interest::READABLE | Interest::WRITABLE;
let event = interest.into_io_event();
assert_eq!(
event as c_int,
libc::EPOLLET | libc::EPOLLIN | libc::EPOLLRDHUP | libc::EPOLLOUT
);
}
}

View File

@ -46,14 +46,6 @@ impl Poll {
source.register(&self.selector, token, interests)
}
/// Re-registers the I/O source's fd in order to monitor its io events.
pub fn reregister<S>(&self, source: &mut S, token: Token, interests: Interest) -> io::Result<()>
where
S: Source + ?Sized,
{
source.reregister(&self.selector, token, interests)
}
/// De-registers the I/O source's fd so the Poll will no longer monitor its
/// io events.
pub fn deregister<S>(&self, source: &mut S) -> io::Result<()>
@ -74,3 +66,21 @@ impl std::fmt::Debug for Poll {
write!(fmt, "({:?})", self.selector)
}
}
#[cfg(test)]
mod test {
/// UT cases for debug info of poll
///
/// # Brief
/// 1. Create a Poll
/// 2. Check its fmt debug info
#[test]
#[cfg(target_os = "linux")]
fn ut_poll_debug_info() {
use crate::Poll;
let poll = Poll::new().unwrap();
let fmt = format!("{:?}", poll);
assert!(fmt.contains("epoll fd:"));
assert!(fmt.contains("Select id:"));
}
}

View File

@ -35,15 +35,6 @@ pub trait Source {
interests: Interest,
) -> io::Result<()>;
/// Reregisters the connection into [`crate::Poll`], this can change
/// [`Interest`].
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()>;
/// Deregisters the connection from [`crate::Poll`].
fn deregister(&mut self, selector: &Selector) -> io::Result<()>;

View File

@ -12,7 +12,7 @@
// limitations under the License.
use std::io;
use std::os::raw::{c_int, c_uint};
use std::os::raw::c_int;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
@ -75,7 +75,7 @@ impl Selector {
/// Registers the fd with specific interested events
pub fn register(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()> {
let mut sys_event = libc::epoll_event {
events: interests_to_io_event(interests),
events: interests.into_io_event(),
u64: usize::from(token) as u64,
};
@ -88,7 +88,7 @@ impl Selector {
/// Re-registers the fd with specific interested events
pub fn reregister(&self, fd: i32, token: Token, interests: Interest) -> io::Result<()> {
let mut sys_event = libc::epoll_event {
events: interests_to_io_event(interests),
events: interests.into_io_event(),
u64: usize::from(token) as u64,
};
@ -112,21 +112,6 @@ impl Selector {
}
}
fn interests_to_io_event(interests: Interest) -> c_uint {
let mut io_event = libc::EPOLLET as u32;
if interests.is_readable() {
io_event |= libc::EPOLLIN as u32;
io_event |= libc::EPOLLRDHUP as u32;
}
if interests.is_writable() {
io_event |= libc::EPOLLOUT as u32;
}
io_event as c_uint
}
impl Drop for Selector {
fn drop(&mut self) {
if let Err(_err) = syscall!(close(self.ep)) {
@ -178,3 +163,38 @@ impl EventTrait for Event {
(self.events as libc::c_int & libc::EPOLLERR) != 0
}
}
#[cfg(test)]
mod test {
use crate::sys::socket;
use crate::{Event, EventTrait, Interest, Selector, Token};
/// UT cases for `Selector::reregister`.
///
/// # Brief
/// 1. Create a Selector
/// 2. Reregister the selector
#[test]
fn ut_epoll_reregister() {
let selector = Selector::new().unwrap();
let sock = socket::socket_new(libc::AF_UNIX, libc::SOCK_STREAM).unwrap();
let ret = selector.register(sock, Token::from_usize(0), Interest::READABLE);
assert!(ret.is_ok());
let ret = selector.reregister(sock, Token::from_usize(0), Interest::WRITABLE);
assert!(ret.is_ok());
}
/// UT case for `Event::is_error`
///
/// # Brief
/// 1. Create an event from libc::EPOLLERR
/// 2. Check if it's an error
#[test]
fn ut_event_is_err() {
let event = Event {
events: libc::EPOLLERR as u32,
u64: 0,
};
assert!(event.is_error());
}
}

View File

@ -30,15 +30,6 @@ impl<'a> Source for SourceFd<'a> {
selector.register(self.get_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.get_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.get_fd())
}
@ -47,3 +38,22 @@ impl<'a> Source for SourceFd<'a> {
*self.0
}
}
#[cfg(test)]
mod test {
use crate::sys::{socket, SourceFd};
/// UT cases for debug info of SourceFd.
///
/// # Brief
/// 1. Create a SourceFd
/// 2. Reregister the SourceFd
#[test]
fn ut_source_fd_debug_info() {
let sock = socket::socket_new(libc::AF_UNIX, libc::SOCK_STREAM).unwrap();
let source_fd = SourceFd(&sock);
let fmt = format!("{:?}", source_fd);
assert!(fmt.contains("SourceFd("));
}
}

View File

@ -182,15 +182,6 @@ impl Source for TcpListener {
selector.register(self.get_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.get_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.get_fd())
}

View File

@ -148,3 +148,24 @@ fn into_linger(duration: Option<Duration>) -> linger {
},
}
}
#[cfg(test)]
mod test {
use std::ffi::c_int;
use std::os::fd::{AsRawFd, FromRawFd};
use crate::sys::unix::tcp::socket::into_linger;
use crate::sys::unix::tcp::TcpSocket;
/// UT for `into_linger`
///
/// # Brief
/// 1. Call `into_linger` with parameter None
/// 2. Check if the returned linger is correct
#[test]
fn ut_into_linger_none() {
let linger = into_linger(None);
assert_eq!(linger.l_linger, 0);
assert_eq!(linger.l_linger, 0);
}
}

View File

@ -286,15 +286,6 @@ impl Source for TcpStream {
selector.register(self.get_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.get_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.get_fd())
}

View File

@ -763,15 +763,6 @@ impl Source for UdpSocket {
selector.register(self.get_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.get_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.get_fd())
}
@ -791,15 +782,6 @@ impl Source for ConnectedUdpSocket {
selector.register(self.get_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.get_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.get_fd())
}

View File

@ -269,15 +269,6 @@ impl Source for UnixDatagram {
selector.register(self.inner.as_raw_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.inner.as_raw_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.inner.as_raw_fd())
}
@ -304,3 +295,41 @@ impl FromRawFd for UnixDatagram {
UnixDatagram::from_std(FromRawFd::from_raw_fd(fd))
}
}
#[cfg(test)]
mod test {
use std::net::Shutdown;
use std::os::fd::{FromRawFd, IntoRawFd};
use crate::UnixDatagram;
/// UT for `UnixDatagram::pair`
///
/// # Brief
/// 1. Create a pair of UnixDatagram
/// 2. Check if the peer address is correct
/// 3. Check if the local address is correct
/// 4. Shutdown both UnixDatagram
#[test]
fn ut_uds_datagram_pair() {
let (sender, receiver) = UnixDatagram::pair().unwrap();
let sender2 = sender.try_clone().unwrap();
let addr = sender2.local_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
let addr = receiver.peer_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
let fd = receiver.into_raw_fd();
let receiver2 = unsafe { UnixDatagram::from_raw_fd(fd) };
let addr = receiver2.local_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
receiver2.shutdown(Shutdown::Both).unwrap();
sender.shutdown(Shutdown::Both).unwrap()
}
}

View File

@ -172,15 +172,6 @@ impl Source for UnixListener {
selector.register(self.inner.as_raw_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.inner.as_raw_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.inner.as_raw_fd())
}

View File

@ -102,3 +102,25 @@ impl fmt::Debug for SocketAddr {
}
}
}
#[cfg(test)]
mod test {
use crate::SocketAddr;
/// UT for uds sockaddr debug info
///
/// # Brief
/// 1. Create an UDS socket address
/// 2. Check if the debug info is correct
#[test]
fn ut_uds_socket_addr_debug_info() {
let sock_addr = libc::sockaddr_un {
sun_family: 1,
sun_path: [2; 108],
};
let addr = SocketAddr::from_parts(sock_addr, 10);
let fmt = format!("{addr:?}");
assert!(fmt.contains("\"\\u{2}\\u{2}\\u{2}\\u{2}\\u{2}\\u{2}\\u{2}\" (pathname)"));
}
}

View File

@ -227,15 +227,6 @@ impl Source for UnixStream {
selector.register(self.inner.as_raw_fd(), token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
selector.reregister(self.inner.as_raw_fd(), token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
selector.deregister(self.inner.as_raw_fd())
}
@ -256,3 +247,41 @@ impl FromRawFd for UnixStream {
UnixStream::from_std(FromRawFd::from_raw_fd(fd))
}
}
#[cfg(test)]
mod test {
use std::net::Shutdown;
use std::os::fd::{FromRawFd, IntoRawFd};
use crate::UnixStream;
/// UT for `UnixStream::pair`
///
/// # Brief
/// 1. Create a pair of UnixStream
/// 2. Check if the peer address is correct
/// 3. Check if the local address is correct
/// 4. Shutdown both UnixStream
#[test]
fn ut_uds_stream_pair() {
let (sender, receiver) = UnixStream::pair().unwrap();
let sender2 = sender.try_clone().unwrap();
let addr = sender2.local_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
let addr = receiver.peer_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
let fd = receiver.into_raw_fd();
let receiver2 = unsafe { UnixStream::from_raw_fd(fd) };
let addr = receiver2.local_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
receiver2.shutdown(Shutdown::Both).unwrap();
sender.shutdown(Shutdown::Both).unwrap()
}
}

View File

@ -57,24 +57,6 @@ impl NetState {
}
}
/// Reregister the socket
pub fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
match self.inner.as_mut() {
Some(state) => selector
.reregister(state.state.clone(), token, interests)
.map(|_| {
state.token = token;
state.interests = interests;
}),
None => Err(io::ErrorKind::NotFound.into()),
}
}
/// Deregister the socket
pub fn deregister(&mut self) -> io::Result<()> {
match self.inner.as_mut() {

View File

@ -67,15 +67,6 @@ impl Selector {
SelectorInner::register(&self.inner, socket, token, interests)
}
pub(crate) fn reregister(
&self,
sock_state: Pin<Arc<Mutex<SockState>>>,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.inner.reregister(sock_state, token, interests)
}
pub(crate) fn clone_cp(&self) -> Arc<CompletionPort> {
self.inner.completion_port.clone()
}

View File

@ -152,15 +152,6 @@ impl Source for TcpListener {
.register(selector, token, interests, self.as_raw_socket())
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.state.reregister(selector, token, interests)
}
fn deregister(&mut self, _selector: &Selector) -> io::Result<()> {
self.state.deregister()
}

View File

@ -327,15 +327,6 @@ impl Source for TcpStream {
.register(selector, token, interests, self.as_raw_socket())
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.state.reregister(selector, token, interests)
}
fn deregister(&mut self, _selector: &Selector) -> io::Result<()> {
self.state.deregister()
}

View File

@ -644,15 +644,6 @@ impl Source for UdpSocket {
.register(selector, token, interests, self.get_fd())
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.state.reregister(selector, token, interests)
}
fn deregister(&mut self, _selector: &Selector) -> io::Result<()> {
self.state.deregister()
}
@ -673,15 +664,6 @@ impl Source for ConnectedUdpSocket {
.register(selector, token, interests, self.get_fd())
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.state.reregister(selector, token, interests)
}
fn deregister(&mut self, _selector: &Selector) -> io::Result<()> {
self.state.deregister()
}

View File

@ -32,3 +32,24 @@ impl Waker {
self.inner.wake()
}
}
#[cfg(test)]
mod test {
/// UT cases for debug info of waker
///
/// # Brief
/// 1. Create a Waker
/// 2. Check its fmt debug info
#[test]
#[cfg(target_os = "linux")]
fn ut_waker_debug_info() {
use crate::{Poll, Token, Waker};
let poll = Poll::new().unwrap();
let waker = Waker::new(&poll, Token::from_usize(0)).unwrap();
let fmt = format!("{:?}", waker);
assert!(fmt.contains("fd:"));
assert!(fmt.contains("read:"));
assert!(fmt.contains("write:"));
}
}

162
ylong_io/tests/tcp_test.rs Normal file
View File

@ -0,0 +1,162 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::io::{IoSlice, IoSliceMut, Read, Write};
use std::net::SocketAddr;
use std::{io, net, thread};
use ylong_io::TcpListener;
/// SDV for TcpStream read and write
///
/// # Brief
/// 1. Create a Tcp server
/// 2. Write `hello` to client
/// 3. Read `hello` from client
#[test]
fn sdv_tcp_server() {
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let server = TcpListener::bind(addr).unwrap();
let addr = server.local_addr().unwrap();
let thread = thread::spawn(move || {
let (mut stream, _) = loop {
let stream = server.accept();
match stream {
Ok(stream) => break stream,
Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue,
Err(e) => panic!("tcp accept failed: {e:?}"),
}
};
let mut ret = stream.write(b"hello");
loop {
match &ret {
Ok(n) => {
assert_eq!(*n, 5);
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
ret = stream.write(b"hello");
}
Err(e) => panic!("tcp write failed: {e:?}"),
}
}
let mut read_stream = stream.try_clone().unwrap();
let mut buf = [0; 5];
loop {
let ret = read_stream.read(&mut buf);
match &ret {
Ok(n) => {
assert_eq!(*n, 5);
assert_eq!(&buf, b"hello");
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue,
Err(e) => panic!("tcp write failed: {e:?}"),
}
}
});
let mut client = loop {
let tcp = net::TcpStream::connect(addr);
match tcp {
Err(_) => continue,
Ok(stream) => break stream,
}
};
let mut buf = [0; 5];
let ret = client.read(&mut buf).unwrap();
assert_eq!(ret, 5);
assert_eq!(&buf, b"hello");
let ret = client.write(&buf).unwrap();
assert_eq!(ret, 5);
thread.join().unwrap();
}
/// SDV for TcpStream read_vectored and write_vectored
///
/// # Brief
/// 1. Create a Tcp server
/// 2. Write `hello` to client
/// 3. Read `hello` from client
#[test]
fn sdv_tcp_server_vectored() {
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let server = TcpListener::bind(addr).unwrap();
let addr = server.local_addr().unwrap();
let thread = thread::spawn(move || {
let (mut stream, _) = loop {
let stream = server.accept();
match stream {
Ok(stream) => break stream,
Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue,
Err(e) => panic!("tcp accept failed: {e:?}"),
}
};
let vec = b"hello";
let slice = IoSlice::new(vec);
let mut ret = stream.write_vectored(&[slice]);
loop {
match &ret {
Ok(n) => {
assert_eq!(*n, 5);
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
ret = stream.write(b"hello");
stream.flush().unwrap();
}
Err(e) => panic!("tcp write failed: {e:?}"),
}
}
let mut read_stream = stream.try_clone().unwrap();
loop {
let mut buf = [0; 5];
let slice = IoSliceMut::new(&mut buf);
let ret = read_stream.read_vectored(&mut [slice]);
match &ret {
Ok(n) => {
assert_eq!(*n, 5);
assert_eq!(&buf, b"hello");
break;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue,
Err(e) => panic!("tcp write failed: {e:?}"),
}
}
});
let mut client = loop {
let tcp = net::TcpStream::connect(addr);
match tcp {
Err(_) => continue,
Ok(stream) => break stream,
}
};
let mut buf = [0; 5];
let ret = client.read(&mut buf).unwrap();
assert_eq!(ret, 5);
assert_eq!(&buf, b"hello");
let ret = client.write(&buf).unwrap();
assert_eq!(ret, 5);
thread.join().unwrap();
}

180
ylong_io/tests/uds_test.rs Normal file
View File

@ -0,0 +1,180 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg(target_os = "linux")]
use std::collections::HashMap;
use std::io;
use std::io::{IoSlice, IoSliceMut, Read, Write};
use std::net::Shutdown;
use std::os::fd::{FromRawFd, IntoRawFd};
use std::str::from_utf8;
use ylong_io::{EventTrait, Events, Interest, Poll, Token, UnixDatagram, UnixListener, UnixStream};
const PATH: &str = "/tmp/io_uds_path1";
const SERVER: Token = Token(0);
/// SDV test for UnixStream.
///
/// # Brief
/// 1. Create a pair of UnixStream.
/// 2. Server sends "Hello client".
/// 3. Client reads the message and sends "Hello server".
/// 4. Server receives the message
#[test]
fn sdv_uds_stream_test() {
let _ = std::fs::remove_file(PATH);
let handle = std::thread::spawn(server);
let mut stream = loop {
if let Ok(stream) = UnixStream::connect(PATH) {
break stream;
}
};
loop {
let mut buffer = [0_u8; 1024];
let slice = IoSliceMut::new(&mut buffer);
std::thread::sleep(std::time::Duration::from_micros(300));
match stream.read_vectored(&mut [slice]) {
Ok(n) => {
assert_eq!(from_utf8(&buffer[0..n]).unwrap(), "Hello client");
break;
}
Err(_) => continue,
}
}
let buf = b"Hello server";
let slice = IoSlice::new(buf);
let n = stream.write_vectored(&[slice]).unwrap();
assert_eq!(n, 12);
handle.join().unwrap().unwrap();
stream.shutdown(Shutdown::Both).unwrap();
std::fs::remove_file(PATH).unwrap();
}
fn server() -> io::Result<()> {
let poll = Poll::new()?;
let mut server = UnixListener::bind(PATH)?;
poll.register(&mut server, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(128);
// Map of `Token` -> `UnixListener`.
let mut connections = HashMap::new();
let mut unique_token = Token(SERVER.0 + 1);
for _ in 0..3 {
poll.poll(&mut events, None)?;
for event in events.iter() {
if SERVER == event.token() {
let (mut stream, _) = server.accept()?;
let token = Token(unique_token.0 + 1);
unique_token = Token(unique_token.0 + 1);
poll.register(&mut stream, token, Interest::READABLE | Interest::WRITABLE)?;
connections.insert(token, stream);
} else {
match connections.get_mut(&event.token()) {
Some(connection) => {
if event.is_writable() {
match connection.write(b"Hello client") {
Err(_) => {
poll.deregister(connection)?;
poll.register(connection, event.token(), Interest::READABLE)?;
break;
}
Ok(_) => {
poll.deregister(connection)?;
poll.register(connection, event.token(), Interest::READABLE)?;
break;
}
}
} else if event.is_readable() {
let mut msg_buf = [0_u8; 100];
match connection.read(&mut msg_buf) {
Ok(0) => poll.deregister(connection)?,
Ok(n) => {
if let Ok(str_buf) = from_utf8(&msg_buf[0..n]) {
assert_eq!(str_buf, "Hello server");
} else {
println!("Received (none UTF-8) data: {:?}", &msg_buf);
}
}
Err(_n) => {
poll.deregister(connection)?;
break;
}
}
}
}
None => break,
}
}
}
}
Ok(())
}
/// SDV test for UnixDatagram.
///
/// # Brief
/// 1. Create a pair of UnixDatagram.
/// 2. Sender sends message first.
/// 3. Receiver receives message.
/// 4. Check if the test results are correct.
#[test]
fn sdv_uds_send_recv() {
let (sender, _) = UnixDatagram::pair().unwrap();
let addr = sender.local_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
let addr = sender.peer_addr().unwrap();
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
let sender2 = sender.try_clone().unwrap();
sender2.shutdown(Shutdown::Write).unwrap();
let n = sender2.send(b"Hello");
assert_eq!(n.unwrap_err().kind(), io::ErrorKind::BrokenPipe);
let (sender, receiver) = UnixDatagram::pair().unwrap();
let n = sender.send(b"Hello").expect("sender send failed");
assert_eq!(n, "Hello".len());
let mut buf = [0; 5];
let ret = sender2.recv(&mut buf);
assert!(ret.is_err());
let mut recv_buf = [0_u8; 12];
let fd = receiver.into_raw_fd();
let receiver = unsafe { UnixDatagram::from_raw_fd(fd) };
let len = loop {
match receiver.recv_from(&mut recv_buf[..]) {
Ok((n, addr)) => {
let fmt = format!("{addr:?}");
assert_eq!(&fmt, "(unnamed)");
break n;
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {}
Err(e) => panic!("{:?}", e),
}
};
let fmt = format!("{receiver:?}");
let expected = format!("fd: FileDesc(OwnedFd {{ fd: {fd} }})");
assert!(fmt.contains(&expected));
assert!(fmt.contains("local: (unnamed), peer: (unnamed)"));
assert_eq!(&recv_buf[..len], b"Hello");
}

View File

@ -168,3 +168,23 @@ required-features = ["time", "multi_instance_runtime"]
name = "ylong_runtime_timer_memory"
path = "examples/ylong_runtime_timer_memory.rs"
required-features = ["time", "multi_instance_runtime"]
[[example]]
name = "ylong_timer_latency"
path = "examples/ylong_timer_latency.rs"
required-features = ["time"]
[[example]]
name = "ylong_runtime_tcp_fd_limit"
path = "examples/ylong_runtime_tcp_fd_limit.rs"
required-features = ["net"]
[[example]]
name = "ylong_runtime_spawn_fail"
path = "examples/ylong_runtime_spawn_fail.rs"
required-features = ["time"]
[[example]]
name = "ylong_timer_out_of_context"
path = "examples/ylong_timer_out_of_context.rs"
required-features = ["time"]

View File

@ -38,7 +38,7 @@ fn main() -> io::Result<()> {
loop {
let start = Instant::now();
match stream.read(&mut recv_buf).await {
Ok(n) if n == 0 => break,
Ok(0) => break,
Ok(n) => {
println!("Receive len: {n}.");
}
@ -48,7 +48,7 @@ fn main() -> io::Result<()> {
}
}
match stream.write(&recv_buf).await {
Ok(n) if n == 0 => {
Ok(0) => {
println!("Server now break");
break;
}

View File

@ -0,0 +1,121 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Benchmarks for bounded mpsc
#![feature(test)]
extern crate core;
mod task_helpers;
extern crate test;
#[macro_export]
macro_rules! tokio_bounded_mpsc {
($runtime: expr, $bench: ident, $num: literal, $loop_num: literal) => {
#[bench]
fn $bench(b: &mut Bencher) {
let runtime = $runtime;
b.iter(black_box(|| {
let (sender, mut receiver) = channel(10);
let mut handlers = vec![];
let handle = runtime.spawn(async move {
for _ in 0..$num * $loop_num {
let res = receiver.recv().await.unwrap();
assert_eq!(res, 1);
}
});
handlers.push(handle);
for _ in 0..$num {
let producer = sender.clone();
let handle = runtime.spawn(async move {
for _ in 0..$loop_num {
producer.send(1).await.unwrap();
}
});
handlers.push(handle);
}
for handle in handlers {
let _ = runtime.block_on(handle).unwrap();
}
}));
}
};
}
#[macro_export]
macro_rules! ylong_bounded_mpsc {
($bench: ident, $num: literal, $loop_num: literal) => {
#[bench]
fn $bench(b: &mut Bencher) {
b.iter(black_box(|| {
let (sender, mut receiver) = bounded_channel(10);
let mut handlers = vec![];
let handle = ylong_runtime::spawn(async move {
for _ in 0..$num * $loop_num {
let res = receiver.recv().await.unwrap();
assert_eq!(res, 1);
}
});
handlers.push(handle);
for _ in 0..$num {
let producer = sender.clone();
let handle = ylong_runtime::spawn(async move {
for _ in 0..$loop_num {
producer.send(1).await.unwrap();
}
});
handlers.push(handle);
}
for handle in handlers {
let _ = ylong_runtime::block_on(handle).unwrap();
}
}));
}
};
}
#[cfg(test)]
mod tokio_bounded_mpsc_bench {
extern crate test;
use std::hint::black_box;
use test::Bencher;
use tokio::sync::mpsc::channel;
pub use crate::task_helpers::tokio_runtime;
tokio_bounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_1_1000, 1, 1000);
tokio_bounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_5_1000, 5, 1000);
tokio_bounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_10_1000, 10, 1000);
tokio_bounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_50_1000, 50, 1000);
}
#[cfg(test)]
mod ylong_bounded_mpsc_bench {
extern crate test;
use std::hint::black_box;
use test::Bencher;
use ylong_runtime::sync::mpsc::bounded_channel;
ylong_bounded_mpsc!(ylong_spawn_blocking_1_1000, 1, 1000);
ylong_bounded_mpsc!(ylong_spawn_blocking_5_1000, 5, 1000);
ylong_bounded_mpsc!(ylong_spawn_blocking_10_1000, 10, 1000);
ylong_bounded_mpsc!(ylong_spawn_blocking_50_1000, 50, 1000);
}

View File

@ -38,8 +38,10 @@ macro_rules! tokio_mutex_task {
for _ in 0..$num {
let mutex1 = mutex.clone();
handlers.push(runtime.spawn(async move {
let mut lock = mutex1.lock().await;
*lock += 1;
for _ in 0..1000 {
let mut lock = mutex1.lock().await;
*lock += 1;
}
}));
}
@ -48,7 +50,7 @@ macro_rules! tokio_mutex_task {
}
let _res = runtime.block_on(async {
let n = mutex.lock().await;
assert_eq!(*n, $num);
assert_eq!(*n, $num * 1000);
});
}));
}
@ -66,8 +68,10 @@ macro_rules! ylong_mutex_task {
for _ in 0..$num {
let mutex1 = mutex.clone();
handlers.push(ylong_runtime::spawn(async move {
let mut lock = mutex1.lock().await;
*lock += 1;
for _ in 0..1000 {
let mut lock = mutex1.lock().await;
*lock += 1;
}
}));
}
@ -76,7 +80,7 @@ macro_rules! ylong_mutex_task {
}
let _res = ylong_runtime::block_on(async {
let n = mutex.lock().await;
assert_eq!(*n, $num);
assert_eq!(*n, $num * 1000);
});
}));
}

View File

@ -72,7 +72,7 @@ macro_rules! ylong_process_task {
}
#[cfg(test)]
mod uds_bench {
mod process_bench {
extern crate test;
use std::hint::black_box;

View File

@ -0,0 +1,92 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Benchmarks for spawn_blocking.
#![feature(test)]
extern crate core;
mod task_helpers;
extern crate test;
#[macro_export]
macro_rules! tokio_spawn_blocking_task {
($runtime: expr, $bench: ident, $num: literal, $upper: literal) => {
#[bench]
fn $bench(b: &mut Bencher) {
let runtime = $runtime;
b.iter(black_box(|| {
let mut handlers = Vec::with_capacity($num);
for _ in 0..$num {
handlers.push(runtime.spawn_blocking(|| {
fibbo($upper);
}));
}
for handler in handlers {
let _ = runtime.block_on(handler).unwrap();
}
}));
}
};
}
#[macro_export]
macro_rules! ylong_spawn_blocking_task {
($bench: ident, $num: literal, $upper: literal) => {
#[bench]
fn $bench(b: &mut Bencher) {
b.iter(black_box(|| {
let mut handlers = Vec::with_capacity($num);
for _ in 0..$num {
handlers.push(ylong_runtime::spawn_blocking(|| {
fibbo($upper);
}));
}
for handler in handlers {
let _ = ylong_runtime::block_on(handler).unwrap();
}
}));
}
};
}
#[cfg(test)]
mod tokio_spawn_blocking_bench {
extern crate test;
use std::hint::black_box;
use test::Bencher;
pub use crate::task_helpers::{fibbo, tokio_runtime};
tokio_spawn_blocking_task!(tokio_runtime(), tokio_blocking_task_10_15, 10, 15);
tokio_spawn_blocking_task!(tokio_runtime(), tokio_blocking_task_120_15, 100, 15);
}
#[cfg(test)]
mod ylong_spawn_blocking_bench {
extern crate test;
use std::hint::black_box;
use test::Bencher;
pub use crate::task_helpers::fibbo;
ylong_spawn_blocking_task!(ylong_blocking_task_10_15, 10, 15);
ylong_spawn_blocking_task!(ylong_blocking_task_100_15, 100, 15);
}

View File

@ -90,7 +90,7 @@ macro_rules! ylong_task_creation_local {
}
#[cfg(test)]
mod tcp_bench {
mod task_creation {
extern crate test;
use std::hint::black_box;

View File

@ -0,0 +1,119 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Benchmarks for unbounded mpsc
#![feature(test)]
extern crate core;
mod task_helpers;
extern crate test;
#[macro_export]
macro_rules! tokio_unbounded_mpsc {
($runtime: expr, $bench: ident, $num: literal, $loop_num: literal) => {
#[bench]
fn $bench(b: &mut Bencher) {
let runtime = $runtime;
b.iter(black_box(|| {
let (sender, mut receiver) = unbounded_channel();
let mut handlers = vec![];
let handle = runtime.spawn(async move {
for _ in 0..$num * $loop_num {
let res = receiver.recv().await.unwrap();
assert_eq!(res, 1);
}
});
handlers.push(handle);
for _ in 0..$num {
let producer = sender.clone();
let handle = runtime.spawn(async move {
for _ in 0..$loop_num {
producer.send(1).unwrap();
}
});
handlers.push(handle);
}
for handle in handlers {
let _ = runtime.block_on(handle).unwrap();
}
}));
}
};
}
#[macro_export]
macro_rules! ylong_unbounded_mpsc {
($bench: ident, $num: literal, $loop_num: literal) => {
#[bench]
fn $bench(b: &mut Bencher) {
b.iter(black_box(|| {
let (sender, mut receiver) = unbounded_channel();
let mut handlers = vec![];
let handle = ylong_runtime::spawn(async move {
for _ in 0..$num * $loop_num {
let res = receiver.recv().await.unwrap();
assert_eq!(res, 1);
}
});
handlers.push(handle);
for _ in 0..$num {
let producer = sender.clone();
let handle = ylong_runtime::spawn(async move {
for _ in 0..$loop_num {
producer.send(1).unwrap();
}
});
handlers.push(handle);
}
for handle in handlers {
let _ = ylong_runtime::block_on(handle).unwrap();
}
}));
}
};
}
#[cfg(test)]
mod tokio_unbounded_mpsc_bench {
extern crate test;
use std::hint::black_box;
use test::Bencher;
use tokio::sync::mpsc::unbounded_channel;
pub use crate::task_helpers::tokio_runtime;
tokio_unbounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_1_1000, 1, 1000);
tokio_unbounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_5_1000, 5, 1000);
tokio_unbounded_mpsc!(tokio_runtime(), tokio_spawn_blocking_10_1000, 10, 1000);
}
#[cfg(test)]
mod ylong_unbounded_mpsc_bench {
extern crate test;
use std::hint::black_box;
use test::Bencher;
use ylong_runtime::sync::mpsc::unbounded_channel;
ylong_unbounded_mpsc!(ylong_spawn_blocking_1_1000, 1, 1000);
ylong_unbounded_mpsc!(ylong_spawn_blocking_5_1000, 5, 1000);
ylong_unbounded_mpsc!(ylong_spawn_blocking_10_1000, 10, 1000);
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A test for Runtime initialization failure, this should panic
use std::thread;
use std::time::Duration;
fn main() {
let mut vec = vec![];
let mut count = 0;
for _ in 0..16326 {
count += 1;
println!("{count}");
let handle = thread::spawn(move || {
thread::sleep(Duration::from_secs(1000));
});
vec.push(handle);
}
println!("start to initialize the runtime");
let handle = ylong_runtime::spawn(async move {
println!("runtime initialized");
});
ylong_runtime::block_on(handle).unwrap();
for handle in vec {
handle.join().unwrap();
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This example simulates the situation of spawn failure due to insufficient
//! memory
use std::time::Duration;
fn main() {
// loop until the program gets killed automatically
loop {
let _handle = ylong_runtime::spawn(async move {
let buf = vec![0; 2000000];
ylong_runtime::time::sleep(Duration::from_secs(100)).await;
assert_eq!(buf, [0; 2000000]);
});
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Spawn a task which will panic, the runtime should catch the panic
fn main() {
let handle = ylong_runtime::spawn(async move {
panic!("panic");
});
let err = ylong_runtime::block_on(handle).unwrap_err();
assert_eq!(err.kind(), ylong_runtime::error::ErrorKind::Panic);
println!("process exit normally");
}

View File

@ -0,0 +1,41 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This example simulates the situation of task starvation by spawning long
//! tasks that have no await point
use std::thread;
use std::time::Duration;
use tokio::time::Instant;
fn main() {
// initialize the runtime with only 1 worker thread
ylong_runtime::builder::RuntimeBuilder::new_multi_thread()
.worker_num(1)
.build_global()
.unwrap();
let instant = Instant::now();
let _long_hold = ylong_runtime::spawn(async move {
thread::sleep(Duration::from_secs(5));
});
let handle = ylong_runtime::spawn(async move {
let a = 0;
assert_eq!(a, 0);
});
ylong_runtime::block_on(handle).unwrap();
let time_cost = instant.elapsed().as_secs();
println!("time cost: {}", time_cost);
assert!(time_cost >= 5);
}

View File

@ -0,0 +1,33 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A test for FD overflow
use ylong_runtime::net::TcpListener;
fn main() {
let handle = ylong_runtime::spawn(async move {
let mut vec = vec![];
loop {
let tcp = TcpListener::bind("127.0.0.1:0").await;
match tcp {
Err(e) => {
println!("err: {}", e.kind());
return;
}
Ok(listener) => vec.push(listener),
}
}
});
ylong_runtime::block_on(handle).unwrap();
}

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Sleep usage in ylong_runtime.
//! A test for sleep latency in ylong_runtime.
use std::time::{Duration, Instant};

View File

@ -0,0 +1,29 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This example simulates the scenario where a worker thread gets its stack
//! overflowed
fn main() {
ylong_runtime::builder::RuntimeBuilder::new_multi_thread()
.worker_stack_size(1)
.build_global()
.unwrap();
let handle = ylong_runtime::spawn(async move {
let a = [0; 20000];
assert_eq!(a, [0; 20000]);
});
ylong_runtime::block_on(handle).unwrap();
}

View File

@ -0,0 +1,61 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Sleep latency in ylong_runtime.
use std::time::{Duration, Instant};
fn main() {
let mut handlers = vec![];
for _ in 0..1000 {
let handle = ylong_runtime::spawn(async move {
let duration = Duration::from_millis(100);
let start = Instant::now();
ylong_runtime::time::sleep(duration).await;
let since = start.elapsed();
let latency = since.saturating_sub(duration).as_millis();
println!("since is {}", since.as_millis());
latency
});
handlers.push(handle);
}
let mut average = 0;
for handler in handlers {
let time = ylong_runtime::block_on(handler).unwrap();
average += time;
}
average /= 1000;
println!("ylong average latency is {} millisecond", average);
let runtime = tokio::runtime::Runtime::new().unwrap();
let mut handlers = vec![];
for _ in 0..1000 {
let handle = runtime.spawn(async move {
let duration = Duration::from_millis(100);
let start = Instant::now();
tokio::time::sleep(duration).await;
let since = start.elapsed();
let latency = since.saturating_sub(duration).as_millis();
println!("since is {}", since.as_millis());
latency
});
handlers.push(handle);
}
let mut average = 0;
for handler in handlers {
let time = runtime.block_on(handler).unwrap();
average += time;
}
average /= 1000;
println!("average latency is {} millisecond", average);
}

View File

@ -0,0 +1,23 @@
// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This example simulates the scenario of calling a timer related api outside
//! the runtime's context
use std::time::Duration;
fn main() {
// this will cause panic because the runtime cannot register the timer on the
// main thread
ylong_runtime::time::sleep(Duration::from_secs(1));
}

View File

@ -597,10 +597,6 @@ pub(crate) mod test {
type Output = usize;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.total > self.value {
// unsafe {
// Pin::get_unchecked_mut(self).value += 1;
//}
self.get_mut().value += 1;
cx.waker().wake_by_ref();
Poll::Pending

View File

@ -728,6 +728,8 @@ impl DirEntry {
#[cfg(test)]
mod test {
use std::io;
use crate::fs::{
canonicalize, copy, create_dir, hard_link, metadata, read, read_dir, read_link,
read_to_string, remove_dir_all, remove_file, rename, set_permissions, symlink_metadata,
@ -752,6 +754,20 @@ mod test {
});
}
/// UT test for creating
///
/// # Brief
///
/// 1. Create a new directory whose parent doesn't exist.
/// 2. Check if the returned error is NotFound.
#[test]
fn ut_fs_create_dir_fail() {
crate::block_on(async {
let ret = create_dir("non-existed_parent/non_existed_child").await;
assert_eq!(ret.unwrap_err().kind(), io::ErrorKind::NotFound);
})
}
/// UT test for `rename`
///
/// # Brief

View File

@ -568,6 +568,7 @@ impl FileInner {
#[cfg(test)]
mod test {
use std::io;
use std::io::SeekFrom;
use crate::fs::async_file::DEFAULT_BUF_LIMIT;
@ -754,4 +755,26 @@ mod test {
crate::block_on(handle).unwrap();
std::fs::remove_file(file_path).unwrap();
}
use std::fmt::{Debug, Formatter};
impl Debug for File {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.file.fmt(f)
}
}
/// UT for opening an non-existed file
///
/// # Brief
/// 1. Open a file that does not exist
/// 2. Check if the returned error is NotFound
#[test]
fn ut_fs_open_fail() {
let handle = crate::spawn(async move {
let file = File::open("file_not_exist").await;
assert_eq!(file.unwrap_err().kind(), io::ErrorKind::NotFound);
});
crate::block_on(handle).unwrap();
}
}

View File

@ -92,6 +92,7 @@ impl<'a, R: ?Sized> ReadToEndTask<'a, R> {
}
}
}
const PROBE_SIZE: usize = 32;
fn poll_read_to_end<R: AsyncRead + Unpin>(
buf: &mut Vec<u8>,
@ -100,9 +101,10 @@ fn poll_read_to_end<R: AsyncRead + Unpin>(
cx: &mut Context<'_>,
) -> Poll<io::Result<usize>> {
loop {
// Allocate 32 bytes every time, if the remaining capacity is larger than 32
// Allocate spaces to read, if the remaining capacity is larger than 32
// bytes, this will do nothing.
buf.reserve(32);
buf.try_reserve(PROBE_SIZE)
.map_err(|_| io::ErrorKind::OutOfMemory)?;
let len = buf.len();
let mut read_buf = ReadBuf::uninit(unsafe {
from_raw_parts_mut(buf.as_mut_ptr().cast::<MaybeUninit<u8>>(), buf.capacity())
@ -113,9 +115,7 @@ fn poll_read_to_end<R: AsyncRead + Unpin>(
let poll = Pin::new(&mut reader).poll_read(cx, &mut read_buf);
let new_len = read_buf.filled_len();
match poll {
Poll::Pending => {
return Poll::Pending;
}
Poll::Pending => return Poll::Pending,
Poll::Ready(Ok(())) if (new_len - len) == 0 => {
return Poll::Ready(Ok(mem::replace(read_len, 0)))
}

View File

@ -12,7 +12,6 @@
// limitations under the License.
#![warn(missing_docs)]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
//! # ylong_runtime
//! A runtime for writing IO-bounded and CPU-bounded applications.

View File

@ -15,7 +15,6 @@ macro_rules! cfg_net {
($($item:item)*) => {
$(
#[cfg(feature = "net")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "net")))]
$item
)*
}
@ -25,7 +24,6 @@ macro_rules! cfg_time {
($($item:item)*) => {
$(
#[cfg(feature = "time")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "time")))]
$item
)*
}
@ -35,7 +33,6 @@ macro_rules! cfg_ffrt {
($($item:item)*) => {
$(
#[cfg(feature = "ffrt")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "ffrt")))]
$item
)*
}
@ -45,7 +42,6 @@ macro_rules! cfg_signal {
($($item:item)*) => {
$(
#[cfg(feature = "signal")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "signal")))]
$item
)*
}
@ -56,7 +52,6 @@ macro_rules! cfg_process {
($($item:item)*) => {
$(
#[cfg(feature = "process")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "process")))]
$item
)*
}
@ -66,7 +61,6 @@ macro_rules! cfg_sync {
($($item:item)*) => {
$(
#[cfg(feature = "sync")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "sync")))]
$item
)*
}
@ -76,7 +70,6 @@ macro_rules! cfg_macros {
($($item:item)*) => {
$(
#[cfg(feature = "macros")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))]
$item
)*
}
@ -86,7 +79,6 @@ macro_rules! cfg_fs {
($($item:item)*) => {
$(
#[cfg(feature = "fs")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))]
$item
)*
}
@ -120,7 +112,7 @@ macro_rules! cfg_metrics {
}
}
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", any(feature = "net", feature = "process")))]
macro_rules! syscall {
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
let res = unsafe { libc::$fn($($arg, )*) };

View File

@ -13,26 +13,21 @@
use std::fmt::{Debug, Formatter};
use std::io;
use std::io::{Read, Write};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::sync::Arc;
use std::task::{Context, Poll};
#[cfg(target_os = "linux")]
use libc::{gid_t, uid_t};
use ylong_io::{Interest, Source};
use crate::executor::Handle;
use crate::io::poll_ready;
use crate::net::ScheduleIO;
use crate::io::{poll_ready, ReadBuf};
use crate::net::{ReadyEvent, ScheduleIO};
use crate::util::slab::Ref;
cfg_net!(
use std::task::{Context, Poll};
use std::mem::MaybeUninit;
use crate::io::ReadBuf;
use crate::net::ReadyEvent;
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.
pub(crate) struct AsyncSource<E: Source> {

View File

@ -45,7 +45,6 @@ const DRIVER_TICK_INIT: u8 = 0;
// | reserved | generation | address |
// |----------|------------|---------|
// | 1 bit | 7 bits | 24 bits |
// const RESERVED: Mask = Mask::new(1, 31);
const GENERATION: Mask = Mask::new(7, 24);
const ADDRESS: Mask = Mask::new(24, 0);

View File

@ -25,14 +25,11 @@ pub(crate) mod driver;
pub(crate) mod ready;
pub(crate) mod schedule_io;
cfg_net! {
pub use sys::{TcpListener, TcpStream};
pub use sys::{UdpSocket, ConnectedUdpSocket};
pub use sys::{SplitReadHalf, SplitWriteHalf, BorrowReadHalf, BorrowWriteHalf};
#[cfg(unix)]
pub use sys::{UnixListener, UnixStream, UnixDatagram};
pub use sys::ToSocketAddrs;
}
#[cfg(not(feature = "ffrt"))]
pub(crate) use driver::IoDriver;
pub use sys::{
BorrowReadHalf, BorrowWriteHalf, ConnectedUdpSocket, SplitReadHalf, SplitWriteHalf,
TcpListener, TcpStream, ToSocketAddrs, UdpSocket,
};
#[cfg(unix)]
pub use sys::{UnixDatagram, UnixListener, UnixStream};

View File

@ -213,303 +213,310 @@ 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
#[test]
#[cfg(feature = "tcp")]
fn ut_ready_from_event() {
ut_ready_from_event_01();
ut_ready_from_event_02();
ut_ready_from_event_03();
ut_ready_from_event_04();
#[cfg(test)]
mod test {
use ylong_io::Interest;
// Readable
fn ut_ready_from_event_01() {
let mut event = libc::epoll_event {
events: 0b00,
u64: 0,
};
event.events |= libc::EPOLLIN as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b01);
use crate::net::{Ready, ReadyEvent};
// @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(all(not(feature = "ffrt"), target_os = "linux"))]
fn ut_ready_from_event() {
ut_ready_from_event_01();
ut_ready_from_event_02();
ut_ready_from_event_03();
ut_ready_from_event_04();
// Readable
fn ut_ready_from_event_01() {
let mut event = libc::epoll_event {
events: 0b00,
u64: 0,
};
event.events |= libc::EPOLLIN as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b01);
}
// Writable
fn ut_ready_from_event_02() {
let mut event = libc::epoll_event {
events: 0b00,
u64: 0,
};
event.events |= libc::EPOLLOUT as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b10);
}
// Read off
fn ut_ready_from_event_03() {
let mut event = libc::epoll_event {
events: 0b00,
u64: 0,
};
event.events |= (libc::EPOLLIN | libc::EPOLLRDHUP) as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b101);
}
// Write Off
fn ut_ready_from_event_04() {
let mut event = libc::epoll_event {
events: 0x00,
u64: 0,
};
event.events |= (libc::EPOLLOUT | libc::EPOLLERR) as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b1010);
}
}
// Writable
fn ut_ready_from_event_02() {
let mut event = libc::epoll_event {
events: 0b00,
u64: 0,
};
event.events |= libc::EPOLLOUT as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b10);
/// 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);
}
// Read off
fn ut_ready_from_event_03() {
let mut event = libc::epoll_event {
events: 0b00,
u64: 0,
};
event.events |= (libc::EPOLLIN | libc::EPOLLRDHUP) as u32;
let ready = Ready::from_event(&event);
assert_eq!(ready.0, 0b101);
/// 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);
assert!(ready.is_empty());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_empty());
}
// Write Off
fn ut_ready_from_event_04() {
let mut event = libc::epoll_event {
events: 0x00,
u64: 0,
};
event.events |= (libc::EPOLLOUT | libc::EPOLLERR) as u32;
let ready = Ready::from_event(&event);
/// 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);
assert!(ready.is_readable());
let ready = Ready::from_usize(0x02);
assert!(!ready.is_readable());
}
/// 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);
assert!(ready.is_writable());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_writable());
}
/// 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);
assert!(ready.is_read_closed());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_read_closed());
}
/// 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);
assert!(ready.is_write_closed());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_write_closed());
}
/// 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);
}
/// 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;
let ready = Ready::from_interest(interest);
assert_eq!(ready.as_usize(), 0b101);
let interest = Interest::WRITABLE;
let ready = Ready::from_interest(interest);
assert_eq!(ready.as_usize(), 0b1010);
}
/// 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;
let ready = Ready::from_usize(0b1111);
let res = ready.intersection(interest);
assert_eq!(res.0, 0b0101);
}
/// 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;
let ready = Ready::from_usize(0b1111);
assert!(ready.satisfies(interest));
let ready = Ready::from_usize(0b0000);
assert!(!ready.satisfies(interest));
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
let ready3 = ready1 | ready2;
assert_eq!(ready3.0, 0b1111);
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
ready1 |= ready2;
assert_eq!(ready1.0, 0b1111);
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
let ready = ready1 & ready2;
assert_eq!(ready.0, 0b0000);
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
let ready = ready1 - ready2;
assert_eq!(ready.0, 0b1010);
}
}
/// 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);
}
/// 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);
assert!(ready.is_empty());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_empty());
}
/// 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);
assert!(ready.is_readable());
let ready = Ready::from_usize(0x02);
assert!(!ready.is_readable());
}
/// 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);
assert!(ready.is_writable());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_writable());
}
/// 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);
assert!(ready.is_read_closed());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_read_closed());
}
/// 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);
assert!(ready.is_write_closed());
let ready = Ready::from_usize(0x01);
assert!(!ready.is_write_closed());
}
/// 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);
}
/// 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;
let ready = Ready::from_interest(interest);
assert_eq!(ready.as_usize(), 0b101);
let interest = Interest::WRITABLE;
let ready = Ready::from_interest(interest);
assert_eq!(ready.as_usize(), 0b1010);
}
/// 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;
let ready = Ready::from_usize(0b1111);
let res = ready.intersection(interest);
assert_eq!(res.0, 0b0101);
}
/// 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;
let ready = Ready::from_usize(0b1111);
assert!(ready.satisfies(interest));
let ready = Ready::from_usize(0b0000);
assert!(!ready.satisfies(interest));
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
let ready3 = ready1 | ready2;
assert_eq!(ready3.0, 0b1111);
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
ready1 |= ready2;
assert_eq!(ready1.0, 0b1111);
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
let ready = ready1 & ready2;
assert_eq!(ready.0, 0b0000);
}
/// 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);
let ready2 = Ready::from_usize(0b0101);
let ready = ready1 - ready2;
assert_eq!(ready.0, 0b1010);
}
/// 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));
assert_eq!(ready_event.tick, 1u8);
assert_eq!(ready_event.ready.0, 0b0101);
}
/// 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);
}
/// 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));
assert_eq!(ready_event.get_ready().0, 0b0101);
/// 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));
assert_eq!(ready_event.tick, 1u8);
assert_eq!(ready_event.ready.0, 0b0101);
}
/// 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);
}
/// 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));
assert_eq!(ready_event.get_ready().0, 0b0101);
}
}

View File

@ -241,7 +241,6 @@ use std::os::fd::{AsRawFd, RawFd};
#[cfg(target_os = "linux")]
use libc::{gid_t, uid_t};
#[cfg(unix)]
use ylong_io::Source;

View File

@ -651,7 +651,6 @@ use std::os::fd::{AsRawFd, RawFd};
#[cfg(target_os = "linux")]
use libc::{gid_t, uid_t};
#[cfg(unix)]
use ylong_io::Source;

View File

@ -159,15 +159,6 @@ impl Source for PtyInner {
SourceFd(&self.get_fd()).register(selector, token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
SourceFd(&self.get_fd()).reregister(selector, token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
SourceFd(&self.get_fd()).deregister(selector)
}

View File

@ -73,15 +73,6 @@ impl Source for Pipe {
SourceFd(&self.as_raw_fd()).register(selector, token, interests)
}
fn reregister(
&mut self,
selector: &Selector,
token: Token,
interests: Interest,
) -> io::Result<()> {
SourceFd(&self.as_raw_fd()).reregister(selector, token, interests)
}
fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
SourceFd(&self.as_raw_fd()).deregister(selector)
}

View File

@ -69,6 +69,7 @@ where
/// Gets global default executor, spawns async tasks by the task builder, and
/// returns.
#[inline]
pub(crate) fn spawn_async<T, R>(builder: &TaskBuilder, task: T) -> JoinHandle<R>
where
T: Future<Output = R>,

View File

@ -123,6 +123,7 @@ cfg_time! {
}
#[cfg(test)]
#[cfg(feature = "time")]
mod test {
use crate::sync::error::{RecvError, RecvTimeoutError, TryRecvError};

View File

@ -66,8 +66,6 @@ where
RawWaker::new(ptr, raw_waker_ref)
}
/// Warps std::task::{RawWaker, RawWakerVTable, Waker} info, implements task
/// notify and schedule
pub(crate) struct WakerRefHeader<'a> {
waker: ManuallyDrop<Waker>,
_field: PhantomData<&'a Header>,

View File

@ -407,25 +407,13 @@ impl<T> Slots<T> {
// Get the first address of the current `page`
let base = &self.slots[0] as *const _ as usize;
// The case where the first address is 0 and `page` is unallocated
// if base == 0 {
// logerr!("`page` unallocated");
// }
// Get the current `slot` address
let slot = slot as usize;
// Get `Vec` internal element size
let width = mem::size_of::<Slot<T>>();
// if slot < base {
// logerr!("wrong address");
// }
// Get the current `idx`
(slot - base) / width
// if idx >= self.slots.len() as usize {
// logerr!("idx out of range");
// }
}
}

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// cfg gn_test is used to isolate the test compiling on OHOS
#![allow(unexpected_cfgs)]
#![cfg(gn_test)]
mod async_buf_read;

View File

@ -18,6 +18,38 @@ use ylong_runtime::net::{TcpListener, TcpStream};
const ADDR: &str = "127.0.0.1:0";
/// SDV test cases for `TcpStream`.
///
/// # Brief
/// 1. Bind `TcpListener` and wait for `accept()` using an ipv6 address.
/// 2. After accept, write `hello`.
/// 2. `TcpStream` connect to listener and try to read buf.
/// 4. Check if the result is correct.
#[test]
fn sdv_tcp_ipv6_connect() {
let handle = ylong_runtime::spawn(async move {
let listener = TcpListener::bind("[::1]:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let handle = ylong_runtime::spawn(async move {
let mut stream = TcpStream::connect(addr).await;
while stream.is_err() {
stream = TcpStream::connect(addr).await;
}
let mut stream = stream.unwrap();
let mut buf = vec![0; 5];
let _ = stream.read(&mut buf).await;
assert_eq!(buf, b"hello");
});
let (mut stream, _) = listener.accept().await.unwrap();
stream.write(b"hello").await.unwrap();
handle.await.unwrap();
});
ylong_runtime::block_on(handle).unwrap();
}
/// SDV test cases for `TcpListener`.
///
/// # Brief
@ -378,7 +410,7 @@ fn sdv_tcp_split_owned_half() {
/// context
/// 3. Drops the streams and it should not cause Panic
#[test]
#[cfg(not(feature = "ffrt"))]
#[cfg(all(not(feature = "ffrt"), feature = "sync"))]
fn sdv_tcp_drop_out_context() {
let (tx, rx) = ylong_runtime::sync::oneshot::channel();
let handle = ylong_runtime::spawn(async move {
@ -448,7 +480,13 @@ fn sdv_tcp_cancel() {
});
let client = ylong_runtime::spawn(async {
let addr = rx.await.unwrap();
let addr = match rx.await {
Ok(addr) => addr,
Err(_) => {
sleep(Duration::from_secs(100000)).await;
return;
}
};
let mut tcp = TcpStream::connect(addr).await;
while tcp.is_err() {
tcp = TcpStream::connect(addr).await;
@ -503,3 +541,56 @@ fn sdv_tcp_cancel() {
ylong_runtime::block_on(server).unwrap();
ylong_runtime::block_on(client).unwrap();
}
/// SDV case for binding on the same port twice
///
/// # Breif
/// 1. Create a Tcp connection
/// 2. Close the client side before any data transmission
/// 3. Check if the server side gets an UnexpectedEof error
#[test]
#[cfg(feature = "time")]
fn sdv_tcp_unexpected_eof() {
use std::sync::Arc;
let val = Arc::new(std::sync::Mutex::new(0));
let val2 = val.clone();
let (tx, rx) = ylong_runtime::sync::oneshot::channel();
let handle = ylong_runtime::spawn(async move {
let tcp = TcpListener::bind(ADDR).await.unwrap();
let addr = tcp.local_addr().unwrap();
tx.send(addr).unwrap();
let (mut stream, _) = tcp.accept().await.unwrap();
let mut buf = [0; 10];
let ret = stream.read_exact(&mut buf).await.unwrap_err();
assert_eq!(ret.kind(), std::io::ErrorKind::UnexpectedEof);
});
let client = ylong_runtime::spawn(async move {
let addr = rx.await.unwrap();
let mut tcp = TcpStream::connect(addr).await;
while tcp.is_err() {
tcp = TcpStream::connect(addr).await;
}
let mut tcp = tcp.unwrap();
{
let mut guard = val2.lock().unwrap();
*guard = 1;
}
ylong_runtime::time::sleep(std::time::Duration::from_secs(10)).await;
let buf = [3; 10];
tcp.write_all(&buf).await.unwrap();
});
loop {
let guard = val.lock().unwrap();
if *guard != 0 {
break;
}
drop(guard);
std::thread::sleep(std::time::Duration::from_millis(10));
}
client.cancel();
ylong_runtime::block_on(handle).unwrap();
}

View File

@ -128,3 +128,98 @@ impl Signal {
Ok(())
}
}
#[cfg(test)]
mod test {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use crate::common::Signal;
/// UT for signal creation
///
/// # Brief
/// 1. Create a new signal
/// 2. Check if the signal is initialized correctly
#[test]
#[cfg(target_os = "linux")]
fn ut_signal_new() {
let handler = |_info: &libc::siginfo_t| {
let a = 1;
assert_eq!(a, 1);
};
let handler = Arc::new(handler);
let signal = Signal::new(libc::SIGINT, handler).unwrap();
assert!(signal.new_act.is_some());
let signal2 = signal.clone();
drop(signal);
assert!(signal2.new_act.is_some());
}
/// UT for signal register and deregister
///
/// # Brief
/// 1. Registers two different signals with actions that increment two
/// different atomic usize.
/// 2. Manually raises the two signals, checks if the registered action
/// behave correctly.
/// 3. Deregisters the action of the two signals
/// 4. Registers the same action for one of the signals again
/// 5. Manually raises the signal, checks if the registered action behave
/// correctly
/// 6. Deregisters both signal's handler hook, checks if the return is ok.
#[test]
fn ut_signal_register() {
let value = Arc::new(AtomicUsize::new(0));
let value_cpy = value.clone();
let value2 = Arc::new(AtomicUsize::new(10));
let value2_cpy = value2.clone();
let value2_cpy2 = value2.clone();
let res = unsafe {
Signal::register_action(libc::SIGINT, move |_| {
value_cpy.fetch_add(1, Ordering::Relaxed);
})
};
assert!(res.is_ok());
let res = unsafe {
Signal::register_action(libc::SIGTERM, move |_| {
value2_cpy.fetch_add(10, Ordering::Relaxed);
})
};
assert!(res.is_ok());
assert_eq!(value.load(Ordering::Relaxed), 0);
unsafe { libc::raise(libc::SIGINT) };
assert_eq!(value.load(Ordering::Relaxed), 1);
assert_eq!(value2.load(Ordering::Relaxed), 10);
unsafe { libc::raise(libc::SIGTERM) };
assert_eq!(value.load(Ordering::Relaxed), 1);
assert_eq!(value2.load(Ordering::Relaxed), 20);
let res = Signal::deregister_action(libc::SIGTERM);
assert!(res.is_ok());
Signal::deregister_action(libc::SIGINT).unwrap();
let res = unsafe {
Signal::register_action(libc::SIGTERM, move |_| {
value2_cpy2.fetch_add(20, Ordering::Relaxed);
})
};
assert!(res.is_ok());
unsafe { libc::raise(libc::SIGTERM) };
assert_eq!(value2.load(Ordering::Relaxed), 40);
let res = Signal::deregister_hook(libc::SIGTERM);
assert!(res.is_ok());
let res = Signal::deregister_hook(libc::SIGINT);
assert!(res.is_ok());
}
}

View File

@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// cfg gn_test is used to isolate the test compiling on OHOS
#![allow(unexpected_cfgs)]
#![cfg(gn_test)]
mod signal;