Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(net): poll (needs further tests) #751

Closed
wants to merge 11 commits into from
65 changes: 65 additions & 0 deletions kernel/src/net/event_poll/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::{
cell::Cell,
any::Any,
fmt::Debug,
sync::atomic::{AtomicBool, Ordering},
Expand Down Expand Up @@ -872,3 +873,67 @@ bitflags! {
const POLLFREE = 0x4000;
}
}

#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
struct CPollfd {
fd: i32,
events: i16,
revents: i16,
}

#[derive(Debug, Clone)]
pub struct Pollfd {
fd: Option<i32>,
events: EPollEventType,
revents: Cell<EPollEventType>,
}

impl Pollfd {
pub fn new(fd: Option<i32>, events: EPollEventType) -> Self {
let revents = Cell::new(EPollEventType::empty());
Self {
fd,
events,
revents,
}
}

pub fn fd(&self) -> Option<i32> {
self.fd
}

pub fn events(&self) -> EPollEventType {
self.events
}

pub fn revents(&self) -> &Cell<EPollEventType> {
&self.revents
}
}

impl From<CPollfd> for Pollfd {
fn from(from: CPollfd) -> Self {
let fd = if from.fd >= 0 { Some(from.fd) } else { None };
let events = EPollEventType::from_bits_truncate(from.events as u32);
let revents = Cell::new(EPollEventType::from_bits_truncate(from.revents as u32));
Self {
fd,
events,
revents,
}
}
}

impl From<Pollfd> for CPollfd {
fn from(from: Pollfd) -> Self {
let fd = if let Some(fd) = from.fd() { fd } else { -1 };
let events = from.events().bits() as i16;
let revents = from.revents().get().bits() as i16;
Self {
fd,
events,
revents,
}
}
}
132 changes: 130 additions & 2 deletions kernel/src/net/event_poll/syscall.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
use alloc::vec::Vec;
use log::debug;
use system_error::SystemError;

use crate::{
arch::ipc::signal::SigSet,
filesystem::vfs::file::FileMode,
ipc::signal::set_current_sig_blocked,
mm::VirtAddr,
process::ProcessManager,
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall,
},
time::PosixTimeSpec,
time::{
timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper},
PosixTimeSpec,
},
};

use super::{EPollCtlOption, EPollEvent, EventPoll};
use super::{CPollfd, EPollCtlOption, EPollEvent, EPollEventType, EventPoll, Pollfd};

impl Syscall {
pub fn epoll_create(max_size: i32) -> Result<usize, SystemError> {
Expand Down Expand Up @@ -106,4 +112,126 @@ impl Syscall {
}
wait_ret
}

pub fn poll(ufds: VirtAddr, nfds: u32, timeout_msecs: i32) -> Result<usize, SystemError> {
let fds = {
let mut read_add = ufds;
let mut fds: Vec<Pollfd> = Vec::with_capacity(nfds as usize);
for _ in 0..nfds {
let reader = UserBufferReader::new(
read_add.as_ptr::<CPollfd>(),
core::mem::size_of::<CPollfd>(),
true,
)?;
let mut cfd = CPollfd::default();
reader.copy_one_from_user::<CPollfd>(&mut cfd, 0)?;
// debug!("{:?}",cfd);
let fd = Pollfd::from(cfd);
// debug!("{:?}",fd);
fds.push(fd);
read_add += core::mem::size_of::<CPollfd>();
}
fds
};

let mut timespec = None;
if timeout_msecs >= 0 {
let sec = timeout_msecs as i64 / 1000;
let nsec = 1000000 * (timeout_msecs as i64 % 1000);
timespec = Some(PosixTimeSpec::new(sec, nsec));
}

let nums_events = Self::do_poll(&fds, timespec)?;

let mut write_add = ufds;

for fd in fds {
let cfd = CPollfd::from(fd);
let mut writer = UserBufferWriter::new(
write_add.as_ptr::<CPollfd>(),
core::mem::size_of::<CPollfd>(),
false,
)?;
writer.copy_one_to_user(&cfd, 0)?;
write_add += core::mem::size_of::<CPollfd>();
}

Ok(nums_events)
}
pub fn do_poll(
poll_fds: &[Pollfd],
timespec: Option<PosixTimeSpec>,
) -> Result<usize, SystemError> {
let mut timer = None;
let mut timeout = false;
debug!("{:?}", poll_fds);
loop {
let mut revent_nums = 0;
for poll_fd in poll_fds {
let fd = match poll_fd.fd() {
Some(fd) if fd != 0 => fd,
_ => continue,
};

let current_pcb = ProcessManager::current_pcb();
let fd_table = current_pcb.fd_table();
let fd_table_guard = fd_table.read();
let file = fd_table_guard
.get_file_by_fd(fd)
.ok_or(SystemError::EBADF)?;
drop(fd_table_guard);

// let flag = EPollEventType::EPOLLIN;
let flag_to_check1 = EPollEventType::EPOLLOUT
| EPollEventType::EPOLLWRNORM
| EPollEventType::EPOLLERR;
// let flag_to_check2 = EPollEventType::EPOLLOUT | EPollEventType::EPOLLWRNORM;

let revents =
EPollEventType::from_bits_truncate(file.poll()? as u32) & !flag_to_check1;
// debug!("{:?}",poll_fd);

if !revents.is_empty() {
debug!("{:?}", poll_fd);

revent_nums += 1;
// debug!("after:{:?}",revent_nums);
poll_fd.revents().set(revents | flag_to_check1);
}
// poll_fd.revents().set(revents | flag_to_check1);
}
// debug!("{:?}",revent_nums);
// debug!("{:?}", poll_fds);
if revent_nums > 0 {
return Ok(revent_nums);
}

if timeout {
return Ok(0);
}

if timespec.is_some() && timespec.unwrap().tv_sec == 0 {
return Ok(0);
}

// 若无事件发生,则注册定时器,超时后直接返回0
if let Some(timespec) = timespec {
if timer.is_none() {
let handle = WakeUpHelper::new(ProcessManager::current_pcb());
let jiffies = next_n_us_timer_jiffies(
(timespec.tv_sec * 1000000 + timespec.tv_nsec / 1000) as u64,
);
let inner = Timer::new(handle, jiffies);
inner.activate();
timer = Some(inner);
}
}
if let Some(ref timer) = timer {
if timer.timeout() {
// 超时
timeout = true;
}
}
}
}
}
5 changes: 1 addition & 4 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,10 +834,7 @@ impl Syscall {
}

#[cfg(target_arch = "x86_64")]
SYS_POLL => {
warn!("SYS_POLL has not yet been implemented");
Ok(0)
}
SYS_POLL => Self::poll(VirtAddr::new(args[0]), args[1] as u32, args[2] as i32),

SYS_SETPGID => {
warn!("SYS_SETPGID has not yet been implemented");
Expand Down
1 change: 1 addition & 0 deletions user/apps/test_poll/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test_poll
20 changes: 20 additions & 0 deletions user/apps/test_poll/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ifeq ($(ARCH), x86_64)
CROSS_COMPILE=x86_64-linux-musl-
else ifeq ($(ARCH), riscv64)
CROSS_COMPILE=riscv64-linux-musl-
endif

CC=$(CROSS_COMPILE)gcc

.PHONY: all
all: main.c
$(CC) -static -o test_poll main.c

.PHONY: install clean
install: all
mv test_poll $(DADK_CURRENT_BUILD_DIR)/test_poll

clean:
rm test_poll *.o

fmt:
Loading
Loading