Implement pselect and write test

This commit is contained in:
Wildan M
2026-05-22 03:29:57 +07:00
parent 0f216b2fa0
commit 0f03bff838
10 changed files with 229 additions and 12 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
# - sched.h
# - semaphore.h
# - signal.h
# - sys/select.h (not currently imported, needed for pselect, no TODO)
# - sys/select.h
# - sys/stat.h
# - sys/time.h
# - time.h (where it should be defined)
+64 -8
View File
@@ -9,13 +9,15 @@ use cbitset::BitSet;
use crate::{
fs::File,
header::{
bits_sigset_t::sigset_t,
errno,
sys_epoll::{
EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLLERR, EPOLLIN, EPOLLOUT, epoll_create1, epoll_ctl,
epoll_data, epoll_event, epoll_wait,
epoll_data, epoll_event, epoll_pwait,
},
time::timespec,
},
platform::{self, types::c_int},
platform::types::{c_int, suseconds_t},
};
pub use crate::header::bits_timeval::timeval;
@@ -42,9 +44,10 @@ pub fn select_epoll(
writefds: Option<&mut fd_set>,
exceptfds: Option<&mut fd_set>,
timeout: Option<&mut timeval>,
sigmask: *const sigset_t,
) -> c_int {
if nfds < 0 || nfds > FD_SETSIZE as i32 {
platform::ERRNO.set(errno::EINVAL);
crate::platform::ERRNO.set(errno::EINVAL);
return -1;
};
@@ -55,7 +58,6 @@ pub fn select_epoll(
}
File::new(epfd)
};
let mut read_bitset: Option<&mut FdBitSet> = readfds.map(|fd_set| &mut fd_set.fds_bits);
let mut write_bitset: Option<&mut FdBitSet> = writefds.map(|fd_set| &mut fd_set.fds_bits);
let mut except_bitset: Option<&mut FdBitSet> = exceptfds.map(|fd_set| &mut fd_set.fds_bits);
@@ -90,7 +92,7 @@ pub fn select_epoll(
..Default::default() // clippy lint, _pad field on redox but not linux
};
if unsafe { epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &raw mut event) } < 0 {
if platform::ERRNO.get() == errno::EPERM {
if crate::platform::ERRNO.get() == errno::EPERM {
not_epoll += 1;
} else {
return -1;
@@ -134,12 +136,14 @@ pub fn select_epoll(
None => -1,
}
};
let res = unsafe {
epoll_wait(
epoll_pwait(
*ep,
events.as_mut_ptr(),
events.len() as c_int,
epoll_timeout,
sigmask,
)
};
if res < 0 {
@@ -174,7 +178,7 @@ pub fn select_epoll(
count
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pselect.html>.
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/select.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn select(
nfds: c_int,
@@ -205,7 +209,8 @@ pub unsafe extern "C" fn select(
None
} else {
Some(unsafe { &mut *timeout })
}
},
core::ptr::null(),
),
"select({}, {:p}, {:p}, {:p}, {:p})",
nfds,
@@ -215,3 +220,54 @@ pub unsafe extern "C" fn select(
timeout
)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pselect.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pselect(
nfds: c_int,
readfds: *mut fd_set,
writefds: *mut fd_set,
exceptfds: *mut fd_set,
timeout: *const timespec,
sigmask: *const sigset_t,
) -> c_int {
let mut micro_timeout = if timeout.is_null() {
None
} else {
unsafe {
Some(timeval {
tv_sec: (*timeout).tv_sec,
tv_usec: ((*timeout).tv_nsec / 1000) as suseconds_t,
})
}
};
trace_expr!(
select_epoll(
nfds,
if readfds.is_null() {
None
} else {
Some(unsafe { &mut *readfds })
},
if writefds.is_null() {
None
} else {
Some(unsafe { &mut *writefds })
},
if exceptfds.is_null() {
None
} else {
Some(unsafe { &mut *exceptfds })
},
micro_timeout.as_mut(),
sigmask
),
"pselect({}, {:p}, {:p}, {:p}, {:p}, {:p})",
nfds,
readfds,
writefds,
exceptfds,
timeout,
sigmask,
)
}
+1 -1
View File
@@ -22,7 +22,7 @@ support_build: $(BUILD)/expected \
$(BUILD)/Makefile \
$(BUILD)/Makefile.tests.mk \
$(BUILD)/example_dir \
$(BUILD)/select.c \
$(BUILD)/sys_select/select.c \
$(BUILD)/stdlib/realpath.c \
$(BUILD)/stdio/fread.in \
$(BUILD)/stdio/fscanf_offby1.c \
+3 -1
View File
@@ -70,7 +70,6 @@ EXPECT_NAMES=\
locale/setlocale \
math \
regex \
select \
setjmp \
sigaction \
sigaltstack \
@@ -138,6 +137,9 @@ EXPECT_NAMES=\
string/stpcpy \
string/stpncpy \
strings \
sys_select/select \
sys_select/select_timed \
sys_select/pselect \
sys_shm/shm \
sys_socket/recv \
sys_socket/recvfrom \
+2
View File
@@ -0,0 +1,2 @@
write bar
read bar
@@ -0,0 +1,2 @@
write foo
read foo
+93
View File
@@ -0,0 +1,93 @@
#include <sys/select.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "test_helpers.h"
volatile sig_atomic_t got_signal = 0;
void handle_sigusr1(int sig)
{
(void)sig;
got_signal = 1;
}
int main(void)
{
int status;
int pipe_fds[2];
status = pipe(pipe_fds);
ERROR_IF(pipe, status, == -1);
int read_fd = pipe_fds[0];
int write_fd = pipe_fds[1];
// test sigmask
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handle_sigusr1;
status = sigaction(SIGUSR1, &sa, NULL);
ERROR_IF(sigaction, status, == -1);
sigset_t block_mask, orig_mask;
sigemptyset(&block_mask);
sigaddset(&block_mask, SIGUSR1); // block SIGUSR1
status = sigprocmask(SIG_BLOCK, &block_mask, &orig_mask);
ERROR_IF(sigprocmask, status, == -1);
status = raise(SIGUSR1);
ERROR_IF(raise, status, == -1);
UNEXP_IF(raise, got_signal, != 0); // must not fired
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(read_fd, &read_fds);
struct timespec timeout = { .tv_sec = 5, .tv_nsec = 0 };
int ready = pselect(read_fd + 1, &read_fds, NULL, NULL, &timeout, &orig_mask);
UNEXP_IF(pselect, ready, != -1); // errno should be EINTR
UNEXP_IF(pselect_signal_handler, got_signal, != 1); // must been fired
status = sigprocmask(SIG_SETMASK, &orig_mask, NULL);
ERROR_IF(sigprocmask, status, == -1);
// test timespec
char *c = "bar";
ssize_t written = write(write_fd, c, 4);
ERROR_IF(write, written, == -1);
UNEXP_IF(write, written, != 4);
FD_ZERO(&read_fds);
FD_SET(read_fd, &read_fds);
timeout.tv_sec = 999;
timeout.tv_nsec = 0;
ready = pselect(read_fd + 1, &read_fds, NULL, NULL, &timeout, NULL);
ERROR_IF(pselect, ready, == -1);
UNEXP_IF(pselect, ready, != 1);
int is_set = FD_ISSET(read_fd, &read_fds);
UNEXP_IF(FD_ISSET, is_set, == 0);
char x[4];
ssize_t amount = read(read_fd, x, 4);
ERROR_IF(read, amount, == -1);
UNEXP_IF(read, amount, != 4);
status = strcmp(c, x);
printf("write %s\n", c);
printf("read %s\n", x);
UNEXP_IF(strcmp, status, != 0);
close(read_fd);
close(write_fd);
return 0;
}
+1 -1
View File
@@ -6,7 +6,7 @@
#include "test_helpers.h"
int file_test(void) {
int fd = open("select.c", 0, 0);
int fd = open("sys_select/select.c", 0, 0);
if (fd < 0) {
perror("open");
return -1;
+62
View File
@@ -0,0 +1,62 @@
#include <sys/select.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "test_helpers.h"
int main(void)
{
int status;
int pipe_fds[2];
status = pipe(pipe_fds);
ERROR_IF(pipe, status, == -1);
int read_fd = pipe_fds[0];
int write_fd = pipe_fds[1];
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(read_fd, &read_fds);
struct timeval timeout = { .tv_sec = 0, .tv_usec = 10000 };
int ready = select(read_fd + 1, &read_fds, NULL, NULL, &timeout);
ERROR_IF(pselect, ready, == -1);
UNEXP_IF(pselect, ready, != 0);
char *c = "foo";
ssize_t written = write(write_fd, c, 4);
ERROR_IF(write, written, == -1);
UNEXP_IF(write, written, != 4);
FD_ZERO(&read_fds);
FD_SET(read_fd, &read_fds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
ready = select(read_fd + 1, &read_fds, NULL, NULL, &timeout);
ERROR_IF(pselect, ready, == -1);
UNEXP_IF(pselect, ready, != 1);
int is_set = FD_ISSET(read_fd, &read_fds);
UNEXP_IF(FD_ISSET, is_set, == 0);
char x[4];
ssize_t amount = read(read_fd, x, 4);
ERROR_IF(read, amount, == -1);
UNEXP_IF(read, amount, != 4);
status = strcmp(c, x);
printf("write %s\n", c);
printf("read %s\n", x);
UNEXP_IF(strcmp, status, != 0);
close(read_fd);
close(write_fd);
return 0;
}