Implement pselect and write test
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
write bar
|
||||
read bar
|
||||
@@ -0,0 +1,2 @@
|
||||
write foo
|
||||
read foo
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user