diff --git a/api/arceos_posix_api/Cargo.toml b/api/arceos_posix_api/Cargo.toml index 03081419b..fcc1daace 100644 --- a/api/arceos_posix_api/Cargo.toml +++ b/api/arceos_posix_api/Cargo.toml @@ -26,6 +26,7 @@ net = ["dep:axnet", "axfeat/net", "fd"] pipe = ["fd"] select = ["fd"] epoll = ["fd"] +poll = ["fd"] [dependencies] # ArceOS modules diff --git a/api/arceos_posix_api/build.rs b/api/arceos_posix_api/build.rs index 46556bf37..4706fbee8 100644 --- a/api/arceos_posix_api/build.rs +++ b/api/arceos_posix_api/build.rs @@ -57,6 +57,8 @@ typedef struct {{ "pthread_attr_t", "pthread_mutex_t", "pthread_mutexattr_t", + "pollfd", + "nfds_t", "epoll_event", "iovec", "clockid_t", diff --git a/api/arceos_posix_api/ctypes.h b/api/arceos_posix_api/ctypes.h index b1131bced..3a62a65b8 100644 --- a/api/arceos_posix_api/ctypes.h +++ b/api/arceos_posix_api/ctypes.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/api/arceos_posix_api/src/imp/io_mpx/mod.rs b/api/arceos_posix_api/src/imp/io_mpx/mod.rs index f0c44b0ab..1d78ebcca 100644 --- a/api/arceos_posix_api/src/imp/io_mpx/mod.rs +++ b/api/arceos_posix_api/src/imp/io_mpx/mod.rs @@ -18,8 +18,12 @@ mod epoll; #[cfg(feature = "select")] mod select; +#[cfg(feature = "poll")] +mod poll; #[cfg(feature = "epoll")] pub use self::epoll::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; #[cfg(feature = "select")] pub use self::select::sys_select; +#[cfg(feature = "poll")] +pub use self::poll::sys_poll; diff --git a/api/arceos_posix_api/src/imp/io_mpx/poll.rs b/api/arceos_posix_api/src/imp/io_mpx/poll.rs new file mode 100644 index 000000000..c6de3c190 --- /dev/null +++ b/api/arceos_posix_api/src/imp/io_mpx/poll.rs @@ -0,0 +1,68 @@ +use crate::{ + ctypes, + imp::fd_ops::get_file_like, +}; +use axerrno::{LinuxError, LinuxResult}; +use axhal::time::current_time; + +use core::{ffi::c_int, time::Duration}; + +fn poll_all(fds: &mut [ctypes::pollfd]) -> LinuxResult { + let mut events_num = 0; + + for pollfd_item in fds.iter_mut() { + let intfd = pollfd_item.fd; + let events = pollfd_item.events; + let revents = &mut pollfd_item.revents; + match get_file_like(intfd as c_int)?.poll() { + Err(_) => { + if (events & ctypes::EPOLLERR as i16) != 0 { + *revents |= ctypes::EPOLLERR as i16; + } + } + Ok(state) => { + if state.readable && (events & ctypes::EPOLLIN as i16 != 0) { + *revents |= ctypes::EPOLLIN as i16; + } + + if state.writable && (events & ctypes::EPOLLOUT as i16 != 0) { + *revents |= ctypes::EPOLLOUT as i16; + } + } + } + events_num += 1; + } + Ok(events_num) +} + +// used to monitor multiple file descriptors for events +pub unsafe fn sys_poll( + fds: *mut ctypes::pollfd, + nfds: ctypes::nfds_t, + timeout: c_int +) -> c_int{ + debug!("ax_poll <= nfds: {} timeout: {}", nfds, timeout); + + syscall_body!(ax_poll, { + if nfds <= 0 { + return Err(LinuxError::EINVAL); + } + let fds = core::slice::from_raw_parts_mut(fds, nfds as usize); + let deadline = (!timeout.is_negative()) + .then(|| current_time() + Duration::from_millis(timeout as u64)); + loop { + #[cfg(feature = "net")] + axnet::poll_interfaces(); + let fds_num = poll_all(fds)?; + if fds_num > 0 { + return Ok(fds_num as c_int); + } + + if deadline.map_or(false, |ddl| current_time() >= ddl) { + debug!(" timeout!"); + return Ok(0); + } + crate::sys_sched_yield(); + } + }) +} diff --git a/api/arceos_posix_api/src/imp/mod.rs b/api/arceos_posix_api/src/imp/mod.rs index ac0fe02aa..adc7da948 100644 --- a/api/arceos_posix_api/src/imp/mod.rs +++ b/api/arceos_posix_api/src/imp/mod.rs @@ -19,7 +19,7 @@ pub mod time; pub mod fd_ops; #[cfg(feature = "fs")] pub mod fs; -#[cfg(any(feature = "select", feature = "epoll"))] +#[cfg(any(feature = "select", feature = "poll", feature = "epoll"))] pub mod io_mpx; #[cfg(feature = "net")] pub mod net; diff --git a/api/arceos_posix_api/src/lib.rs b/api/arceos_posix_api/src/lib.rs index 71d469dd4..3fa1eaf48 100644 --- a/api/arceos_posix_api/src/lib.rs +++ b/api/arceos_posix_api/src/lib.rs @@ -55,6 +55,8 @@ pub use imp::fs::{sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_ren pub use imp::io_mpx::sys_select; #[cfg(feature = "epoll")] pub use imp::io_mpx::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; +#[cfg(feature = "poll")] +pub use imp::io_mpx::sys_poll; #[cfg(feature = "net")] pub use imp::net::{ sys_accept, sys_bind, sys_connect, sys_freeaddrinfo, sys_getaddrinfo, sys_getpeername, diff --git a/scripts/make/features.mk b/scripts/make/features.mk index 2ae6276ad..47fc1cb2d 100644 --- a/scripts/make/features.mk +++ b/scripts/make/features.mk @@ -14,7 +14,7 @@ ifeq ($(APP_TYPE),c) ax_feat_prefix := axfeat/ lib_feat_prefix := axlibc/ - lib_features := fp_simd alloc multitask fs net fd pipe select epoll + lib_features := fp_simd alloc multitask fs net fd pipe select poll epoll else # TODO: it's better to use `axfeat/` as `ax_feat_prefix`, but all apps need to have `axfeat` as a dependency ax_feat_prefix := axstd/ @@ -28,7 +28,7 @@ ifeq ($(APP_TYPE), c) ifneq ($(wildcard $(APP)/features.txt),) # check features.txt exists override FEATURES += $(shell cat $(APP)/features.txt) endif - ifneq ($(filter fs net pipe select epoll,$(FEATURES)),) + ifneq ($(filter fs net pipe select poll epoll,$(FEATURES)),) override FEATURES += fd endif endif diff --git a/ulib/axlibc/Cargo.toml b/ulib/axlibc/Cargo.toml index 703e79e01..a21a4d1e6 100644 --- a/ulib/axlibc/Cargo.toml +++ b/ulib/axlibc/Cargo.toml @@ -45,6 +45,7 @@ net = ["arceos_posix_api/net", "fd"] fd = [] pipe = ["arceos_posix_api/pipe"] select = ["arceos_posix_api/select"] +poll = ["arceos_posix_api/poll"] epoll = ["arceos_posix_api/epoll"] [dependencies] diff --git a/ulib/axlibc/c/poll.c b/ulib/axlibc/c/poll.c deleted file mode 100644 index 988628618..000000000 --- a/ulib/axlibc/c/poll.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (c) [2023] [Syswonder Community] - * [Rukos] is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -#include -#include - -// TODO -int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout) -{ - unimplemented(); - return 0; -} diff --git a/ulib/axlibc/include/poll.h b/ulib/axlibc/include/sys/poll.h similarity index 100% rename from ulib/axlibc/include/poll.h rename to ulib/axlibc/include/sys/poll.h diff --git a/ulib/axlibc/src/io_mpx.rs b/ulib/axlibc/src/io_mpx.rs index 522b8d7d9..edabb278a 100644 --- a/ulib/axlibc/src/io_mpx.rs +++ b/ulib/axlibc/src/io_mpx.rs @@ -13,6 +13,8 @@ use core::ffi::c_int; #[cfg(feature = "select")] use arceos_posix_api::sys_select; +#[cfg(feature = "poll")] +use arceos_posix_api::sys_poll; #[cfg(feature = "epoll")] use arceos_posix_api::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; @@ -61,3 +63,15 @@ pub unsafe extern "C" fn select( ) -> c_int { e(sys_select(nfds, readfds, writefds, exceptfds, timeout)) } + + +/// Monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation +#[cfg(feature = "poll")] +#[no_mangle] +pub unsafe extern "C" fn poll( + fds: *mut ctypes::pollfd, + nfds: ctypes::nfds_t, + timeout: c_int +) -> c_int { + e(sys_poll(fds, nfds, timeout)) +} \ No newline at end of file diff --git a/ulib/axlibc/src/lib.rs b/ulib/axlibc/src/lib.rs index b7d718580..8a00aa048 100644 --- a/ulib/axlibc/src/lib.rs +++ b/ulib/axlibc/src/lib.rs @@ -62,7 +62,7 @@ mod utils; mod fd_ops; #[cfg(feature = "fs")] mod fs; -#[cfg(any(feature = "select", feature = "epoll"))] +#[cfg(any(feature = "select", feature = "poll", feature = "epoll"))] mod io_mpx; #[cfg(feature = "alloc")] mod malloc; @@ -127,6 +127,8 @@ pub use self::pipe::pipe; #[cfg(feature = "select")] pub use self::io_mpx::select; +#[cfg(feature = "poll")] +pub use self::io_mpx::poll; #[cfg(feature = "epoll")] pub use self::io_mpx::{epoll_create, epoll_ctl, epoll_wait};