mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 20:16:42 +00:00
Add full epoll_pwait
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9484d35730
commit
07caaa5b3f
@ -265,7 +265,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_FCHMODAT = 268 => sys_fchmodat(args[..3]);
|
SYS_FCHMODAT = 268 => sys_fchmodat(args[..3]);
|
||||||
SYS_SET_ROBUST_LIST = 273 => sys_set_robust_list(args[..2]);
|
SYS_SET_ROBUST_LIST = 273 => sys_set_robust_list(args[..2]);
|
||||||
SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]);
|
SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]);
|
||||||
SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..5]);
|
SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..6]);
|
||||||
SYS_EVENTFD = 284 => sys_eventfd(args[..1]);
|
SYS_EVENTFD = 284 => sys_eventfd(args[..1]);
|
||||||
SYS_ACCEPT4 = 288 => sys_accept4(args[..4]);
|
SYS_ACCEPT4 = 288 => sys_accept4(args[..4]);
|
||||||
SYS_EVENTFD2 = 290 => sys_eventfd2(args[..2]);
|
SYS_EVENTFD2 = 290 => sys_eventfd2(args[..2]);
|
||||||
|
@ -11,6 +11,7 @@ use crate::{
|
|||||||
utils::CreationFlags,
|
utils::CreationFlags,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
process::posix_thread::PosixThreadExt,
|
||||||
util::{read_val_from_user, write_val_to_user},
|
util::{read_val_from_user, write_val_to_user},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,12 +90,7 @@ pub fn sys_epoll_ctl(
|
|||||||
Ok(SyscallReturn::Return(0 as _))
|
Ok(SyscallReturn::Return(0 as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sys_epoll_wait(
|
fn do_epoll_wait(epfd: FileDesc, max_events: i32, timeout: i32) -> Result<Vec<EpollEvent>> {
|
||||||
epfd: FileDesc,
|
|
||||||
events_addr: Vaddr,
|
|
||||||
max_events: i32,
|
|
||||||
timeout: i32,
|
|
||||||
) -> Result<SyscallReturn> {
|
|
||||||
let max_events = {
|
let max_events = {
|
||||||
if max_events <= 0 {
|
if max_events <= 0 {
|
||||||
return_errno_with_message!(Errno::EINVAL, "max_events is not positive");
|
return_errno_with_message!(Errno::EINVAL, "max_events is not positive");
|
||||||
@ -106,20 +102,30 @@ pub fn sys_epoll_wait(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let current = current!();
|
||||||
|
let file_table = current.file_table().lock();
|
||||||
|
let epoll_file = file_table
|
||||||
|
.get_file(epfd)?
|
||||||
|
.downcast_ref::<EpollFile>()
|
||||||
|
.ok_or(Error::with_message(Errno::EINVAL, "not epoll file"))?;
|
||||||
|
let epoll_events = epoll_file.wait(max_events, timeout.as_ref())?;
|
||||||
|
|
||||||
|
Ok(epoll_events)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_epoll_wait(
|
||||||
|
epfd: FileDesc,
|
||||||
|
events_addr: Vaddr,
|
||||||
|
max_events: i32,
|
||||||
|
timeout: i32,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
debug!(
|
debug!(
|
||||||
"epfd = {}, events_addr = 0x{:x}, max_events = {}, timeout = {:?}",
|
"epfd = {}, events_addr = 0x{:x}, max_events = {}, timeout = {:?}",
|
||||||
epfd, events_addr, max_events, timeout
|
epfd, events_addr, max_events, timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
let current = current!();
|
let epoll_events = do_epoll_wait(epfd, max_events, timeout)?;
|
||||||
let file = {
|
|
||||||
let file_table = current.file_table().lock();
|
|
||||||
file_table.get_file(epfd)?.clone()
|
|
||||||
};
|
|
||||||
let epoll_file = file
|
|
||||||
.downcast_ref::<EpollFile>()
|
|
||||||
.ok_or(Error::with_message(Errno::EINVAL, "not epoll file"))?;
|
|
||||||
let epoll_events = epoll_file.wait(max_events, timeout.as_ref())?;
|
|
||||||
|
|
||||||
// Write back
|
// Write back
|
||||||
let mut write_addr = events_addr;
|
let mut write_addr = events_addr;
|
||||||
@ -132,17 +138,74 @@ pub fn sys_epoll_wait(
|
|||||||
Ok(SyscallReturn::Return(epoll_events.len() as _))
|
Ok(SyscallReturn::Return(epoll_events.len() as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_signal_mask(set_ptr: Vaddr) -> Result<u64> {
|
||||||
|
let new_set: Option<u64> = if set_ptr != 0 {
|
||||||
|
Some(read_val_from_user::<u64>(set_ptr)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let current_thread = current_thread!();
|
||||||
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
|
let mut sig_mask = posix_thread.sig_mask().lock();
|
||||||
|
|
||||||
|
let old_sig_mask_value = sig_mask.as_u64();
|
||||||
|
|
||||||
|
if let Some(new_set) = new_set {
|
||||||
|
sig_mask.set(new_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(old_sig_mask_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_signal_mask(sig_mask_val: u64) {
|
||||||
|
let current_thread = current_thread!();
|
||||||
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
|
let mut sig_mask = posix_thread.sig_mask().lock();
|
||||||
|
|
||||||
|
sig_mask.set(sig_mask_val);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sys_epoll_pwait(
|
pub fn sys_epoll_pwait(
|
||||||
epfd: FileDesc,
|
epfd: FileDesc,
|
||||||
events_addr: Vaddr,
|
events_addr: Vaddr,
|
||||||
max_events: i32,
|
max_events: i32,
|
||||||
timeout: i32,
|
timeout: i32,
|
||||||
sigmask: Vaddr, //TODO: handle sigmask
|
sigmask: Vaddr,
|
||||||
|
sigset_size: usize,
|
||||||
) -> Result<SyscallReturn> {
|
) -> Result<SyscallReturn> {
|
||||||
if sigmask != 0 {
|
debug!(
|
||||||
warn!("epoll_pwait cannot handle signal mask, yet");
|
"epfd = {}, events_addr = 0x{:x}, max_events = {}, timeout = {:?}, sigmask = 0x{:x}, sigset_size = {}",
|
||||||
|
epfd, events_addr, max_events, timeout, sigmask, sigset_size
|
||||||
|
);
|
||||||
|
|
||||||
|
if sigset_size != 8 {
|
||||||
|
error!("sigset size is not equal to 8");
|
||||||
}
|
}
|
||||||
sys_epoll_wait(epfd, events_addr, max_events, timeout)
|
|
||||||
|
let old_sig_mask_value = set_signal_mask(sigmask)?;
|
||||||
|
|
||||||
|
let ready_events = match do_epoll_wait(epfd, max_events, timeout) {
|
||||||
|
Ok(events) => {
|
||||||
|
restore_signal_mask(old_sig_mask_value);
|
||||||
|
events
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Restore the signal mask even if an error occurs
|
||||||
|
restore_signal_mask(old_sig_mask_value);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write back
|
||||||
|
let mut write_addr = events_addr;
|
||||||
|
for event in ready_events.iter() {
|
||||||
|
let c_event = c_epoll_event::from(event);
|
||||||
|
write_val_to_user(write_addr, &c_event)?;
|
||||||
|
write_addr += core::mem::size_of::<c_epoll_event>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(ready_events.len() as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod)]
|
#[derive(Debug, Clone, Copy, Pod)]
|
||||||
|
@ -14,6 +14,7 @@ TEST_APPS := \
|
|||||||
capability \
|
capability \
|
||||||
clone3 \
|
clone3 \
|
||||||
cpu_affinity \
|
cpu_affinity \
|
||||||
|
epoll \
|
||||||
eventfd2 \
|
eventfd2 \
|
||||||
execve \
|
execve \
|
||||||
file_io \
|
file_io \
|
||||||
|
5
regression/apps/epoll/Makefile
Normal file
5
regression/apps/epoll/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS :=
|
111
regression/apps/epoll/epoll_pwait.c
Normal file
111
regression/apps/epoll/epoll_pwait.c
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Signal handler for SIGUSR1
|
||||||
|
static void handle_sigusr1(int sig)
|
||||||
|
{
|
||||||
|
write(STDOUT_FILENO, "SIGUSR1 handled\n", 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int pipefd[2]; // Array to store pipe file descriptors
|
||||||
|
pid_t cpid; // Child process ID
|
||||||
|
char buf[1024]; // Read buffer
|
||||||
|
struct epoll_event ev, events[1];
|
||||||
|
int epfd, nfds;
|
||||||
|
|
||||||
|
// Create a pipe
|
||||||
|
if (pipe(pipefd) == -1) {
|
||||||
|
perror("pipe error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create epoll instance
|
||||||
|
if ((epfd = epoll_create1(0)) == -1) {
|
||||||
|
perror("epoll_create1 error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fork to create child process
|
||||||
|
cpid = fork();
|
||||||
|
if (cpid == -1) {
|
||||||
|
perror("fork error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpid == 0) { // Child process
|
||||||
|
close(pipefd[0]); // Child closes read end of the pipe
|
||||||
|
|
||||||
|
sleep(3); // Sleep for several seconds to provide a time window to send SIGUSR1
|
||||||
|
|
||||||
|
const char *message = "Message from child process\n";
|
||||||
|
write(pipefd[1], message,
|
||||||
|
strlen(message)); // Write a string to the pipe
|
||||||
|
close(pipefd[1]); // Close write end of the pipe
|
||||||
|
_exit(EXIT_SUCCESS);
|
||||||
|
} else {
|
||||||
|
// Parent process
|
||||||
|
struct sigaction sa;
|
||||||
|
sigset_t sigset;
|
||||||
|
|
||||||
|
// Setup signal handler for SIGUSR1
|
||||||
|
sa.sa_handler = handle_sigusr1;
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
|
||||||
|
perror("sigaction error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the signal set to block SIGUSR1
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGUSR1);
|
||||||
|
|
||||||
|
close(pipefd[1]); // Parent closes write end of the pipe
|
||||||
|
|
||||||
|
// Set up epoll to listen for events
|
||||||
|
ev.events = EPOLLIN; // Listen for input events
|
||||||
|
ev.data.fd = pipefd[0];
|
||||||
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, pipefd[0], &ev) == -1) {
|
||||||
|
perror("epoll_ctl error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for events to occur, blocking SIGUSR1
|
||||||
|
printf("Waiting for event on pipe, SIGUSR1 is blocked...\n");
|
||||||
|
nfds = epoll_pwait(epfd, events, 1, -1, &sigset);
|
||||||
|
if (nfds == -1) {
|
||||||
|
perror("epoll_pwait error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, epoll_pwait was successful
|
||||||
|
printf("epoll_pwait returned successfully.\n");
|
||||||
|
if (events[0].data.fd == pipefd[0]) {
|
||||||
|
// Read data
|
||||||
|
ssize_t count = read(pipefd[0], buf, sizeof(buf) - 1);
|
||||||
|
if (count > 0) {
|
||||||
|
buf[count] =
|
||||||
|
'\0'; // Ensure string is null-terminated
|
||||||
|
printf("Received data: %s",
|
||||||
|
buf); // Output the entire string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pipefd[0]); // Close read end of the pipe
|
||||||
|
close(epfd); // Close the epoll file descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the child process to complete
|
||||||
|
wait(NULL);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
95
regression/apps/epoll/epoll_wait.c
Normal file
95
regression/apps/epoll/epoll_wait.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int pipefd[2]; // Array to store pipe file descriptors
|
||||||
|
pid_t cpid; // Child process ID
|
||||||
|
char buf[1024]; // Read buffer
|
||||||
|
struct epoll_event ev, events[1];
|
||||||
|
int epfd, nfds;
|
||||||
|
|
||||||
|
// Create a pipe
|
||||||
|
if (pipe(pipefd) == -1) {
|
||||||
|
perror("pipe error");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create epoll instance
|
||||||
|
if ((epfd = epoll_create1(0)) == -1) {
|
||||||
|
perror("epoll_create1 error");
|
||||||
|
close(pipefd[0]);
|
||||||
|
close(pipefd[1]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fork to create child process
|
||||||
|
cpid = fork();
|
||||||
|
if (cpid == -1) {
|
||||||
|
perror("fork error");
|
||||||
|
close(pipefd[0]);
|
||||||
|
close(pipefd[1]);
|
||||||
|
close(epfd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpid == 0) { // Child process
|
||||||
|
close(pipefd[0]); // Child closes read end of the pipe
|
||||||
|
const char *message = "Hello, world!\n";
|
||||||
|
write(pipefd[1], message,
|
||||||
|
strlen(message)); // Write a string to the pipe
|
||||||
|
close(pipefd[1]); // Close write end of the pipe
|
||||||
|
_exit(EXIT_SUCCESS);
|
||||||
|
} else { // Parent process
|
||||||
|
close(pipefd[1]); // Parent closes write end of the pipe
|
||||||
|
|
||||||
|
// Set up epoll to listen for events
|
||||||
|
ev.events = EPOLLIN; // Listen for input events
|
||||||
|
ev.data.fd = pipefd[0];
|
||||||
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, pipefd[0], &ev) == -1) {
|
||||||
|
perror("epoll_ctl error");
|
||||||
|
close(pipefd[0]);
|
||||||
|
close(epfd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for events to occur
|
||||||
|
printf("Waiting for event on pipe...\n");
|
||||||
|
nfds = epoll_wait(epfd, events, 1, -1);
|
||||||
|
if (nfds == -1) {
|
||||||
|
perror("epoll_wait error");
|
||||||
|
close(pipefd[0]);
|
||||||
|
close(epfd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, epoll_wait was successful
|
||||||
|
printf("epoll_wait returned successfully.\n");
|
||||||
|
if (events[0].data.fd == pipefd[0]) {
|
||||||
|
// Read data
|
||||||
|
ssize_t count = read(pipefd[0], buf, sizeof(buf) - 1);
|
||||||
|
if (count > 0) {
|
||||||
|
buf[count] =
|
||||||
|
'\0'; // Ensure string is null-terminated
|
||||||
|
printf("Received data: %s",
|
||||||
|
buf); // Output the entire string
|
||||||
|
} else {
|
||||||
|
perror("read error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pipefd[0]); // Close read end of the pipe
|
||||||
|
close(epfd); // Close the epoll file descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the child process to complete
|
||||||
|
wait(NULL);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -11,5 +11,6 @@ cd ${SCRIPT_DIR}
|
|||||||
./ext2.sh
|
./ext2.sh
|
||||||
./process.sh
|
./process.sh
|
||||||
./network.sh
|
./network.sh
|
||||||
|
./test_epoll_pwait.sh
|
||||||
|
|
||||||
echo "All regression tests passed."
|
echo "All regression tests passed."
|
||||||
|
31
regression/apps/scripts/test_epoll_pwait.sh
Executable file
31
regression/apps/scripts/test_epoll_pwait.sh
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
EPOLLTEST_DIR=/regression/epoll
|
||||||
|
cd ${EPOLLTEST_DIR}
|
||||||
|
|
||||||
|
echo "Start epoll_pwait test......"
|
||||||
|
|
||||||
|
# Step 2: Run epoll_pwait in the background
|
||||||
|
./epoll_pwait &
|
||||||
|
EPOLL_PID=$!
|
||||||
|
|
||||||
|
echo "epoll_pwait PID: $EPOLL_PID"
|
||||||
|
|
||||||
|
# Step 3: Wait for 1 seconds to let epoll_pwait initialize and block SIGUSR1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Step 4: Send SIGUSR1 to epoll_pwait
|
||||||
|
kill -USR1 $EPOLL_PID
|
||||||
|
echo "Sent SIGUSR1 to PID $EPOLL_PID"
|
||||||
|
|
||||||
|
# Optional: Wait a bit more to see the output if the process is still running
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# You can also wait till the subprocess epoll_pwait completely finishes
|
||||||
|
# wait $EPOLL_PID
|
||||||
|
|
||||||
|
echo "Test completed."
|
@ -1,9 +1,4 @@
|
|||||||
EpollTest.AllWritable
|
|
||||||
EpollTest.LastReadable
|
|
||||||
EpollTest.LastNonWritable
|
|
||||||
EpollTest.Timeout_NoRandomSave
|
EpollTest.Timeout_NoRandomSave
|
||||||
EpollTest.WaitThenUnblock
|
|
||||||
EpollTest.UnblockWithSignal
|
|
||||||
EpollTest.TimeoutNoFds
|
EpollTest.TimeoutNoFds
|
||||||
EpollTest.UnblockWithNewFD
|
EpollTest.UnblockWithNewFD
|
||||||
EpollTest.Oneshot
|
EpollTest.Oneshot
|
||||||
|
Reference in New Issue
Block a user