mirror of
https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime
synced 2024-10-06 19:43:53 +00:00
benchmark补全
Signed-off-by: MingyuChen <chenmingyu4@huawei.com>
This commit is contained in:
parent
c22b209a74
commit
fef055fd82
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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:"));
|
||||
}
|
||||
}
|
||||
|
@ -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<()>;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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("));
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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)"));
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
162
ylong_io/tests/tcp_test.rs
Normal 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
180
ylong_io/tests/uds_test.rs
Normal 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");
|
||||
}
|
@ -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"]
|
@ -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;
|
||||
}
|
||||
|
121
ylong_runtime/benches/ylong_tokio_bounded_mpsc.rs
Normal file
121
ylong_runtime/benches/ylong_tokio_bounded_mpsc.rs
Normal 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);
|
||||
}
|
@ -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);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
@ -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;
|
||||
|
92
ylong_runtime/benches/ylong_tokio_spawn_blocking.rs
Normal file
92
ylong_runtime/benches/ylong_tokio_spawn_blocking.rs
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
119
ylong_runtime/benches/ylong_tokio_unbounded_mpsc.rs
Normal file
119
ylong_runtime/benches/ylong_tokio_unbounded_mpsc.rs
Normal 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);
|
||||
}
|
40
ylong_runtime/examples/ylong_runtime_create_thread_fail.rs
Normal file
40
ylong_runtime/examples/ylong_runtime_create_thread_fail.rs
Normal 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();
|
||||
}
|
||||
}
|
28
ylong_runtime/examples/ylong_runtime_spawn_fail.rs
Normal file
28
ylong_runtime/examples/ylong_runtime_spawn_fail.rs
Normal 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]);
|
||||
});
|
||||
}
|
||||
}
|
23
ylong_runtime/examples/ylong_runtime_spawn_panic.rs
Normal file
23
ylong_runtime/examples/ylong_runtime_spawn_panic.rs
Normal 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");
|
||||
}
|
41
ylong_runtime/examples/ylong_runtime_task_starvation.rs
Normal file
41
ylong_runtime/examples/ylong_runtime_task_starvation.rs
Normal 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);
|
||||
}
|
33
ylong_runtime/examples/ylong_runtime_tcp_fd_limit.rs
Normal file
33
ylong_runtime/examples/ylong_runtime_tcp_fd_limit.rs
Normal 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();
|
||||
}
|
@ -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};
|
||||
|
||||
|
@ -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();
|
||||
}
|
61
ylong_runtime/examples/ylong_timer_latency.rs
Normal file
61
ylong_runtime/examples/ylong_timer_latency.rs
Normal 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);
|
||||
}
|
23
ylong_runtime/examples/ylong_timer_out_of_context.rs
Normal file
23
ylong_runtime/examples/ylong_timer_out_of_context.rs
Normal 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));
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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, )*) };
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -123,6 +123,7 @@ cfg_time! {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "time")]
|
||||
mod test {
|
||||
use crate::sync::error::{RecvError, RecvTimeoutError, TryRecvError};
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -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");
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user