From f3fb5c90d0ef50e7d88f5e4676909dc44a1131ba Mon Sep 17 00:00:00 2001 From: yanjuguang Date: Thu, 24 Aug 2023 17:37:35 +0800 Subject: [PATCH] posix-api: refactor ulib/axlibc, add posix-api layer --- Cargo.lock | 197 +++------------- Cargo.toml | 1 + api/arceos_posix_api/.gitignore | 1 + api/arceos_posix_api/Cargo.toml | 52 +++++ api/arceos_posix_api/build.rs | 106 +++++++++ api/arceos_posix_api/ctypes.h | 14 ++ api/arceos_posix_api/src/imp/fd_ops.rs | 128 +++++++++++ .../arceos_posix_api/src/imp/fs.rs | 111 ++++----- api/arceos_posix_api/src/imp/io.rs | 72 ++++++ .../arceos_posix_api/src/imp}/io_mpx/epoll.rs | 51 ++--- api/arceos_posix_api/src/imp/io_mpx/mod.rs | 16 ++ .../src/imp}/io_mpx/select.rs | 24 +- api/arceos_posix_api/src/imp/mod.rs | 20 ++ .../arceos_posix_api/src/imp/net.rs | 193 +++++++++------- api/arceos_posix_api/src/imp/pipe.rs | 214 ++++++++++++++++++ .../arceos_posix_api/src/imp}/pthread/mod.rs | 36 +-- .../src/imp}/pthread/mutex.rs | 37 +-- api/arceos_posix_api/src/imp/resources.rs | 51 +++++ api/arceos_posix_api/src/imp/stdio.rs | 170 ++++++++++++++ api/arceos_posix_api/src/imp/sys.rs | 29 +++ api/arceos_posix_api/src/imp/task.rs | 40 ++++ api/arceos_posix_api/src/imp/time.rs | 84 +++++++ api/arceos_posix_api/src/lib.rs | 62 +++++ api/arceos_posix_api/src/utils.rs | 61 +++++ apps/c/httpclient/httpclient.c | 7 +- apps/c/pthread/pipe/main.c | 1 + scripts/make/build_c.mk | 3 +- ulib/axlibc/.gitignore | 3 +- ulib/axlibc/Cargo.toml | 38 +--- ulib/axlibc/build.rs | 104 +-------- ulib/axlibc/c/epoll.c | 23 -- ulib/axlibc/c/fcntl.c | 7 +- ulib/axlibc/c/mmap.c | 3 +- ulib/axlibc/c/network.c | 34 --- ulib/axlibc/c/pthread.c | 38 +--- ulib/axlibc/c/resource.c | 56 ----- ulib/axlibc/c/select.c | 26 --- ulib/axlibc/c/socket.c | 70 ------ ulib/axlibc/c/stdio.c | 45 ++-- ulib/axlibc/c/stdlib.c | 58 +---- ulib/axlibc/c/string.c | 7 - ulib/axlibc/c/time.c | 28 +-- ulib/axlibc/c/uio.c | 9 - ulib/axlibc/c/unistd.c | 90 +------- ulib/axlibc/cbindgen.toml | 29 --- ulib/axlibc/ctypes.h | 14 -- ulib/axlibc/include/netdb.h | 7 +- ulib/axlibc/include_gen/.gitkeep | 0 ulib/axlibc/src/errno.rs | 5 +- ulib/axlibc/src/fd_ops.rs | 184 +++------------ ulib/axlibc/src/fs.rs | 67 ++++++ ulib/axlibc/src/io.rs | 32 +++ ulib/axlibc/src/io_mpx.rs | 54 +++++ ulib/axlibc/src/io_mpx/mod.rs | 16 -- ulib/axlibc/src/lib.rs | 118 +++++----- ulib/axlibc/src/malloc.rs | 9 +- ulib/axlibc/src/mktime.rs | 4 +- ulib/axlibc/src/net.rs | 180 +++++++++++++++ ulib/axlibc/src/pipe.rs | 206 +---------------- ulib/axlibc/src/pthread.rs | 59 +++++ ulib/axlibc/src/rand.rs | 19 +- ulib/axlibc/src/resource.rs | 17 ++ ulib/axlibc/src/setjmp.rs | 6 +- ulib/axlibc/src/stdio.rs | 109 --------- ulib/axlibc/src/strftime.rs | 11 +- ulib/axlibc/src/strtod.rs | 8 +- ulib/axlibc/src/sys.rs | 25 +- ulib/axlibc/src/time.rs | 73 +----- ulib/axlibc/src/uio.rs | 27 --- ulib/axlibc/src/unistd.rs | 20 ++ ulib/axlibc/src/utils.rs | 65 +----- 71 files changed, 2037 insertions(+), 1747 deletions(-) create mode 100644 api/arceos_posix_api/.gitignore create mode 100644 api/arceos_posix_api/Cargo.toml create mode 100644 api/arceos_posix_api/build.rs create mode 100644 api/arceos_posix_api/ctypes.h create mode 100644 api/arceos_posix_api/src/imp/fd_ops.rs rename ulib/axlibc/src/file.rs => api/arceos_posix_api/src/imp/fs.rs (62%) create mode 100644 api/arceos_posix_api/src/imp/io.rs rename {ulib/axlibc/src => api/arceos_posix_api/src/imp}/io_mpx/epoll.rs (84%) create mode 100644 api/arceos_posix_api/src/imp/io_mpx/mod.rs rename {ulib/axlibc/src => api/arceos_posix_api/src/imp}/io_mpx/select.rs (92%) create mode 100644 api/arceos_posix_api/src/imp/mod.rs rename ulib/axlibc/src/socket.rs => api/arceos_posix_api/src/imp/net.rs (76%) create mode 100644 api/arceos_posix_api/src/imp/pipe.rs rename {ulib/axlibc/src => api/arceos_posix_api/src/imp}/pthread/mod.rs (84%) rename {ulib/axlibc/src => api/arceos_posix_api/src/imp}/pthread/mutex.rs (54%) create mode 100644 api/arceos_posix_api/src/imp/resources.rs create mode 100644 api/arceos_posix_api/src/imp/stdio.rs create mode 100644 api/arceos_posix_api/src/imp/sys.rs create mode 100644 api/arceos_posix_api/src/imp/task.rs create mode 100644 api/arceos_posix_api/src/imp/time.rs create mode 100644 api/arceos_posix_api/src/lib.rs create mode 100644 api/arceos_posix_api/src/utils.rs delete mode 100644 ulib/axlibc/c/epoll.c delete mode 100644 ulib/axlibc/c/uio.c delete mode 100644 ulib/axlibc/cbindgen.toml delete mode 100644 ulib/axlibc/include_gen/.gitkeep create mode 100644 ulib/axlibc/src/fs.rs create mode 100644 ulib/axlibc/src/io.rs create mode 100644 ulib/axlibc/src/io_mpx.rs delete mode 100644 ulib/axlibc/src/io_mpx/mod.rs create mode 100644 ulib/axlibc/src/net.rs create mode 100644 ulib/axlibc/src/pthread.rs create mode 100644 ulib/axlibc/src/resource.rs delete mode 100644 ulib/axlibc/src/stdio.rs delete mode 100644 ulib/axlibc/src/uio.rs create mode 100644 ulib/axlibc/src/unistd.rs diff --git a/Cargo.lock b/Cargo.lock index 44c015b988..b305bb4329 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,29 @@ dependencies = [ "axtask", ] +[[package]] +name = "arceos_posix_api" +version = "0.1.0" +dependencies = [ + "axalloc", + "axconfig", + "axerrno", + "axfeat", + "axfs", + "axhal", + "axio", + "axlog", + "axnet", + "axruntime", + "axsync", + "axtask", + "bindgen", + "flatten_objects", + "lazy_static", + "spin 0.9.8", + "static_assertions", +] + [[package]] name = "arm_gic" version = "0.1.0" @@ -213,17 +236,6 @@ dependencies = [ "critical-section", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -395,22 +407,11 @@ dependencies = [ name = "axlibc" version = "0.1.0" dependencies = [ - "axalloc", - "axconfig", + "arceos_posix_api", "axerrno", "axfeat", - "axhal", "axio", - "axlog", - "axnet", - "axstd", - "axtask", "bindgen", - "cbindgen", - "flatten_objects", - "lazy_static", - "spin 0.9.8", - "static_assertions", ] [[package]] @@ -619,25 +620,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cbindgen" -version = "0.24.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d" -dependencies = [ - "clap 3.2.25", - "heck", - "indexmap 1.9.3", - "log", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 1.0.109", - "tempfile", - "toml", -] - [[package]] name = "cc" version = "1.0.83" @@ -715,21 +697,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "strsim", - "termcolor", - "textwrap", -] - [[package]] name = "clap" version = "4.3.23" @@ -746,16 +713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" dependencies = [ "anstyle", - "clap_lex 0.5.0", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", + "clap_lex", ] [[package]] @@ -800,7 +758,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.3.23", + "clap", "criterion-plot", "is-terminal", "itertools", @@ -1029,12 +987,6 @@ dependencies = [ "libc", ] -[[package]] -name = "fastrand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" - [[package]] name = "fatfs" version = "0.4.0" @@ -1096,12 +1048,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.0" @@ -1121,21 +1067,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.2" @@ -1165,16 +1096,6 @@ dependencies = [ "cc", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.0.0" @@ -1182,7 +1103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown", ] [[package]] @@ -1191,7 +1112,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "rustix", "windows-sys", ] @@ -1378,7 +1299,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", ] @@ -1394,12 +1315,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_str_bytes" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" - [[package]] name = "page_table" version = "0.1.0" @@ -1611,15 +1526,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "regex" version = "1.9.3" @@ -1851,12 +1757,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "svgbobdoc" version = "0.3.0" @@ -1892,34 +1792,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.47" @@ -1971,15 +1843,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml_datetime" version = "0.6.3" @@ -1992,7 +1855,7 @@ version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap 2.0.0", + "indexmap", "toml_datetime", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 7b77147621..1db098f126 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ members = [ "api/axfeat", "api/arceos_api", + "api/arceos_posix_api", "ulib/axstd", "ulib/axlibc", diff --git a/api/arceos_posix_api/.gitignore b/api/arceos_posix_api/.gitignore new file mode 100644 index 0000000000..5e6d7ebe4b --- /dev/null +++ b/api/arceos_posix_api/.gitignore @@ -0,0 +1 @@ +ctypes_gen.rs diff --git a/api/arceos_posix_api/Cargo.toml b/api/arceos_posix_api/Cargo.toml new file mode 100644 index 0000000000..03081419b9 --- /dev/null +++ b/api/arceos_posix_api/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "arceos_posix_api" +version = "0.1.0" +edition = "2021" +authors = [ + "Yuekai Jia ", + "yanjuguang ", + "wudashuai ", + "yfblock <321353225@qq.com>", + "scPointer ", + "Shiping Yuan ", +] +description = "POSIX-compatible APIs for ArceOS modules" +license = "GPL-3.0-or-later OR Apache-2.0" +repository = "https://github.com/rcore-os/arceos/tree/main/api/arceos_posix_api" + +[features] +default = [] + +smp = ["axfeat/smp"] +alloc = ["dep:axalloc", "axfeat/alloc"] +multitask = ["axtask/multitask", "axfeat/multitask", "axsync/multitask"] +fd = ["alloc"] +fs = ["dep:axfs", "axfeat/fs", "fd"] +net = ["dep:axnet", "axfeat/net", "fd"] +pipe = ["fd"] +select = ["fd"] +epoll = ["fd"] + +[dependencies] +# ArceOS modules +axfeat = { path = "../axfeat" } +axruntime = { path = "../../modules/axruntime" } +axconfig = { path = "../../modules/axconfig" } +axlog = { path = "../../modules/axlog" } +axhal = { path = "../../modules/axhal" } +axsync = { path = "../../modules/axsync" } +axalloc = { path = "../../modules/axalloc", optional = true } +axtask = { path = "../../modules/axtask", optional = true } +axfs = { path = "../../modules/axfs", optional = true } +axnet = { path = "../../modules/axnet", optional = true } + +# Other crates +axio = { path = "../../crates/axio" } +axerrno = { path = "../../crates/axerrno" } +static_assertions = "1.1.0" +spin = { version = "0.9" } +lazy_static = { version = "1.4", features = ["spin_no_std"] } +flatten_objects = { path = "../../crates/flatten_objects" } + +[build-dependencies] +bindgen ={ version = "0.66" } diff --git a/api/arceos_posix_api/build.rs b/api/arceos_posix_api/build.rs new file mode 100644 index 0000000000..3c9aa161b8 --- /dev/null +++ b/api/arceos_posix_api/build.rs @@ -0,0 +1,106 @@ +fn main() { + use std::io::Write; + + fn gen_pthread_mutex(out_file: &str) -> std::io::Result<()> { + // TODO: generate size and initial content automatically. + let (mutex_size, mutex_init) = if cfg!(feature = "multitask") { + if cfg!(feature = "smp") { + (6, "{0, 8, 0, 0, 0, 0}") // core::mem::transmute::<_, [usize; 6]>(axsync::Mutex::new(())) + } else { + (5, "{8, 0, 0, 0, 0}") // core::mem::transmute::<_, [usize; 5]>(axsync::Mutex::new(())) + } + } else { + (1, "{0}") + }; + + let mut output = Vec::new(); + writeln!( + output, + "// Generated by arceos_posix_api/build.rs, DO NOT edit!" + )?; + writeln!( + output, + r#" +typedef struct {{ + long __l[{mutex_size}]; +}} pthread_mutex_t; + +#define PTHREAD_MUTEX_INITIALIZER {{ .__l = {mutex_init}}} +"# + )?; + std::fs::write(out_file, output)?; + Ok(()) + } + + fn gen_c_to_rust_bindings(in_file: &str, out_file: &str) { + println!("cargo:rerun-if-changed={in_file}"); + + let allow_types = [ + "stat", + "size_t", + "ssize_t", + "off_t", + "mode_t", + "sock.*", + "fd_set", + "timeval", + "pthread_t", + "pthread_attr_t", + "pthread_mutex_t", + "pthread_mutexattr_t", + "epoll_event", + "iovec", + "clockid_t", + "rlimit", + "aibuf", + ]; + let allow_vars = [ + "O_.*", + "AF_.*", + "SOCK_.*", + "IPPROTO_.*", + "FD_.*", + "F_.*", + "_SC_.*", + "EPOLL_CTL_.*", + "EPOLL.*", + "RLIMIT_.*", + "EAI_.*", + "MAXADDRS", + ]; + + #[derive(Debug)] + struct MyCallbacks; + + impl bindgen::callbacks::ParseCallbacks for MyCallbacks { + fn include_file(&self, fname: &str) { + if !fname.contains("ax_pthread_mutex.h") { + println!("cargo:rerun-if-changed={}", fname); + } + } + } + + let mut builder = bindgen::Builder::default() + .header(in_file) + .clang_arg("-I./../../ulib/axlibc/include") + .parse_callbacks(Box::new(MyCallbacks)) + .derive_default(true) + .size_t_is_usize(false) + .use_core(); + for ty in allow_types { + builder = builder.allowlist_type(ty); + } + for var in allow_vars { + builder = builder.allowlist_var(var); + } + + builder + .generate() + .expect("Unable to generate c->rust bindings") + .write_to_file(out_file) + .expect("Couldn't write bindings!"); + } + + gen_pthread_mutex("../../ulib/axlibc/include/ax_pthread_mutex.h").unwrap(); + gen_c_to_rust_bindings("ctypes.h", "src/ctypes_gen.rs"); +} diff --git a/api/arceos_posix_api/ctypes.h b/api/arceos_posix_api/ctypes.h new file mode 100644 index 0000000000..7d745f80d6 --- /dev/null +++ b/api/arceos_posix_api/ctypes.h @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/api/arceos_posix_api/src/imp/fd_ops.rs b/api/arceos_posix_api/src/imp/fd_ops.rs new file mode 100644 index 0000000000..75ee61061f --- /dev/null +++ b/api/arceos_posix_api/src/imp/fd_ops.rs @@ -0,0 +1,128 @@ +use alloc::sync::Arc; +use core::ffi::c_int; + +use axerrno::{LinuxError, LinuxResult}; +use axio::PollState; +use flatten_objects::FlattenObjects; +use spin::RwLock; + +use super::stdio::{stdin, stdout}; +use crate::ctypes; + +pub const AX_FILE_LIMIT: usize = 1024; + +pub trait FileLike: Send + Sync { + fn read(&self, buf: &mut [u8]) -> LinuxResult; + fn write(&self, buf: &[u8]) -> LinuxResult; + fn stat(&self) -> LinuxResult; + fn into_any(self: Arc) -> Arc; + fn poll(&self) -> LinuxResult; + fn set_nonblocking(&self, nonblocking: bool) -> LinuxResult; +} + +lazy_static::lazy_static! { + static ref FD_TABLE: RwLock, AX_FILE_LIMIT>> = { + let mut fd_table = FlattenObjects::new(); + fd_table.add_at(0, Arc::new(stdin()) as _).unwrap(); // stdin + fd_table.add_at(1, Arc::new(stdout()) as _).unwrap(); // stdout + fd_table.add_at(2, Arc::new(stdout()) as _).unwrap(); // stderr + RwLock::new(fd_table) + }; +} + +pub fn get_file_like(fd: c_int) -> LinuxResult> { + FD_TABLE + .read() + .get(fd as usize) + .cloned() + .ok_or(LinuxError::EBADF) +} + +pub fn add_file_like(f: Arc) -> LinuxResult { + Ok(FD_TABLE.write().add(f).ok_or(LinuxError::EMFILE)? as c_int) +} + +pub fn close_file_like(fd: c_int) -> LinuxResult { + let f = FD_TABLE + .write() + .remove(fd as usize) + .ok_or(LinuxError::EBADF)?; + drop(f); + Ok(()) +} + +/// Close a file by `fd`. +pub fn sys_close(fd: c_int) -> c_int { + debug!("sys_close <= {}", fd); + if (0..=2).contains(&fd) { + return 0; // stdin, stdout, stderr + } + syscall_body!(sys_close, close_file_like(fd).map(|_| 0)) +} + +fn dup_fd(old_fd: c_int) -> LinuxResult { + let f = get_file_like(old_fd)?; + let new_fd = add_file_like(f)?; + Ok(new_fd) +} + +/// Duplicate a file descriptor. +pub fn sys_dup(old_fd: c_int) -> c_int { + debug!("sys_dup <= {}", old_fd); + syscall_body!(sys_dup, dup_fd(old_fd)) +} + +/// Duplicate a file descriptor, but it uses the file descriptor number specified in `new_fd`. +/// +/// TODO: `dup2` should forcibly close new_fd if it is already opened. +pub fn sys_dup2(old_fd: c_int, new_fd: c_int) -> c_int { + debug!("sys_dup2 <= old_fd: {}, new_fd: {}", old_fd, new_fd); + syscall_body!(sys_dup2, { + if old_fd == new_fd { + let r = sys_fcntl(old_fd, ctypes::F_GETFD as _, 0); + if r >= 0 { + return Ok(old_fd); + } else { + return Ok(r); + } + } + if new_fd as usize >= AX_FILE_LIMIT { + return Err(LinuxError::EBADF); + } + + let f = get_file_like(old_fd)?; + FD_TABLE + .write() + .add_at(new_fd as usize, f) + .ok_or(LinuxError::EMFILE)?; + + Ok(new_fd) + }) +} + +/// Manipulate file descriptor. +/// +/// TODO: `SET/GET` command is ignored, hard-code stdin/stdout +pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int { + debug!("sys_fcntl <= fd: {} cmd: {} arg: {}", fd, cmd, arg); + syscall_body!(sys_fcntl, { + match cmd as u32 { + ctypes::F_DUPFD => dup_fd(fd), + ctypes::F_DUPFD_CLOEXEC => { + // TODO: Change fd flags + dup_fd(fd) + } + ctypes::F_SETFL => { + if fd == 0 || fd == 1 || fd == 2 { + return Ok(0); + } + get_file_like(fd)?.set_nonblocking(arg & (ctypes::O_NONBLOCK as usize) > 0)?; + Ok(0) + } + _ => { + warn!("unsupported fcntl parameters: cmd {}", cmd); + Ok(0) + } + } + }) +} diff --git a/ulib/axlibc/src/file.rs b/api/arceos_posix_api/src/imp/fs.rs similarity index 62% rename from ulib/axlibc/src/file.rs rename to api/arceos_posix_api/src/imp/fs.rs index 78e2a598bc..6c92f2da6d 100644 --- a/ulib/axlibc/src/file.rs +++ b/api/arceos_posix_api/src/imp/fs.rs @@ -2,17 +2,22 @@ use alloc::sync::Arc; use core::ffi::{c_char, c_int}; use axerrno::{LinuxError, LinuxResult}; -use axio::{prelude::*, PollState, SeekFrom}; -use axstd::fs::OpenOptions; -use axstd::sync::Mutex; +use axfs::fops::OpenOptions; +use axio::{PollState, SeekFrom}; +use axsync::Mutex; -use crate::{ctypes, fd_ops::FileLike, utils::char_ptr_to_str}; +use super::fd_ops::{get_file_like, FileLike}; +use crate::{ctypes, utils::char_ptr_to_str}; -pub struct File(Mutex); +pub struct File { + inner: Mutex, +} impl File { - fn new(inner: axstd::fs::File) -> Self { - Self(Mutex::new(inner)) + fn new(inner: axfs::fops::File) -> Self { + Self { + inner: Mutex::new(inner), + } } fn add_to_fd_table(self) -> LinuxResult { @@ -29,19 +34,17 @@ impl File { impl FileLike for File { fn read(&self, buf: &mut [u8]) -> LinuxResult { - let len = self.0.lock().read(buf)?; - Ok(len) + Ok(self.inner.lock().read(buf)?) } fn write(&self, buf: &[u8]) -> LinuxResult { - let len = self.0.lock().write(buf)?; - Ok(len) + Ok(self.inner.lock().write(buf)?) } fn stat(&self) -> LinuxResult { - let metadata = self.0.lock().metadata()?; + let metadata = self.inner.lock().get_attr()?; let ty = metadata.file_type() as u8; - let perm = metadata.permissions().bits() as u32; + let perm = metadata.perm().bits() as u32; let st_mode = ((ty as u32) << 12) | perm; Ok(ctypes::stat { st_ino: 1, @@ -79,7 +82,10 @@ fn flags_to_options(flags: c_int, _mode: ctypes::mode_t) -> OpenOptions { match flags & 0b11 { ctypes::O_RDONLY => options.read(true), ctypes::O_WRONLY => options.write(true), - _ => options.read(true).write(true), + _ => { + options.read(true); + options.write(true); + } }; if flags & ctypes::O_APPEND != 0 { options.append(true); @@ -100,17 +106,12 @@ fn flags_to_options(flags: c_int, _mode: ctypes::mode_t) -> OpenOptions { /// /// Return its index in the file table (`fd`). Return `EMFILE` if it already /// has the maximum number of files open. -#[no_mangle] -pub unsafe extern "C" fn ax_open( - filename: *const c_char, - flags: c_int, - mode: ctypes::mode_t, -) -> c_int { +pub fn sys_open(filename: *const c_char, flags: c_int, mode: ctypes::mode_t) -> c_int { let filename = char_ptr_to_str(filename); - debug!("ax_open <= {:?} {:#o} {:#o}", filename, flags, mode); - ax_call_body!(ax_open, { + debug!("sys_open <= {:?} {:#o} {:#o}", filename, flags, mode); + syscall_body!(sys_open, { let options = flags_to_options(flags, mode); - let file = options.open(filename?)?; + let file = axfs::fops::File::open(filename?, &options)?; File::new(file).add_to_fd_table() }) } @@ -118,21 +119,16 @@ pub unsafe extern "C" fn ax_open( /// Set the position of the file indicated by `fd`. /// /// Return its position after seek. -#[no_mangle] -pub unsafe extern "C" fn ax_lseek( - fd: c_int, - offset: ctypes::off_t, - whence: c_int, -) -> ctypes::off_t { - debug!("ax_lseek <= {} {} {}", fd, offset, whence); - ax_call_body!(ax_lseek, { +pub fn sys_lseek(fd: c_int, offset: ctypes::off_t, whence: c_int) -> ctypes::off_t { + debug!("sys_lseek <= {} {} {}", fd, offset, whence); + syscall_body!(sys_lseek, { let pos = match whence { 0 => SeekFrom::Start(offset as _), 1 => SeekFrom::Current(offset as _), 2 => SeekFrom::End(offset as _), _ => return Err(LinuxError::EINVAL), }; - let off = File::from_fd(fd)?.0.lock().seek(pos)?; + let off = File::from_fd(fd)?.inner.lock().seek(pos)?; Ok(off) }) } @@ -140,29 +136,44 @@ pub unsafe extern "C" fn ax_lseek( /// Get the file metadata by `path` and write into `buf`. /// /// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_stat(path: *const c_char, buf: *mut ctypes::stat) -> ctypes::ssize_t { +pub unsafe fn sys_stat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { let path = char_ptr_to_str(path); - debug!("ax_stat <= {:?} {:#x}", path, buf as usize); - ax_call_body!(ax_stat, { + debug!("sys_stat <= {:?} {:#x}", path, buf as usize); + syscall_body!(sys_stat, { if buf.is_null() { return Err(LinuxError::EFAULT); } - let file = axstd::fs::File::open(path?)?; + let mut options = OpenOptions::new(); + options.read(true); + let file = axfs::fops::File::open(path?, &options)?; let st = File::new(file).stat()?; unsafe { *buf = st }; Ok(0) }) } +/// Get file metadata by `fd` and write into `buf`. +/// +/// Return 0 if success. +pub unsafe fn sys_fstat(fd: c_int, buf: *mut ctypes::stat) -> c_int { + debug!("sys_fstat <= {} {:#x}", fd, buf as usize); + syscall_body!(sys_fstat, { + if buf.is_null() { + return Err(LinuxError::EFAULT); + } + + unsafe { *buf = get_file_like(fd)?.stat()? }; + Ok(0) + }) +} + /// Get the metadata of the symbolic link and write into `buf`. /// /// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_lstat(path: *const c_char, buf: *mut ctypes::stat) -> ctypes::ssize_t { +pub unsafe fn sys_lstat(path: *const c_char, buf: *mut ctypes::stat) -> ctypes::ssize_t { let path = char_ptr_to_str(path); - debug!("ax_lstat <= {:?} {:#x}", path, buf as usize); - ax_call_body!(ax_lstat, { + debug!("sys_lstat <= {:?} {:#x}", path, buf as usize); + syscall_body!(sys_lstat, { if buf.is_null() { return Err(LinuxError::EFAULT); } @@ -172,15 +183,14 @@ pub unsafe extern "C" fn ax_lstat(path: *const c_char, buf: *mut ctypes::stat) - } /// Get the path of the current directory. -#[no_mangle] -pub unsafe extern "C" fn ax_getcwd(buf: *mut c_char, size: usize) -> *mut c_char { - debug!("ax_getcwd <= {:#x} {}", buf as usize, size); - ax_call_body!(ax_getcwd, { +pub fn sys_getcwd(buf: *mut c_char, size: usize) -> *mut c_char { + debug!("sys_getcwd <= {:#x} {}", buf as usize, size); + syscall_body!(sys_getcwd, { if buf.is_null() { return Ok(core::ptr::null::() as _); } let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, size as _) }; - let cwd = axstd::env::current_dir()?; + let cwd = axfs::api::current_dir()?; let cwd = cwd.as_bytes(); if cwd.len() < size { dst[..cwd.len()].copy_from_slice(cwd); @@ -196,13 +206,12 @@ pub unsafe extern "C" fn ax_getcwd(buf: *mut c_char, size: usize) -> *mut c_char /// If new exists, it is first removed. /// /// Return 0 if the operation succeeds, otherwise return -1. -#[no_mangle] -pub unsafe extern "C" fn ax_rename(old: *const c_char, new: *const c_char) -> c_int { - ax_call_body!(ax_rename, { +pub fn sys_rename(old: *const c_char, new: *const c_char) -> c_int { + syscall_body!(sys_rename, { let old_path = char_ptr_to_str(old)?; let new_path = char_ptr_to_str(new)?; - debug!("ax_rename <= old: {:?}, new: {:?}", old_path, new_path); - axstd::fs::rename(old_path, new_path)?; + debug!("sys_rename <= old: {:?}, new: {:?}", old_path, new_path); + axfs::api::rename(old_path, new_path)?; Ok(0) }) } diff --git a/api/arceos_posix_api/src/imp/io.rs b/api/arceos_posix_api/src/imp/io.rs new file mode 100644 index 0000000000..269ce20354 --- /dev/null +++ b/api/arceos_posix_api/src/imp/io.rs @@ -0,0 +1,72 @@ +use crate::ctypes; +use axerrno::LinuxError; +use core::ffi::{c_int, c_void}; + +#[cfg(feature = "fd")] +use crate::imp::fd_ops::get_file_like; +#[cfg(not(feature = "fd"))] +use axio::prelude::*; + +/// Read data from the file indicated by `fd`. +/// +/// Return the read size if success. +pub fn sys_read(fd: c_int, buf: *mut c_void, count: usize) -> ctypes::ssize_t { + debug!("sys_read <= {} {:#x} {}", fd, buf as usize, count); + syscall_body!(sys_read, { + if buf.is_null() { + return Err(LinuxError::EFAULT); + } + let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, count) }; + #[cfg(feature = "fd")] + { + Ok(get_file_like(fd)?.read(dst)? as ctypes::ssize_t) + } + #[cfg(not(feature = "fd"))] + match fd { + 0 => Ok(super::stdio::stdin().read(dst)? as ctypes::ssize_t), + 1 | 2 => Err(LinuxError::EPERM), + _ => Err(LinuxError::EBADF), + } + }) +} + +/// Write data to the file indicated by `fd`. +/// +/// Return the written size if success. +pub fn sys_write(fd: c_int, buf: *const c_void, count: usize) -> ctypes::ssize_t { + debug!("sys_write <= {} {:#x} {}", fd, buf as usize, count); + syscall_body!(sys_write, { + if buf.is_null() { + return Err(LinuxError::EFAULT); + } + let src = unsafe { core::slice::from_raw_parts(buf as *const u8, count) }; + #[cfg(feature = "fd")] + { + Ok(get_file_like(fd)?.write(src)? as ctypes::ssize_t) + } + #[cfg(not(feature = "fd"))] + match fd { + 0 => Err(LinuxError::EPERM), + 1 | 2 => Ok(super::stdio::stdout().write(src)? as ctypes::ssize_t), + _ => Err(LinuxError::EBADF), + } + }) +} + +/// Write a vector. +pub unsafe fn sys_writev(fd: c_int, iov: *const ctypes::iovec, iocnt: c_int) -> ctypes::ssize_t { + debug!("sys_writev <= fd: {}", fd); + syscall_body!(sys_writev, { + if !(0..=1024).contains(&iocnt) { + return Err(LinuxError::EINVAL); + } + + let iovs = unsafe { core::slice::from_raw_parts(iov, iocnt as usize) }; + let mut ret = 0; + for iov in iovs.iter() { + ret += sys_write(fd, iov.iov_base, iov.iov_len); + } + + Ok(ret) + }) +} diff --git a/ulib/axlibc/src/io_mpx/epoll.rs b/api/arceos_posix_api/src/imp/io_mpx/epoll.rs similarity index 84% rename from ulib/axlibc/src/io_mpx/epoll.rs rename to api/arceos_posix_api/src/imp/io_mpx/epoll.rs index d934385ec0..5404b2f13a 100644 --- a/ulib/axlibc/src/io_mpx/epoll.rs +++ b/api/arceos_posix_api/src/imp/io_mpx/epoll.rs @@ -2,19 +2,18 @@ //! //! TODO: do not support `EPOLLET` flag -use crate::{ - ctypes, - fd_ops::{add_file_like, get_file_like, FileLike}, -}; -use axerrno::{LinuxError, LinuxResult}; -use axhal::time::current_time; -use axstd::sync::Mutex; - use alloc::collections::btree_map::Entry; use alloc::collections::BTreeMap; use alloc::sync::Arc; use core::{ffi::c_int, time::Duration}; +use axerrno::{LinuxError, LinuxResult}; +use axhal::time::current_time; +use axsync::Mutex; + +use crate::ctypes; +use crate::imp::fd_ops::{add_file_like, get_file_like, FileLike}; + pub struct EpollInstance { events: Mutex>, } @@ -138,13 +137,12 @@ impl FileLike for EpollInstance { } } -/// `ax_epoll_create()` creates a new epoll instance. +/// Creates a new epoll instance. /// -/// `ax_epoll_create()` returns a file descriptor referring to the new epoll instance. -#[no_mangle] -pub unsafe extern "C" fn ax_epoll_create(size: c_int) -> c_int { - debug!("ax_epoll_create <= {}", size); - ax_call_body!(ax_epoll_create, { +/// It returns a file descriptor referring to the new epoll instance. +pub fn sys_epoll_create(size: c_int) -> c_int { + debug!("sys_epoll_create <= {}", size); + syscall_body!(sys_epoll_create, { if size < 0 { return Err(LinuxError::EINVAL); } @@ -154,39 +152,38 @@ pub unsafe extern "C" fn ax_epoll_create(size: c_int) -> c_int { } /// Control interface for an epoll file descriptor -#[no_mangle] -pub unsafe extern "C" fn ax_epoll_ctl( +pub unsafe fn sys_epoll_ctl( epfd: c_int, op: c_int, fd: c_int, event: *mut ctypes::epoll_event, ) -> c_int { - debug!("ax_epoll_ctl <= epfd: {} op: {} fd: {}", epfd, op, fd); - ax_call_body!(ax_epoll_ctl, { - let ret = - EpollInstance::from_fd(epfd)?.control(op as usize, fd as usize, &(*event))? as c_int; + debug!("sys_epoll_ctl <= epfd: {} op: {} fd: {}", epfd, op, fd); + syscall_body!(sys_epoll_ctl, { + let ret = unsafe { + EpollInstance::from_fd(epfd)?.control(op as usize, fd as usize, &(*event))? as c_int + }; Ok(ret) }) } -/// `ax_epoll_wait()` waits for events on the epoll instance referred to by the file descriptor epfd. -#[no_mangle] -pub unsafe extern "C" fn ax_epoll_wait( +/// Waits for events on the epoll instance referred to by the file descriptor epfd. +pub unsafe fn sys_epoll_wait( epfd: c_int, events: *mut ctypes::epoll_event, maxevents: c_int, timeout: c_int, ) -> c_int { debug!( - "ax_epoll_wait <= epfd: {}, maxevents: {}, timeout: {}", + "sys_epoll_wait <= epfd: {}, maxevents: {}, timeout: {}", epfd, maxevents, timeout ); - ax_call_body!(ax_epoll_wait, { + syscall_body!(sys_epoll_wait, { if maxevents <= 0 { return Err(LinuxError::EINVAL); } - let events = core::slice::from_raw_parts_mut(events, maxevents as usize); + let events = unsafe { core::slice::from_raw_parts_mut(events, maxevents as usize) }; let deadline = (!timeout.is_negative()) .then(|| current_time() + Duration::from_millis(timeout as u64)); let epoll_instance = EpollInstance::from_fd(epfd)?; @@ -202,7 +199,7 @@ pub unsafe extern "C" fn ax_epoll_wait( debug!(" timeout!"); return Ok(0); } - axstd::thread::yield_now(); + crate::sys_sched_yield(); } }) } diff --git a/api/arceos_posix_api/src/imp/io_mpx/mod.rs b/api/arceos_posix_api/src/imp/io_mpx/mod.rs new file mode 100644 index 0000000000..397ed44f30 --- /dev/null +++ b/api/arceos_posix_api/src/imp/io_mpx/mod.rs @@ -0,0 +1,16 @@ +//! I/O multiplexing: +//! +//! * [`select`](select::sys_select) +//! * [`epoll_create`](epoll::sys_epoll_create) +//! * [`epoll_ctl`](epoll::sys_epoll_ctl) +//! * [`epoll_wait`](epoll::sys_epoll_wait) + +#[cfg(feature = "epoll")] +mod epoll; +#[cfg(feature = "select")] +mod select; + +#[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; diff --git a/ulib/axlibc/src/io_mpx/select.rs b/api/arceos_posix_api/src/imp/io_mpx/select.rs similarity index 92% rename from ulib/axlibc/src/io_mpx/select.rs rename to api/arceos_posix_api/src/imp/io_mpx/select.rs index 6c239dd194..6986598b5c 100644 --- a/ulib/axlibc/src/io_mpx/select.rs +++ b/api/arceos_posix_api/src/imp/io_mpx/select.rs @@ -1,8 +1,9 @@ +use core::ffi::c_int; + use axerrno::{LinuxError, LinuxResult}; use axhal::time::current_time; -use core::ffi::c_int; -use crate::{ctypes, fd_ops::get_file_like}; +use crate::{ctypes, imp::fd_ops::get_file_like}; const FD_SETSIZE: usize = 1024; const BITS_PER_USIZE: usize = usize::BITS as usize; @@ -107,8 +108,7 @@ impl FdSets { } /// Monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation -#[no_mangle] -pub unsafe extern "C" fn ax_select( +pub unsafe fn sys_select( nfds: c_int, readfds: *mut ctypes::fd_set, writefds: *mut ctypes::fd_set, @@ -116,20 +116,22 @@ pub unsafe extern "C" fn ax_select( timeout: *mut ctypes::timeval, ) -> c_int { debug!( - "ax_select <= {} {:#x} {:#x} {:#x}", + "sys_select <= {} {:#x} {:#x} {:#x}", nfds, readfds as usize, writefds as usize, exceptfds as usize ); - ax_call_body!(ax_select, { + syscall_body!(sys_select, { if nfds < 0 { return Err(LinuxError::EINVAL); } let nfds = (nfds as usize).min(FD_SETSIZE); - let deadline = timeout.as_ref().map(|t| current_time() + (*t).into()); + let deadline = unsafe { timeout.as_ref().map(|t| current_time() + (*t).into()) }; let fd_sets = FdSets::from(nfds, readfds, writefds, exceptfds); - zero_fd_set(readfds, nfds); - zero_fd_set(writefds, nfds); - zero_fd_set(exceptfds, nfds); + unsafe { + zero_fd_set(readfds, nfds); + zero_fd_set(writefds, nfds); + zero_fd_set(exceptfds, nfds); + } loop { #[cfg(feature = "net")] @@ -143,7 +145,7 @@ pub unsafe extern "C" fn ax_select( debug!(" timeout!"); return Ok(0); } - axstd::thread::yield_now(); + crate::sys_sched_yield(); } }) } diff --git a/api/arceos_posix_api/src/imp/mod.rs b/api/arceos_posix_api/src/imp/mod.rs new file mode 100644 index 0000000000..603f934baa --- /dev/null +++ b/api/arceos_posix_api/src/imp/mod.rs @@ -0,0 +1,20 @@ +mod stdio; + +pub mod io; +pub mod resources; +pub mod sys; +pub mod task; +pub mod time; + +#[cfg(feature = "fd")] +pub mod fd_ops; +#[cfg(feature = "fs")] +pub mod fs; +#[cfg(any(feature = "select", feature = "epoll"))] +pub mod io_mpx; +#[cfg(feature = "net")] +pub mod net; +#[cfg(feature = "pipe")] +pub mod pipe; +#[cfg(feature = "multitask")] +pub mod pthread; diff --git a/ulib/axlibc/src/socket.rs b/api/arceos_posix_api/src/imp/net.rs similarity index 76% rename from ulib/axlibc/src/socket.rs rename to api/arceos_posix_api/src/imp/net.rs index 1703349d12..861e4737bb 100644 --- a/ulib/axlibc/src/socket.rs +++ b/api/arceos_posix_api/src/imp/net.rs @@ -1,4 +1,4 @@ -use alloc::{sync::Arc, vec}; +use alloc::{sync::Arc, vec, vec::Vec}; use core::ffi::{c_char, c_int, c_void}; use core::mem::size_of; use core::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; @@ -6,9 +6,11 @@ use core::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; use axerrno::{LinuxError, LinuxResult}; use axio::PollState; use axnet::{TcpSocket, UdpSocket}; -use axstd::sync::Mutex; +use axsync::Mutex; -use crate::{ctypes, fd_ops::FileLike, utils::char_ptr_to_str}; +use super::fd_ops::FileLike; +use crate::ctypes; +use crate::utils::char_ptr_to_str; pub enum Socket { Udp(Mutex), @@ -227,11 +229,10 @@ fn from_sockaddr( /// Create an socket for communication. /// /// Return the socket file descriptor. -#[no_mangle] -pub unsafe extern "C" fn ax_socket(domain: c_int, socktype: c_int, protocol: c_int) -> c_int { - debug!("ax_socket <= {} {} {}", domain, socktype, protocol); +pub fn sys_socket(domain: c_int, socktype: c_int, protocol: c_int) -> c_int { + debug!("sys_socket <= {} {} {}", domain, socktype, protocol); let (domain, socktype, protocol) = (domain as u32, socktype as u32, protocol as u32); - ax_call_body!(ax_socket, { + syscall_body!(sys_socket, { match (domain, socktype, protocol) { (ctypes::AF_INET, ctypes::SOCK_STREAM, ctypes::IPPROTO_TCP) | (ctypes::AF_INET, ctypes::SOCK_STREAM, 0) => { @@ -249,17 +250,16 @@ pub unsafe extern "C" fn ax_socket(domain: c_int, socktype: c_int, protocol: c_i /// Bind a address to a socket. /// /// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_bind( +pub fn sys_bind( socket_fd: c_int, socket_addr: *const ctypes::sockaddr, addrlen: ctypes::socklen_t, ) -> c_int { debug!( - "ax_bind <= {} {:#x} {}", + "sys_bind <= {} {:#x} {}", socket_fd, socket_addr as usize, addrlen ); - ax_call_body!(ax_bind, { + syscall_body!(sys_bind, { let addr = from_sockaddr(socket_addr, addrlen)?; Socket::from_fd(socket_fd)?.bind(addr)?; Ok(0) @@ -269,17 +269,16 @@ pub unsafe extern "C" fn ax_bind( /// Connects the socket to the address specified. /// /// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_connect( +pub fn sys_connect( socket_fd: c_int, socket_addr: *const ctypes::sockaddr, addrlen: ctypes::socklen_t, ) -> c_int { debug!( - "ax_connect <= {} {:#x} {}", + "sys_connect <= {} {:#x} {}", socket_fd, socket_addr as usize, addrlen ); - ax_call_body!(ax_connect, { + syscall_body!(sys_connect, { let addr = from_sockaddr(socket_addr, addrlen)?; Socket::from_fd(socket_fd)?.connect(addr)?; Ok(0) @@ -289,8 +288,7 @@ pub unsafe extern "C" fn ax_connect( /// Send a message on a socket to the address specified. /// /// Return the number of bytes sent if success. -#[no_mangle] -pub unsafe extern "C" fn ax_sendto( +pub fn sys_sendto( socket_fd: c_int, buf_ptr: *const c_void, len: ctypes::size_t, @@ -299,10 +297,10 @@ pub unsafe extern "C" fn ax_sendto( addrlen: ctypes::socklen_t, ) -> ctypes::ssize_t { debug!( - "ax_sendto <= {} {:#x} {} {} {:#x} {}", + "sys_sendto <= {} {:#x} {} {} {:#x} {}", socket_fd, buf_ptr as usize, len, flag, socket_addr as usize, addrlen ); - ax_call_body!(ax_sendto, { + syscall_body!(sys_sendto, { if buf_ptr.is_null() { return Err(LinuxError::EFAULT); } @@ -315,18 +313,17 @@ pub unsafe extern "C" fn ax_sendto( /// Send a message on a socket to the address connected. /// /// Return the number of bytes sent if success. -#[no_mangle] -pub unsafe extern "C" fn ax_send( +pub fn sys_send( socket_fd: c_int, buf_ptr: *const c_void, len: ctypes::size_t, flag: c_int, // currently not used ) -> ctypes::ssize_t { debug!( - "ax_sendto <= {} {:#x} {} {}", + "sys_sendto <= {} {:#x} {} {}", socket_fd, buf_ptr as usize, len, flag ); - ax_call_body!(ax_send, { + syscall_body!(sys_send, { if buf_ptr.is_null() { return Err(LinuxError::EFAULT); } @@ -338,8 +335,7 @@ pub unsafe extern "C" fn ax_send( /// Receive a message on a socket and get its source address. /// /// Return the number of bytes received if success. -#[no_mangle] -pub unsafe extern "C" fn ax_recvfrom( +pub unsafe fn sys_recvfrom( socket_fd: c_int, buf_ptr: *mut c_void, len: ctypes::size_t, @@ -348,10 +344,10 @@ pub unsafe extern "C" fn ax_recvfrom( addrlen: *mut ctypes::socklen_t, ) -> ctypes::ssize_t { debug!( - "ax_recvfrom <= {} {:#x} {} {} {:#x} {:#x}", + "sys_recvfrom <= {} {:#x} {} {} {:#x} {:#x}", socket_fd, buf_ptr as usize, len, flag, socket_addr as usize, addrlen as usize ); - ax_call_body!(ax_recvfrom, { + syscall_body!(sys_recvfrom, { if buf_ptr.is_null() || socket_addr.is_null() || addrlen.is_null() { return Err(LinuxError::EFAULT); } @@ -371,18 +367,17 @@ pub unsafe extern "C" fn ax_recvfrom( /// Receive a message on a socket. /// /// Return the number of bytes received if success. -#[no_mangle] -pub unsafe extern "C" fn ax_recv( +pub fn sys_recv( socket_fd: c_int, buf_ptr: *mut c_void, len: ctypes::size_t, flag: c_int, // currently not used ) -> ctypes::ssize_t { debug!( - "ax_recv <= {} {:#x} {} {}", + "sys_recv <= {} {:#x} {} {}", socket_fd, buf_ptr as usize, len, flag ); - ax_call_body!(ax_recv, { + syscall_body!(sys_recv, { if buf_ptr.is_null() { return Err(LinuxError::EFAULT); } @@ -394,13 +389,12 @@ pub unsafe extern "C" fn ax_recv( /// Listen for connections on a socket /// /// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_listen( +pub fn sys_listen( socket_fd: c_int, backlog: c_int, // currently not used -) -> ctypes::ssize_t { - debug!("ax_listen <= {} {}", socket_fd, backlog); - ax_call_body!(ax_listen, { +) -> c_int { + debug!("sys_listen <= {} {}", socket_fd, backlog); + syscall_body!(sys_listen, { Socket::from_fd(socket_fd)?.listen()?; Ok(0) }) @@ -409,17 +403,16 @@ pub unsafe extern "C" fn ax_listen( /// Accept for connections on a socket /// /// Return file descriptor for the accepted socket if success. -#[no_mangle] -pub unsafe extern "C" fn ax_accept( +pub unsafe fn sys_accept( socket_fd: c_int, socket_addr: *mut ctypes::sockaddr, socket_len: *mut ctypes::socklen_t, -) -> ctypes::ssize_t { +) -> c_int { debug!( - "ax_accept <= {} {:#x} {:#x}", + "sys_accept <= {} {:#x} {:#x}", socket_fd, socket_addr as usize, socket_len as usize ); - ax_call_body!(ax_accept, { + syscall_body!(sys_accept, { if socket_addr.is_null() || socket_len.is_null() { return Err(LinuxError::EFAULT); } @@ -437,13 +430,12 @@ pub unsafe extern "C" fn ax_accept( /// Shut down a full-duplex connection. /// /// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_shutdown( +pub fn sys_shutdown( socket_fd: c_int, flag: c_int, // currently not used -) -> ctypes::ssize_t { - debug!("ax_shutdown <= {} {}", socket_fd, flag); - ax_call_body!(ax_shutdown, { +) -> c_int { + debug!("sys_shutdown <= {} {}", socket_fd, flag); + syscall_body!(sys_shutdown, { Socket::from_fd(socket_fd)?.shutdown()?; Ok(0) }) @@ -451,26 +443,29 @@ pub unsafe extern "C" fn ax_shutdown( /// Query addresses for a domain name. /// +/// Only IPv4. Ports are always 0. Ignore servname and hint. +/// Results' ai_flags and ai_canonname are 0 or NULL. +/// /// Return address number if success. -#[no_mangle] -pub unsafe extern "C" fn ax_getaddrinfo( - node: *const c_char, - service: *const c_char, - addrs: *mut ctypes::sockaddr, - len: ctypes::size_t, +pub unsafe fn sys_getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + _hints: *const ctypes::addrinfo, + res: *mut *mut ctypes::addrinfo, ) -> c_int { - let name = char_ptr_to_str(node); - let port = char_ptr_to_str(service); - debug!( - "ax_getaddrinfo <= {:?} {:?} {:#x} {}", - name, port, addrs as usize, len - ); - ax_call_body!(ax_getaddrinfo, { - if addrs.is_null() || (node.is_null() && service.is_null()) { + let name = char_ptr_to_str(nodename); + let port = char_ptr_to_str(servname); + debug!("sys_getaddrinfo <= {:?} {:?}", name, port); + syscall_body!(sys_getaddrinfo, { + if nodename.is_null() && servname.is_null() { + return Ok(0); + } + if res.is_null() { return Err(LinuxError::EFAULT); } - let addr_slice = unsafe { core::slice::from_raw_parts_mut(addrs, len) }; - let res = if let Ok(domain) = name { + + let port = port.map_or(0, |p| p.parse::().unwrap_or(0)); + let ip_addrs = if let Ok(domain) = name { if let Ok(a) = domain.parse::() { vec![a] } else { @@ -480,29 +475,74 @@ pub unsafe extern "C" fn ax_getaddrinfo( vec![Ipv4Addr::LOCALHOST.into()] }; - for (i, item) in res.iter().enumerate().take(len) { - addr_slice[i] = into_sockaddr(SocketAddr::new( - *item, - port.map_or(0, |p| p.parse::().unwrap_or(0)), - )) - .0; + let len = ip_addrs.len().min(ctypes::MAXADDRS as usize); + if len == 0 { + return Ok(0); + } + + let mut out: Vec = Vec::with_capacity(len); + for (i, &ip) in ip_addrs.iter().enumerate().take(len) { + let buf = match ip { + IpAddr::V4(ip) => ctypes::aibuf { + ai: ctypes::addrinfo { + ai_family: ctypes::AF_INET as _, + // TODO: This is a hard-code part, only return TCP parameters + ai_socktype: ctypes::SOCK_STREAM as _, + ai_protocol: ctypes::IPPROTO_TCP as _, + ai_addrlen: size_of::() as _, + ai_addr: core::ptr::null_mut(), + ai_canonname: core::ptr::null_mut(), + ai_next: core::ptr::null_mut(), + ai_flags: 0, + }, + sa: ctypes::aibuf_sa { + sin: SocketAddrV4::new(ip, port).into(), + }, + slot: i as i16, + lock: [0], + ref_: 0, + }, + _ => panic!("IPv6 is not supported"), + }; + out.push(buf); + out[i].ai.ai_addr = + unsafe { core::ptr::addr_of_mut!(out[i].sa.sin) as *mut ctypes::sockaddr }; + if i > 0 { + out[i - 1].ai.ai_next = core::ptr::addr_of_mut!(out[i].ai); + } } - Ok(res.len().min(len)) + + out[0].ref_ = len as i16; + unsafe { *res = core::ptr::addr_of_mut!(out[0].ai) }; + core::mem::forget(out); // drop in `sys_freeaddrinfo` + Ok(len) }) } +/// Free queried `addrinfo` struct +pub unsafe fn sys_freeaddrinfo(res: *mut ctypes::addrinfo) { + if res.is_null() { + return; + } + let aibuf_ptr = res as *mut ctypes::aibuf; + let len = (*aibuf_ptr).ref_ as usize; + assert!((*aibuf_ptr).slot == 0); + assert!(len > 0); + let vec = Vec::from_raw_parts(aibuf_ptr, len, len); // TODO: lock + drop(vec); +} + /// Get current address to which the socket sockfd is bound. -#[no_mangle] -pub unsafe extern "C" fn ax_getsockname( +pub unsafe fn sys_getsockname( sock_fd: c_int, addr: *mut ctypes::sockaddr, addrlen: *mut ctypes::socklen_t, ) -> c_int { debug!( - "ax_getsockname <= {} {:#x} {:#x}", + "sys_getsockname <= {} {:#x} {:#x}", sock_fd, addr as usize, addrlen as usize ); - ax_call_body!(ax_getsockname, { + syscall_body!(sys_getsockname, { if addr.is_null() || addrlen.is_null() { return Err(LinuxError::EFAULT); } @@ -517,17 +557,16 @@ pub unsafe extern "C" fn ax_getsockname( } /// Get peer address to which the socket sockfd is connected. -#[no_mangle] -pub unsafe extern "C" fn ax_getpeername( +pub unsafe fn sys_getpeername( sock_fd: c_int, addr: *mut ctypes::sockaddr, addrlen: *mut ctypes::socklen_t, ) -> c_int { debug!( - "ax_getpeername <= {} {:#x} {:#x}", + "sys_getpeername <= {} {:#x} {:#x}", sock_fd, addr as usize, addrlen as usize ); - ax_call_body!(ax_getpeername, { + syscall_body!(sys_getpeername, { if addr.is_null() || addrlen.is_null() { return Err(LinuxError::EFAULT); } diff --git a/api/arceos_posix_api/src/imp/pipe.rs b/api/arceos_posix_api/src/imp/pipe.rs new file mode 100644 index 0000000000..17a9b248b6 --- /dev/null +++ b/api/arceos_posix_api/src/imp/pipe.rs @@ -0,0 +1,214 @@ +use alloc::sync::Arc; +use core::ffi::c_int; + +use axerrno::{LinuxError, LinuxResult}; +use axio::PollState; +use axsync::Mutex; + +use super::fd_ops::{add_file_like, close_file_like, FileLike}; +use crate::ctypes; + +#[derive(Copy, Clone, PartialEq)] +enum RingBufferStatus { + Full, + Empty, + Normal, +} + +const RING_BUFFER_SIZE: usize = 256; + +pub struct PipeRingBuffer { + arr: [u8; RING_BUFFER_SIZE], + head: usize, + tail: usize, + status: RingBufferStatus, +} + +impl PipeRingBuffer { + pub const fn new() -> Self { + Self { + arr: [0; RING_BUFFER_SIZE], + head: 0, + tail: 0, + status: RingBufferStatus::Empty, + } + } + + pub fn write_byte(&mut self, byte: u8) { + self.status = RingBufferStatus::Normal; + self.arr[self.tail] = byte; + self.tail = (self.tail + 1) % RING_BUFFER_SIZE; + if self.tail == self.head { + self.status = RingBufferStatus::Full; + } + } + + pub fn read_byte(&mut self) -> u8 { + self.status = RingBufferStatus::Normal; + let c = self.arr[self.head]; + self.head = (self.head + 1) % RING_BUFFER_SIZE; + if self.head == self.tail { + self.status = RingBufferStatus::Empty; + } + c + } + + /// Get the length of remaining data in the buffer + pub const fn available_read(&self) -> usize { + if matches!(self.status, RingBufferStatus::Empty) { + 0 + } else if self.tail > self.head { + self.tail - self.head + } else { + self.tail + RING_BUFFER_SIZE - self.head + } + } + + /// Get the length of remaining space in the buffer + pub const fn available_write(&self) -> usize { + if matches!(self.status, RingBufferStatus::Full) { + 0 + } else { + RING_BUFFER_SIZE - self.available_read() + } + } +} + +pub struct Pipe { + readable: bool, + buffer: Arc>, +} + +impl Pipe { + pub fn new() -> (Pipe, Pipe) { + let buffer = Arc::new(Mutex::new(PipeRingBuffer::new())); + let read_end = Pipe { + readable: true, + buffer: buffer.clone(), + }; + let write_end = Pipe { + readable: false, + buffer, + }; + (read_end, write_end) + } + + pub const fn readable(&self) -> bool { + self.readable + } + + pub const fn writable(&self) -> bool { + !self.readable + } + + pub fn write_end_close(&self) -> bool { + Arc::strong_count(&self.buffer) == 1 + } +} + +impl FileLike for Pipe { + fn read(&self, buf: &mut [u8]) -> LinuxResult { + if !self.readable() { + return Err(LinuxError::EPERM); + } + let mut read_size = 0usize; + let max_len = buf.len(); + loop { + let mut ring_buffer = self.buffer.lock(); + let loop_read = ring_buffer.available_read(); + if loop_read == 0 { + if self.write_end_close() { + return Ok(read_size); + } + drop(ring_buffer); + // Data not ready, wait for write end + crate::sys_sched_yield(); // TODO: use synconize primitive + continue; + } + for _ in 0..loop_read { + if read_size == max_len { + return Ok(read_size); + } + buf[read_size] = ring_buffer.read_byte(); + read_size += 1; + } + } + } + + fn write(&self, buf: &[u8]) -> LinuxResult { + if !self.writable() { + return Err(LinuxError::EPERM); + } + let mut write_size = 0usize; + let max_len = buf.len(); + loop { + let mut ring_buffer = self.buffer.lock(); + let loop_write = ring_buffer.available_write(); + if loop_write == 0 { + drop(ring_buffer); + // Buffer is full, wait for read end to consume + crate::sys_sched_yield(); // TODO: use synconize primitive + continue; + } + for _ in 0..loop_write { + if write_size == max_len { + return Ok(write_size); + } + ring_buffer.write_byte(buf[write_size]); + write_size += 1; + } + } + } + + fn stat(&self) -> LinuxResult { + let st_mode = 0o10000 | 0o600u32; // S_IFIFO | rw------- + Ok(ctypes::stat { + st_ino: 1, + st_nlink: 1, + st_mode, + st_uid: 1000, + st_gid: 1000, + st_blksize: 4096, + ..Default::default() + }) + } + + fn into_any(self: Arc) -> Arc { + self + } + + fn poll(&self) -> LinuxResult { + let buf = self.buffer.lock(); + Ok(PollState { + readable: self.readable() && buf.available_read() > 0, + writable: self.writable() && buf.available_write() > 0, + }) + } + + fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { + Ok(()) + } +} + +/// Create a pipe +/// +/// Return 0 if succeed +pub fn sys_pipe(fds: &mut [c_int]) -> c_int { + debug!("sys_pipe <= {:#x}", fds.as_ptr() as usize); + syscall_body!(sys_pipe, { + if fds.len() != 2 { + return Err(LinuxError::EFAULT); + } + + let (read_end, write_end) = Pipe::new(); + let read_fd = add_file_like(Arc::new(read_end))?; + let write_fd = add_file_like(Arc::new(write_end)).inspect_err(|_| { + close_file_like(read_fd).ok(); + })?; + + fds[0] = read_fd as c_int; + fds[1] = write_fd as c_int; + + Ok(0) + }) +} diff --git a/ulib/axlibc/src/pthread/mod.rs b/api/arceos_posix_api/src/imp/pthread/mod.rs similarity index 84% rename from ulib/axlibc/src/pthread/mod.rs rename to api/arceos_posix_api/src/imp/pthread/mod.rs index e989151d16..bcf12fff8e 100644 --- a/ulib/axlibc/src/pthread/mod.rs +++ b/api/arceos_posix_api/src/imp/pthread/mod.rs @@ -6,7 +6,7 @@ use axerrno::{LinuxError, LinuxResult}; use axtask::AxTaskRef; use spin::RwLock; -use super::ctypes; +use crate::ctypes; pub mod mutex; @@ -103,18 +103,8 @@ impl Pthread { } } -/// Get current thread ID. -#[no_mangle] -pub unsafe extern "C" fn ax_getpid() -> c_int { - ax_call_body!(ax_getpid, { - let pid = axtask::current().id().as_u64() as c_int; - Ok(pid) - }) -} - /// Returns the `pthread` struct of current thread. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_self() -> ctypes::pthread_t { +pub fn sys_pthread_self() -> ctypes::pthread_t { Pthread::current().expect("fail to get current thread") as *const Pthread as _ } @@ -122,18 +112,17 @@ pub unsafe extern "C" fn ax_pthread_self() -> ctypes::pthread_t { /// /// If successful, it stores the pointer to the newly created `struct __pthread` /// in `res` and returns 0. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_create( +pub unsafe fn sys_pthread_create( res: *mut ctypes::pthread_t, attr: *const ctypes::pthread_attr_t, start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, arg: *mut c_void, ) -> c_int { debug!( - "ax_pthread_create <= {:#x}, {:#x}", + "sys_pthread_create <= {:#x}, {:#x}", start_routine as usize, arg as usize ); - ax_call_body!(ax_pthread_create, { + syscall_body!(sys_pthread_create, { let ptr = Pthread::create(attr, start_routine, arg)?; unsafe { core::ptr::write(res, ptr) }; Ok(0) @@ -141,20 +130,15 @@ pub unsafe extern "C" fn ax_pthread_create( } /// Exits the current thread. The value `retval` will be returned to the joiner. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_exit(retval: *mut c_void) -> ! { - debug!("ax_pthread_exit <= {:#x}", retval as usize); +pub fn sys_pthread_exit(retval: *mut c_void) -> ! { + debug!("sys_pthread_exit <= {:#x}", retval as usize); Pthread::exit_current(retval); } /// Waits for the given thread to exit, and stores the return value in `retval`. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_join( - thread: ctypes::pthread_t, - retval: *mut *mut c_void, -) -> c_int { - debug!("ax_pthread_join <= {:#x}", retval as usize); - ax_call_body!(ax_pthread_join, { +pub unsafe fn sys_pthread_join(thread: ctypes::pthread_t, retval: *mut *mut c_void) -> c_int { + debug!("sys_pthread_join <= {:#x}", retval as usize); + syscall_body!(sys_pthread_join, { let ret = Pthread::join(thread)?; if !retval.is_null() { unsafe { core::ptr::write(retval, ret) }; diff --git a/ulib/axlibc/src/pthread/mutex.rs b/api/arceos_posix_api/src/imp/pthread/mutex.rs similarity index 54% rename from ulib/axlibc/src/pthread/mutex.rs rename to api/arceos_posix_api/src/imp/pthread/mutex.rs index ac4af9da77..f22a8f55d4 100644 --- a/ulib/axlibc/src/pthread/mutex.rs +++ b/api/arceos_posix_api/src/imp/pthread/mutex.rs @@ -1,6 +1,8 @@ use crate::{ctypes, utils::check_null_mut_ptr}; + use axerrno::LinuxResult; -use axstd::sync::Mutex; +use axsync::Mutex; + use core::ffi::c_int; use core::mem::{size_of, ManuallyDrop}; @@ -29,37 +31,40 @@ impl PthreadMutex { } /// Initialize a mutex. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_mutex_init( +pub fn sys_pthread_mutex_init( mutex: *mut ctypes::pthread_mutex_t, _attr: *const ctypes::pthread_mutexattr_t, ) -> c_int { - debug!("ax_pthread_mutex_init <= {:#x}", mutex as usize); - ax_call_body!(ax_pthread_mutex_init, { + debug!("sys_pthread_mutex_init <= {:#x}", mutex as usize); + syscall_body!(sys_pthread_mutex_init, { check_null_mut_ptr(mutex)?; - mutex.cast::().write(PthreadMutex::new()); + unsafe { + mutex.cast::().write(PthreadMutex::new()); + } Ok(0) }) } /// Lock the given mutex. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { - debug!("ax_pthread_mutex_lock <= {:#x}", mutex as usize); - ax_call_body!(ax_pthread_mutex_lock, { +pub fn sys_pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { + debug!("sys_pthread_mutex_lock <= {:#x}", mutex as usize); + syscall_body!(sys_pthread_mutex_lock, { check_null_mut_ptr(mutex)?; - (*mutex.cast::()).lock()?; + unsafe { + (*mutex.cast::()).lock()?; + } Ok(0) }) } /// Unlock the given mutex. -#[no_mangle] -pub unsafe extern "C" fn ax_pthread_mutex_unlock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { - debug!("ax_pthread_mutex_unlock <= {:#x}", mutex as usize); - ax_call_body!(ax_pthread_mutex_unlock, { +pub fn sys_pthread_mutex_unlock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { + debug!("sys_pthread_mutex_unlock <= {:#x}", mutex as usize); + syscall_body!(sys_pthread_mutex_unlock, { check_null_mut_ptr(mutex)?; - (*mutex.cast::()).unlock()?; + unsafe { + (*mutex.cast::()).unlock()?; + } Ok(0) }) } diff --git a/api/arceos_posix_api/src/imp/resources.rs b/api/arceos_posix_api/src/imp/resources.rs new file mode 100644 index 0000000000..16956ae83e --- /dev/null +++ b/api/arceos_posix_api/src/imp/resources.rs @@ -0,0 +1,51 @@ +use crate::ctypes; +use axerrno::LinuxError; +use core::ffi::c_int; + +/// Get resource limitations +/// +/// TODO: support more resource types +pub unsafe fn sys_getrlimit(resource: c_int, rlimits: *mut ctypes::rlimit) -> c_int { + debug!("sys_getrlimit <= {} {:#x}", resource, rlimits as usize); + syscall_body!(sys_getrlimit, { + match resource as u32 { + ctypes::RLIMIT_DATA => {} + ctypes::RLIMIT_STACK => {} + ctypes::RLIMIT_NOFILE => {} + _ => return Err(LinuxError::EINVAL), + } + if rlimits.is_null() { + return Ok(0); + } + match resource as u32 { + ctypes::RLIMIT_STACK => unsafe { + (*rlimits).rlim_cur = axconfig::TASK_STACK_SIZE as _; + (*rlimits).rlim_max = axconfig::TASK_STACK_SIZE as _; + }, + #[cfg(feature = "fd")] + ctypes::RLIMIT_NOFILE => unsafe { + (*rlimits).rlim_cur = super::fd_ops::AX_FILE_LIMIT as _; + (*rlimits).rlim_max = super::fd_ops::AX_FILE_LIMIT as _; + }, + _ => {} + } + Ok(0) + }) +} + +/// Set resource limitations +/// +/// TODO: support more resource types +pub unsafe fn sys_setrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { + debug!("sys_setrlimit <= {} {:#x}", resource, rlimits as usize); + syscall_body!(sys_setrlimit, { + match resource as u32 { + crate::ctypes::RLIMIT_DATA => {} + crate::ctypes::RLIMIT_STACK => {} + crate::ctypes::RLIMIT_NOFILE => {} + _ => return Err(LinuxError::EINVAL), + } + // Currently do not support set resources + Ok(0) + }) +} diff --git a/api/arceos_posix_api/src/imp/stdio.rs b/api/arceos_posix_api/src/imp/stdio.rs new file mode 100644 index 0000000000..ded9c3333a --- /dev/null +++ b/api/arceos_posix_api/src/imp/stdio.rs @@ -0,0 +1,170 @@ +use axerrno::AxResult; +use axio::{prelude::*, BufReader}; +use axsync::Mutex; + +#[cfg(feature = "fd")] +use {alloc::sync::Arc, axerrno::LinuxError, axerrno::LinuxResult, axio::PollState}; + +fn console_read_bytes() -> Option { + axhal::console::getchar().map(|c| if c == b'\r' { b'\n' } else { c }) +} + +fn console_write_bytes(buf: &[u8]) -> AxResult { + axhal::console::write_bytes(buf); + Ok(buf.len()) +} + +struct StdinRaw; +struct StdoutRaw; + +impl Read for StdinRaw { + // Non-blocking read, returns number of bytes read. + fn read(&mut self, buf: &mut [u8]) -> AxResult { + let mut read_len = 0; + while read_len < buf.len() { + if let Some(c) = console_read_bytes() { + buf[read_len] = c; + read_len += 1; + } else { + break; + } + } + Ok(read_len) + } +} + +impl Write for StdoutRaw { + fn write(&mut self, buf: &[u8]) -> AxResult { + console_write_bytes(buf) + } + + fn flush(&mut self) -> AxResult { + Ok(()) + } +} + +pub struct Stdin { + inner: &'static Mutex>, +} + +impl Stdin { + // Block until at least one byte is read. + fn read_blocked(&self, buf: &mut [u8]) -> AxResult { + let read_len = self.inner.lock().read(buf)?; + if buf.is_empty() || read_len > 0 { + return Ok(read_len); + } + // try again until we get something + loop { + let read_len = self.inner.lock().read(buf)?; + if read_len > 0 { + return Ok(read_len); + } + crate::sys_sched_yield(); + } + } +} + +impl Read for Stdin { + fn read(&mut self, buf: &mut [u8]) -> AxResult { + self.read_blocked(buf) + } +} + +pub struct Stdout { + inner: &'static Mutex, +} + +impl Write for Stdout { + fn write(&mut self, buf: &[u8]) -> AxResult { + self.inner.lock().write(buf) + } + + fn flush(&mut self) -> AxResult { + self.inner.lock().flush() + } +} + +/// Constructs a new handle to the standard input of the current process. +pub fn stdin() -> Stdin { + static INSTANCE: Mutex> = Mutex::new(BufReader::new(StdinRaw)); + Stdin { inner: &INSTANCE } +} + +/// Constructs a new handle to the standard output of the current process. +pub fn stdout() -> Stdout { + static INSTANCE: Mutex = Mutex::new(StdoutRaw); + Stdout { inner: &INSTANCE } +} + +#[cfg(feature = "fd")] +impl super::fd_ops::FileLike for Stdin { + fn read(&self, buf: &mut [u8]) -> LinuxResult { + Ok(self.read_blocked(buf)?) + } + + fn write(&self, _buf: &[u8]) -> LinuxResult { + Err(LinuxError::EPERM) + } + + fn stat(&self) -> LinuxResult { + let st_mode = 0o20000 | 0o440u32; // S_IFCHR | r--r----- + Ok(crate::ctypes::stat { + st_ino: 1, + st_nlink: 1, + st_mode, + ..Default::default() + }) + } + + fn into_any(self: Arc) -> Arc { + self + } + + fn poll(&self) -> LinuxResult { + Ok(PollState { + readable: true, + writable: true, + }) + } + + fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { + Ok(()) + } +} + +#[cfg(feature = "fd")] +impl super::fd_ops::FileLike for Stdout { + fn read(&self, _buf: &mut [u8]) -> LinuxResult { + Err(LinuxError::EPERM) + } + + fn write(&self, buf: &[u8]) -> LinuxResult { + Ok(self.inner.lock().write(buf)?) + } + + fn stat(&self) -> LinuxResult { + let st_mode = 0o20000 | 0o220u32; // S_IFCHR | -w--w---- + Ok(crate::ctypes::stat { + st_ino: 1, + st_nlink: 1, + st_mode, + ..Default::default() + }) + } + + fn into_any(self: Arc) -> Arc { + self + } + + fn poll(&self) -> LinuxResult { + Ok(PollState { + readable: true, + writable: true, + }) + } + + fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { + Ok(()) + } +} diff --git a/api/arceos_posix_api/src/imp/sys.rs b/api/arceos_posix_api/src/imp/sys.rs new file mode 100644 index 0000000000..0e7a432927 --- /dev/null +++ b/api/arceos_posix_api/src/imp/sys.rs @@ -0,0 +1,29 @@ +use core::ffi::{c_int, c_long}; + +use crate::ctypes; + +const PAGE_SIZE_4K: usize = 4096; + +/// Return system configuration infomation +/// +/// Notice: currently only support what unikraft covers +pub fn sys_sysconf(name: c_int) -> c_long { + debug!("sys_sysconf <= {}", name); + syscall_body!(sys_sysconf, { + match name as u32 { + // Page size + ctypes::_SC_PAGE_SIZE => Ok(PAGE_SIZE_4K), + // Total physical pages + ctypes::_SC_PHYS_PAGES => Ok(axconfig::PHYS_MEMORY_SIZE / PAGE_SIZE_4K), + // Number of processors in use + ctypes::_SC_NPROCESSORS_ONLN => Ok(axconfig::SMP), + // Avaliable physical pages + #[cfg(feature = "alloc")] + ctypes::_SC_AVPHYS_PAGES => Ok(axalloc::global_allocator().available_pages()), + // Maximum number of files per process + #[cfg(feature = "fd")] + ctypes::_SC_OPEN_MAX => Ok(super::fd_ops::AX_FILE_LIMIT), + _ => Ok(0), + } + }) +} diff --git a/api/arceos_posix_api/src/imp/task.rs b/api/arceos_posix_api/src/imp/task.rs new file mode 100644 index 0000000000..5ba05feef3 --- /dev/null +++ b/api/arceos_posix_api/src/imp/task.rs @@ -0,0 +1,40 @@ +use core::ffi::c_int; + +/// Relinquish the CPU, and switches to another task. +/// +/// For single-threaded configuration (`multitask` feature is disabled), we just +/// relax the CPU and wait for incoming interrupts. +pub fn sys_sched_yield() -> c_int { + #[cfg(feature = "multitask")] + axtask::yield_now(); + #[cfg(not(feature = "multitask"))] + if cfg!(feature = "irq") { + axhal::arch::wait_for_irqs(); + } else { + core::hint::spin_loop(); + } + 0 +} + +/// Get current thread ID. +pub fn sys_getpid() -> c_int { + syscall_body!(sys_getpid, + #[cfg(feature = "multitask")] + { + Ok(axtask::current().id().as_u64() as c_int) + } + #[cfg(not(feature = "multitask"))] + { + Ok(2) // `main` task ID + } + ) +} + +/// Exit current task +pub fn sys_exit(exit_code: c_int) -> ! { + debug!("sys_exit <= {}", exit_code); + #[cfg(feature = "multitask")] + axtask::exit(exit_code); + #[cfg(not(feature = "multitask"))] + axhal::misc::terminate(); +} diff --git a/api/arceos_posix_api/src/imp/time.rs b/api/arceos_posix_api/src/imp/time.rs new file mode 100644 index 0000000000..56fa3a1fe2 --- /dev/null +++ b/api/arceos_posix_api/src/imp/time.rs @@ -0,0 +1,84 @@ +use axerrno::LinuxError; +use core::ffi::{c_int, c_long}; +use core::time::Duration; + +use crate::ctypes; + +impl From for Duration { + fn from(ts: ctypes::timespec) -> Self { + Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32) + } +} + +impl From for Duration { + fn from(tv: ctypes::timeval) -> Self { + Duration::new(tv.tv_sec as u64, tv.tv_usec as u32 * 1000) + } +} + +impl From for ctypes::timespec { + fn from(d: Duration) -> Self { + ctypes::timespec { + tv_sec: d.as_secs() as c_long, + tv_nsec: d.subsec_nanos() as c_long, + } + } +} + +impl From for ctypes::timeval { + fn from(d: Duration) -> Self { + ctypes::timeval { + tv_sec: d.as_secs() as c_long, + tv_usec: d.subsec_micros() as c_long, + } + } +} + +/// Get clock time since booting +pub unsafe fn sys_clock_gettime(_clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { + syscall_body!(sys_clock_gettime, { + if ts.is_null() { + return Err(LinuxError::EFAULT); + } + let now = axhal::time::current_time().into(); + unsafe { *ts = now }; + debug!("sys_clock_gettime: {}.{:09}s", now.tv_sec, now.tv_nsec); + Ok(0) + }) +} + +/// Sleep some nanoseconds +/// +/// TODO: should be woken by signals, and set errno +pub unsafe fn sys_nanosleep(req: *const ctypes::timespec, rem: *mut ctypes::timespec) -> c_int { + syscall_body!(sys_nanosleep, { + unsafe { + if req.is_null() || (*req).tv_nsec < 0 || (*req).tv_nsec > 999999999 { + return Err(LinuxError::EINVAL); + } + } + + let dur = unsafe { + debug!("sys_nanosleep <= {}.{:09}s", (*req).tv_sec, (*req).tv_nsec); + Duration::from(*req) + }; + + let now = axhal::time::current_time(); + + #[cfg(feature = "multitask")] + axtask::sleep(dur); + #[cfg(not(feature = "multitask"))] + axhal::time::busy_wait(dur); + + let after = axhal::time::current_time(); + let actual = after - now; + + if let Some(diff) = dur.checked_sub(actual) { + if !rem.is_null() { + unsafe { (*rem) = diff.into() }; + } + return Err(LinuxError::EINTR); + } + Ok(0) + }) +} diff --git a/api/arceos_posix_api/src/lib.rs b/api/arceos_posix_api/src/lib.rs new file mode 100644 index 0000000000..1e0e126e9e --- /dev/null +++ b/api/arceos_posix_api/src/lib.rs @@ -0,0 +1,62 @@ +//! POSIX-compatible APIs for [ArceOS] modules +//! +//! [ArceOS]: https://github.com/rcore-os/arceos + +#![cfg_attr(all(not(test), not(doc)), no_std)] +#![feature(ip_in_core)] +#![feature(result_option_inspect)] +#![feature(doc_cfg)] +#![feature(doc_auto_cfg)] +#![allow(clippy::missing_safety_doc)] + +#[macro_use] +extern crate axlog; +extern crate axruntime; + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[macro_use] +mod utils; + +mod imp; + +/// Platform-specific constants and parameters. +pub mod config { + pub use axconfig::*; +} + +/// POSIX C types. +#[rustfmt::skip] +#[path = "./ctypes_gen.rs"] +#[allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, clippy::upper_case_acronyms, missing_docs)] +pub mod ctypes; + +pub use imp::io::{sys_read, sys_write, sys_writev}; +pub use imp::resources::{sys_getrlimit, sys_setrlimit}; +pub use imp::sys::sys_sysconf; +pub use imp::task::{sys_exit, sys_getpid, sys_sched_yield}; +pub use imp::time::{sys_clock_gettime, sys_nanosleep}; + +#[cfg(feature = "fd")] +pub use imp::fd_ops::{sys_close, sys_dup, sys_dup2, sys_fcntl}; +#[cfg(feature = "fs")] +pub use imp::fs::{sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_rename, sys_stat}; +#[cfg(feature = "select")] +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 = "net")] +pub use imp::net::{ + sys_accept, sys_bind, sys_connect, sys_freeaddrinfo, sys_getaddrinfo, sys_getpeername, + sys_getsockname, sys_listen, sys_recv, sys_recvfrom, sys_send, sys_sendto, sys_shutdown, + sys_socket, +}; +#[cfg(feature = "pipe")] +pub use imp::pipe::sys_pipe; +#[cfg(feature = "multitask")] +pub use imp::pthread::mutex::{ + sys_pthread_mutex_init, sys_pthread_mutex_lock, sys_pthread_mutex_unlock, +}; +#[cfg(feature = "multitask")] +pub use imp::pthread::{sys_pthread_create, sys_pthread_exit, sys_pthread_join, sys_pthread_self}; diff --git a/api/arceos_posix_api/src/utils.rs b/api/arceos_posix_api/src/utils.rs new file mode 100644 index 0000000000..664bf5231c --- /dev/null +++ b/api/arceos_posix_api/src/utils.rs @@ -0,0 +1,61 @@ +#![allow(dead_code)] +#![allow(unused_macros)] + +use axerrno::{LinuxError, LinuxResult}; +use core::ffi::{c_char, CStr}; + +pub fn char_ptr_to_str<'a>(str: *const c_char) -> LinuxResult<&'a str> { + if str.is_null() { + Err(LinuxError::EFAULT) + } else { + unsafe { CStr::from_ptr(str) } + .to_str() + .map_err(|_| LinuxError::EINVAL) + } +} + +pub fn check_null_ptr(ptr: *const T) -> LinuxResult { + if ptr.is_null() { + Err(LinuxError::EFAULT) + } else { + Ok(()) + } +} + +pub fn check_null_mut_ptr(ptr: *mut T) -> LinuxResult { + if ptr.is_null() { + Err(LinuxError::EFAULT) + } else { + Ok(()) + } +} + +macro_rules! syscall_body { + ($fn: ident, $($stmt: tt)*) => {{ + #[allow(clippy::redundant_closure_call)] + let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); + match res { + Ok(_) | Err(axerrno::LinuxError::EAGAIN) => debug!(concat!(stringify!($fn), " => {:?}"), res), + Err(_) => info!(concat!(stringify!($fn), " => {:?}"), res), + } + match res { + Ok(v) => v as _, + Err(e) => { + -e.code() as _ + } + } + }}; +} + +macro_rules! syscall_body_no_debug { + ($($stmt: tt)*) => {{ + #[allow(clippy::redundant_closure_call)] + let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); + match res { + Ok(v) => v as _, + Err(e) => { + -e.code() as _ + } + } + }}; +} diff --git a/apps/c/httpclient/httpclient.c b/apps/c/httpclient/httpclient.c index 6bccbc4b79..32ec77b58a 100644 --- a/apps/c/httpclient/httpclient.c +++ b/apps/c/httpclient/httpclient.c @@ -1,8 +1,8 @@ +#include #include +#include #include #include -#include -#include #include const char request[] = "\ @@ -49,5 +49,8 @@ int main() } rebuf[l] = '\0'; printf("%s\n", rebuf); + + freeaddrinfo(res); + return 0; } diff --git a/apps/c/pthread/pipe/main.c b/apps/c/pthread/pipe/main.c index a32d829c18..3f7bedd4bc 100644 --- a/apps/c/pthread/pipe/main.c +++ b/apps/c/pthread/pipe/main.c @@ -18,6 +18,7 @@ void *ChildFunc(void *arg) sleep(1); } close(fd[1]); + return NULL; } void main() diff --git a/scripts/make/build_c.mk b/scripts/make/build_c.mk index 9241a76b3e..cb92d16737 100644 --- a/scripts/make/build_c.mk +++ b/scripts/make/build_c.mk @@ -5,7 +5,6 @@ ulib_dir := ulib/axlibc src_dir := $(ulib_dir)/c obj_dir := $(ulib_dir)/build_$(ARCH) inc_dir := $(ulib_dir)/include -inc_gen_dir = $(ulib_dir)/include_gen c_lib := $(obj_dir)/libc.a libgcc := @@ -55,7 +54,7 @@ $(obj_dir): $(call run_cmd,mkdir,-p $@) $(obj_dir)/%.o: $(src_dir)/%.c $(last_cflags) - $(call run_cmd,$(CC),$(CFLAGS) -I$(inc_gen_dir) -c -o $@ $<) + $(call run_cmd,$(CC),$(CFLAGS) -c -o $@ $<) $(c_lib): $(obj_dir) _check_need_rebuild $(ulib_obj) $(call run_cmd,$(AR),rcs $@ $(ulib_obj)) diff --git a/ulib/axlibc/.gitignore b/ulib/axlibc/.gitignore index b451c48a19..b5b452628e 100644 --- a/ulib/axlibc/.gitignore +++ b/ulib/axlibc/.gitignore @@ -1,4 +1,3 @@ -ctypes_gen.rs -include_gen/*.h +src/libctypes_gen.rs include/ax_pthread_mutex.h build_* diff --git a/ulib/axlibc/Cargo.toml b/ulib/axlibc/Cargo.toml index 8883da6cfb..703e79e014 100644 --- a/ulib/axlibc/Cargo.toml +++ b/ulib/axlibc/Cargo.toml @@ -23,49 +23,35 @@ crate-type = ["staticlib"] default = [] # Multicore -smp = ["axstd/smp"] +smp = ["arceos_posix_api/smp"] # Floating point/SIMD -fp_simd = ["axstd/fp_simd"] +fp_simd = ["axfeat/fp_simd"] # Memory -alloc = ["axstd/alloc", "dep:axalloc"] +alloc = ["arceos_posix_api/alloc"] +tls = ["alloc", "axfeat/tls"] # Multi-task -multitask = ["axstd/multitask", "axtask/multitask"] +multitask = ["arceos_posix_api/multitask"] # File system -fs = ["axstd/fs", "fd"] +fs = ["arceos_posix_api/fs", "fd"] # Networking -net = ["axstd/net", "dep:axnet", "fd"] +net = ["arceos_posix_api/net", "fd"] # Libc features -fd = ["alloc"] -pipe = ["fd"] -select = ["fd"] -epoll = ["fd"] +fd = [] +pipe = ["arceos_posix_api/pipe"] +select = ["arceos_posix_api/select"] +epoll = ["arceos_posix_api/epoll"] [dependencies] -# ArceOS modules axfeat = { path = "../../api/axfeat" } -axstd = { path = "../axstd" } -axhal = { path = "../../modules/axhal" } -axlog = { path = "../../modules/axlog" } -axconfig = { path = "../../modules/axconfig" } -axalloc = { path = "../../modules/axalloc", optional = true } -axnet = { path = "../../modules/axnet", optional = true } -axtask = { path = "../../modules/axtask", optional = true } - -# Other crates +arceos_posix_api = { path = "../../api/arceos_posix_api" } axio = { path = "../../crates/axio" } axerrno = { path = "../../crates/axerrno" } -static_assertions = "1.1.0" -spin = { version = "0.9" } -lazy_static = { version = "1.4", features = ["spin_no_std"] } -flatten_objects = { path = "../../crates/flatten_objects" } [build-dependencies] -cbindgen = { version = "0.24" } bindgen ={ version = "0.66" } -axconfig = { path = "../../modules/axconfig" } diff --git a/ulib/axlibc/build.rs b/ulib/axlibc/build.rs index 00db83a591..6c33c929c7 100644 --- a/ulib/axlibc/build.rs +++ b/ulib/axlibc/build.rs @@ -1,113 +1,17 @@ fn main() { - use std::io::Write; - use std::path::{Path, PathBuf}; - - fn gen_ax_config(out_file: &str) -> std::io::Result<()> { - let mut output = Vec::new(); - writeln!(output, "//! Generated by build.rs, DO NOT edit!\n")?; - writeln!( - output, - "#define AX_CONFIG_TASK_STACK_SIZE {:#x}", - axconfig::TASK_STACK_SIZE, - )?; - - std::fs::write(out_file, output)?; - Ok(()) - } - - fn gen_pthread_mutex(out_file: &str) -> std::io::Result<()> { - // TODO: generate size and initial content automatically. - let (mutex_size, mutex_init) = if cfg!(feature = "multitask") { - if cfg!(feature = "smp") { - (6, "{0, 8, 0, 0, 0, 0}") // core::mem::transmute::<_, [usize; 6]>(axsync::Mutex::new(())) - } else { - (5, "{8, 0, 0, 0, 0}") // core::mem::transmute::<_, [usize; 5]>(axsync::Mutex::new(())) - } - } else { - (1, "{0}") - }; - - let mut output = Vec::new(); - writeln!(output, "//! Generated by build.rs, DO NOT edit!")?; - writeln!( - output, - r#" -typedef struct {{ - long __l[{mutex_size}]; -}} pthread_mutex_t; - -#define PTHREAD_MUTEX_INITIALIZER {{ .__l = {mutex_init}}} -"# - )?; - std::fs::write(out_file, output)?; - Ok(()) - } - - fn gen_rust_to_c_bindings(crate_dir: &Path, out_file: &str) { - // load configs from "cbindgen.toml" - cbindgen::generate(crate_dir) - .expect("Unable to generate rust->c bindings") - .write_to_file(out_file); - } - fn gen_c_to_rust_bindings(in_file: &str, out_file: &str) { println!("cargo:rerun-if-changed={in_file}"); - let allow_types = [ - "stat", - "size_t", - "ssize_t", - "off_t", - "mode_t", - "O_*", - "sock.*", - "FILE", - "jmp_buf", - "fd.*", - "timeval", - "pthread_.*", - "epoll_event", - "iovec", - "tm", - ]; - let allow_vars = [ - "O_.*", - "AF_.*", - "SOCK_.*", - "IPPROTO_.*", - "FD_.*", - "F_.*", - "_SC_.*", - "SO_.*", - "SOL_.*", - "EPOLL_CTL_.*", - "EPOLL.*", - ]; - - #[derive(Debug)] - struct MyCallbacks; - - impl bindgen::callbacks::ParseCallbacks for MyCallbacks { - fn include_file(&self, fname: &str) { - if !fname.contains("ax_pthread_mutex.h") { - println!("cargo:rerun-if-changed={}", fname); - } - } - } - + let allow_types = ["tm", "jmp_buf"]; let mut builder = bindgen::Builder::default() .header(in_file) .clang_arg("-I./include") - .parse_callbacks(Box::new(MyCallbacks)) .derive_default(true) .size_t_is_usize(false) .use_core(); for ty in allow_types { builder = builder.allowlist_type(ty); } - for var in allow_vars { - builder = builder.allowlist_var(var); - } builder .generate() @@ -116,9 +20,5 @@ typedef struct {{ .expect("Couldn't write bindings!"); } - let crate_dir = PathBuf::from(&std::env::var("CARGO_MANIFEST_DIR").unwrap()); - gen_rust_to_c_bindings(&crate_dir, "include_gen/axlibc.h"); - gen_ax_config("include_gen/axconfig.h").unwrap(); - gen_pthread_mutex("include/ax_pthread_mutex.h").unwrap(); - gen_c_to_rust_bindings("ctypes.h", "src/ctypes_gen.rs"); + gen_c_to_rust_bindings("ctypes.h", "src/libctypes_gen.rs"); } diff --git a/ulib/axlibc/c/epoll.c b/ulib/axlibc/c/epoll.c deleted file mode 100644 index aaf62f2e1a..0000000000 --- a/ulib/axlibc/c/epoll.c +++ /dev/null @@ -1,23 +0,0 @@ -#ifdef AX_CONFIG_EPOLL - -#include -#include - -#include - -int epoll_create(int size) -{ - return ax_epoll_create(size); -} - -int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) -{ - return ax_epoll_ctl(fd, op, fd2, ev); -} - -int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to) -{ - return ax_epoll_wait(fd, ev, cnt, to); -} - -#endif // AX_CONFIG_EPOLL diff --git a/ulib/axlibc/c/fcntl.c b/ulib/axlibc/c/fcntl.c index 517c3ff301..fa9091713e 100644 --- a/ulib/axlibc/c/fcntl.c +++ b/ulib/axlibc/c/fcntl.c @@ -1,10 +1,12 @@ -#include #include #include #include #ifdef AX_CONFIG_FD +// TODO: remove this function in future work +int ax_fcntl(int fd, int cmd, size_t arg); + int fcntl(int fd, int cmd, ... /* arg */) { unsigned long arg; @@ -20,6 +22,9 @@ int fcntl(int fd, int cmd, ... /* arg */) #ifdef AX_CONFIG_FS +// TODO: remove this function in future work +int ax_open(const char *filename, int flags, mode_t mode); + int open(const char *filename, int flags, ...) { mode_t mode = 0; diff --git a/ulib/axlibc/c/mmap.c b/ulib/axlibc/c/mmap.c index 5382180af6..e3204d7148 100644 --- a/ulib/axlibc/c/mmap.c +++ b/ulib/axlibc/c/mmap.c @@ -1,11 +1,12 @@ #include #include +#include // TODO: void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) { unimplemented(); - return NULL; + return MAP_FAILED; } // TODO: diff --git a/ulib/axlibc/c/network.c b/ulib/axlibc/c/network.c index c00da7b45a..4c6beb845a 100644 --- a/ulib/axlibc/c/network.c +++ b/ulib/axlibc/c/network.c @@ -1,6 +1,5 @@ #ifdef AX_CONFIG_NET -#include #include #include #include @@ -14,39 +13,6 @@ int h_errno; -/*Only IPv4. Ports are always 0. Ignore service and hint. Results' ai_flags, ai_socktype, - * ai_protocol and ai_canonname are 0 or NULL. */ -int getaddrinfo(const char *__restrict node, const char *__restrict service, - const struct addrinfo *__restrict hints, struct addrinfo **__restrict res) -{ - struct sockaddr *addrs = (struct sockaddr *)malloc(MAXADDRS * sizeof(struct sockaddr)); - int res_len = ax_getaddrinfo(node, service, addrs, MAXADDRS); - if (res_len < 0) - return EAI_FAIL; - if (res_len == 0) - return EAI_NONAME; - struct addrinfo *_res = (struct addrinfo *)calloc(res_len, sizeof(struct addrinfo)); - for (int i = 0; i < res_len; i++) { - (_res + i)->ai_family = AF_INET; - (_res + i)->ai_addrlen = sizeof(struct sockaddr); - (_res + i)->ai_addr = (addrs + i); - (_res + i)->ai_next = (_res + i + 1); - // TODO: This is a hard-code part, only return TCP parameters - (_res + i)->ai_socktype = SOCK_STREAM; - (_res + i)->ai_protocol = IPPROTO_TCP; - } - (_res + res_len - 1)->ai_next = NULL; - *res = _res; - return 0; -} - -void freeaddrinfo(struct addrinfo *__restrict res) -{ - free(res->ai_addr); - free(res); - return; -} - static const char gai_msgs[] = "Invalid flags\0" "Name does not resolve\0" "Try again\0" diff --git a/ulib/axlibc/c/pthread.c b/ulib/axlibc/c/pthread.c index ac6bc26a6d..74fb1faf12 100644 --- a/ulib/axlibc/c/pthread.c +++ b/ulib/axlibc/c/pthread.c @@ -1,32 +1,11 @@ #ifdef AX_CONFIG_MULTITASK -#include #include #include #include +#include #include -_Noreturn void pthread_exit(void *result) -{ - ax_pthread_exit(result); -} - -pthread_t pthread_self(void) -{ - return ax_pthread_self(); -} - -int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, - void *(*entry)(void *), void *restrict arg) -{ - return ax_pthread_create(res, attrp, (void *)entry, arg); -} - -int pthread_join(pthread_t t, void **res) -{ - return ax_pthread_join(t, res); -} - int pthread_setcancelstate(int new, int *old) { unimplemented(); @@ -53,21 +32,6 @@ int pthread_cancel(pthread_t t) return 0; } -int pthread_mutex_init(pthread_mutex_t *restrict m, const pthread_mutexattr_t *restrict a) -{ - return ax_pthread_mutex_init(m, a); -} - -int pthread_mutex_lock(pthread_mutex_t *m) -{ - return ax_pthread_mutex_lock(m); -} - -int pthread_mutex_unlock(pthread_mutex_t *m) -{ - return ax_pthread_mutex_unlock(m); -} - // TODO int pthread_mutex_trylock(pthread_mutex_t *m) { diff --git a/ulib/axlibc/c/resource.c b/ulib/axlibc/c/resource.c index df7e6ee61e..3e34624cba 100644 --- a/ulib/axlibc/c/resource.c +++ b/ulib/axlibc/c/resource.c @@ -1,63 +1,7 @@ -#include #include #include #include -int getrlimit(int resource, struct rlimit *rlimits) -{ - switch (resource) { - case RLIMIT_DATA: - break; - case RLIMIT_STACK: - break; - case RLIMIT_NOFILE: - break; - default: - // Unsupported resource - return -EINVAL; - } - - if (!rlimits) - return 0; - switch (resource) { - case RLIMIT_STACK: - rlimits->rlim_cur = AX_CONFIG_TASK_STACK_SIZE; - rlimits->rlim_max = AX_CONFIG_TASK_STACK_SIZE; - break; - case RLIMIT_NOFILE: - rlimits->rlim_cur = AX_FILE_LIMIT; - rlimits->rlim_max = AX_FILE_LIMIT; - break; - default: - break; - } - return 0; -} - -int setrlimit(int resource, struct rlimit *rlimits) -{ - switch (resource) { - case RLIMIT_DATA: - break; - case RLIMIT_STACK: - break; - case RLIMIT_NOFILE: - break; - default: - // Unsupported resource - return -EINVAL; - } - // Set resouce - if (rlimits) { - switch (resource) { - default: - // Currently do not support set resources - break; - } - } - return 0; -} - // TODO int getrusage(int __who, struct rusage *__usage) { diff --git a/ulib/axlibc/c/select.c b/ulib/axlibc/c/select.c index 74dacfaf01..d20d5f6805 100644 --- a/ulib/axlibc/c/select.c +++ b/ulib/axlibc/c/select.c @@ -1,37 +1,11 @@ #ifdef AX_CONFIG_SELECT -#include #include #include #include #include #include -int select(int n, fd_set *__restrict rfds, fd_set *__restrict wfds, fd_set *__restrict efds, - struct timeval *__restrict tv) -{ - time_t s = tv ? tv->tv_sec : 0; - long us = tv ? tv->tv_usec : 0; - // long ns; - const time_t max_time = (1ULL << (8 * sizeof(time_t) - 1)) - 1; - - if (s < 0 || us < 0) { - errno = EINVAL; - return -1; - } - if (us / 1000000 > max_time - s) { - s = max_time; - us = 999999; - // ns = 999999999; - } else { - s += us / 1000000; - us %= 1000000; - // ns = us * 1000; - } - - return ax_select(n, rfds, wfds, efds, tv ? ((struct timeval *)(long[]){s, us}) : NULL); -} - int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec *restrict ts, const sigset_t *restrict mask) { diff --git a/ulib/axlibc/c/socket.c b/ulib/axlibc/c/socket.c index 74c8b713db..677e43198b 100644 --- a/ulib/axlibc/c/socket.c +++ b/ulib/axlibc/c/socket.c @@ -6,38 +6,6 @@ #include #include -#include - -int socket(int domain, int type, int protocol) -{ - return ax_socket(domain, type, protocol); -} - -int shutdown(int fd, int flag) -{ - return ax_shutdown(fd, flag); -} - -int bind(int fd, const struct sockaddr *addr, socklen_t len) -{ - return ax_bind(fd, addr, len); -} - -int connect(int fd, const struct sockaddr *addr, socklen_t len) -{ - return ax_connect(fd, addr, len); -} - -int listen(int fd, int backlog) -{ - return ax_listen(fd, backlog); -} - -int accept(int fd, struct sockaddr *restrict addr, socklen_t *restrict len) -{ - return ax_accept(fd, addr, len); -} - int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int flg) { if (!flg) @@ -56,34 +24,6 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int return ret; } -ssize_t send(int fd, const void *buf, size_t n, int flags) -{ - return ax_send(fd, buf, n, flags); -} - -ssize_t recv(int fd, void *buf, size_t n, int flags) -{ - return ax_recv(fd, buf, n, flags); -} - -ssize_t sendto(int fd, const void *buf, size_t n, int flags, const struct sockaddr *addr, - socklen_t addr_len) -{ - if (addr == NULL && addr_len == 0) - return ax_send(fd, buf, n, flags); - else - return ax_sendto(fd, buf, n, flags, addr, addr_len); -} - -ssize_t recvfrom(int fd, void *restrict buf, size_t n, int flags, struct sockaddr *restrict addr, - socklen_t *restrict addr_len) -{ - if (addr == NULL) - return ax_recv(fd, buf, n, flags); - else - return ax_recvfrom(fd, buf, n, flags, addr, addr_len); -} - int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen) { unimplemented(); @@ -97,16 +37,6 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt return 0; } -int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen) -{ - return ax_getsockname(sockfd, addr, addrlen); -} - -int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen) -{ - return ax_getpeername(sockfd, addr, addrlen); -} - // TODO ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) { diff --git a/ulib/axlibc/c/stdio.c b/ulib/axlibc/c/stdio.c index 98a32811a4..03ea75cf39 100644 --- a/ulib/axlibc/c/stdio.c +++ b/ulib/axlibc/c/stdio.c @@ -9,8 +9,13 @@ #include #include #include +#include -#include +// LOCK used by `puts()` +#ifdef AX_CONFIG_MULTITASK +#include +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +#endif #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -32,13 +37,7 @@ static int __write_buffer(FILE *f) int r = 0; if (f->buffer_len == 0) return 0; - if (f->fd == stdout->fd || f->fd == stderr->fd) { - r = ax_print_str(f->buf, f->buffer_len); -#ifdef AX_CONFIG_FD - } else { - r = write(f->fd, f->buf, f->buffer_len); -#endif - } + r = write(f->fd, f->buf, f->buffer_len); return r; } @@ -108,7 +107,19 @@ int putchar(int c) int puts(const char *s) { - return ax_println_str(s, strlen(s)); // TODO: lock +#ifdef AX_CONFIG_MULTITASK + pthread_mutex_lock(&lock); +#endif + + int r = write(1, (const void *)s, strlen(s)); + char brk[1] = {'\n'}; + write(1, (const void *)brk, 1); + +#ifdef AX_CONFIG_MULTITASK + pthread_mutex_unlock(&lock); +#endif + + return r; } void perror(const char *msg) @@ -199,7 +210,7 @@ FILE *fopen(const char *filename, const char *mode) flags = __fmodeflags(mode); // TODO: currently mode is unused in ax_open - int fd = ax_open(filename, flags, 0666); + int fd = open(filename, flags, 0666); if (fd < 0) return NULL; f->fd = fd; @@ -219,7 +230,7 @@ char *fgets(char *restrict s, int n, FILE *restrict f) int cnt = 0; while (cnt < n - 1) { char c; - if (ax_read(f->fd, (void *)&c, 1) > 0) { + if (read(f->fd, (void *)&c, 1) > 0) { if (c != '\n') s[cnt++] = c; else @@ -237,7 +248,7 @@ size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) size_t read_len = 0; size_t len = 0; do { - len = ax_read(f->fd, destv + read_len, total - read_len); + len = read(f->fd, destv + read_len, total - read_len); if (len < 0) break; read_len += len; @@ -251,7 +262,7 @@ size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restric size_t write_len = 0; size_t len = 0; do { - len = ax_write(f->fd, src + write_len, total - write_len); + len = write(f->fd, src + write_len, total - write_len); if (len < 0) break; write_len += len; @@ -267,13 +278,7 @@ int fputs(const char *restrict s, FILE *restrict f) int fclose(FILE *f) { - return ax_close(f->fd); -} - -// TODO -int rename(const char *old, const char *new) -{ - return ax_rename(old, new); + return close(f->fd); } int fileno(FILE *f) diff --git a/ulib/axlibc/c/stdlib.c b/ulib/axlibc/c/stdlib.c index 3c7b8e3da5..ef8a823680 100644 --- a/ulib/axlibc/c/stdlib.c +++ b/ulib/axlibc/c/stdlib.c @@ -7,43 +7,21 @@ #include #include -#include - char *program_invocation_short_name = "dummy"; char *program_invocation_name = "dummy"; #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) -void srand(unsigned s) -{ - ax_srand(s); -} - -int rand(void) -{ - return ax_rand_u32(); -} - -long random(void) -{ - return (long)ax_rand_u32(); -} - void srandom(unsigned int s) { - ax_srand(s); + srand(s); } #ifdef AX_CONFIG_ALLOC -void *malloc(size_t size) -{ - return ax_malloc(size); -} - void *calloc(size_t m, size_t n) { - void *mem = ax_malloc(m * n); + void *mem = malloc(m * n); return memset(mem, 0, n * m); } @@ -55,35 +33,17 @@ void *realloc(void *memblock, size_t size) size_t o_size = *(size_t *)(memblock - 8); - void *mem = ax_malloc(size); + void *mem = malloc(size); for (int i = 0; i < (o_size < size ? o_size : size); i++) ((char *)mem)[i] = ((char *)memblock)[i]; - ax_free(memblock); + free(memblock); return mem; } -void free(void *addr) -{ - if (!addr) - return; - return ax_free(addr); -} - #endif // AX_CONFIG_ALLOC -_Noreturn void abort(void) -{ - ax_panic(); - __builtin_unreachable(); -} - -_Noreturn void exit(int status) -{ - ax_exit(status); -} - long long llabs(long long a) { return a > 0 ? a : -a; @@ -386,16 +346,6 @@ unsigned long long strtoull(const char *nptr, char **endptr, int base) #ifdef AX_CONFIG_FP_SIMD -float strtof(const char *restrict s, char **restrict p) -{ - return ax_strtof(s, p); -} - -double strtod(const char *restrict s, char **restrict p) -{ - return ax_strtod(s, p); -} - // TODO: precision may not be enough long double strtold(const char *restrict s, char **restrict p) { diff --git a/ulib/axlibc/c/string.c b/ulib/axlibc/c/string.c index 6f48afb807..2c56d7e92d 100644 --- a/ulib/axlibc/c/string.c +++ b/ulib/axlibc/c/string.c @@ -5,8 +5,6 @@ #include #include -#include - size_t strlen(const char *s) { const char *a = s; @@ -221,11 +219,6 @@ char *strrchr(const char *s, int c) return isCharFind; } -char *strerror(int e) -{ - return ax_errno_string(e); -} - int strerror_r(int err, char *buf, size_t buflen) { char *msg = strerror(err); diff --git a/ulib/axlibc/c/time.c b/ulib/axlibc/c/time.c index a670c93e91..9a2384ad9d 100644 --- a/ulib/axlibc/c/time.c +++ b/ulib/axlibc/c/time.c @@ -5,8 +5,6 @@ #include #include -#include - long timezone = 0; const char __utc[] = "UTC"; @@ -21,14 +19,6 @@ const int HOUR_PER_DAY = 24; #define DAYS_PER_100Y (365 * 100 + 24) #define DAYS_PER_4Y (365 * 4 + 1) -#ifdef AX_CONFIG_ALLOC -size_t strftime(char *restrict buf, size_t size, const char *restrict format, - const struct tm *restrict timeptr) -{ - return ax_strftime(buf, size, format, timeptr); -} -#endif - int __secs_to_tm(long long t, struct tm *tm) { long long days, secs, years; @@ -152,7 +142,7 @@ struct tm *localtime(const time_t *timep) time_t time(time_t *t) { struct timespec ts; - ax_clock_gettime(&ts); + clock_gettime(CLOCK_REALTIME, &ts); time_t ret = ts.tv_sec; if (t) *t = ret; @@ -177,17 +167,6 @@ int utimes(const char *filename, const struct timeval times[2]) return 0; } -// TODO: Should match _clk, -int clock_gettime(clockid_t _clk, struct timespec *ts) -{ - return ax_clock_gettime(ts); -} - -int nanosleep(const struct timespec *req, struct timespec *rem) -{ - return ax_nanosleep(req, rem); -} - // TODO void tzset() { @@ -222,8 +201,3 @@ double difftime(time_t t1, time_t t0) return t1 - t0; } #endif - -time_t mktime(struct tm *tm) -{ - return ax_mktime(tm); -} diff --git a/ulib/axlibc/c/uio.c b/ulib/axlibc/c/uio.c deleted file mode 100644 index 8a7781f22a..0000000000 --- a/ulib/axlibc/c/uio.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -#include - -ssize_t writev(int fd, const struct iovec *iovec, int count) -{ - return ax_writev(fd, iovec, count); -} diff --git a/ulib/axlibc/c/unistd.c b/ulib/axlibc/c/unistd.c index ceb5fde841..eec49bf6bd 100644 --- a/ulib/axlibc/c/unistd.c +++ b/ulib/axlibc/c/unistd.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -14,16 +13,6 @@ uid_t geteuid(void) return 0; } -pid_t getpid(void) -{ -#ifdef AX_CONFIG_MULTITASK - return ax_getpid(); -#else - // return 'main' task Id - return 2; -#endif -} - // TODO uid_t getuid(void) { @@ -63,58 +52,6 @@ int usleep(unsigned useconds) return nanosleep(&tv, &tv); } -long sysconf(int name) -{ - return ax_sysconf(name); -} - -#ifdef AX_CONFIG_FD - -int close(int fd) -{ - return ax_close(fd); -} - -int fstat(int fd, struct stat *buf) -{ - return ax_fstat(fd, buf); -} - -ssize_t read(int fd, void *buf, size_t count) -{ - return ax_read(fd, buf, count); -} - -ssize_t write(int fd, const void *buf, size_t count) -{ - return ax_write(fd, buf, count); -} - -int dup(int fd) -{ - return ax_dup(fd); -} - -int dup2(int old, int new) -{ - int r; - if (old == new) { - r = fcntl(old, F_GETFD); - if (r >= 0) - return old; - else - return r; - } - return ax_dup3(old, new, 0); -} - -int dup3(int old, int new, int flags) -{ - return ax_dup3(old, new, flags); -} - -#endif // AX_CONFIG_FD - #ifdef AX_CONFIG_FS // TODO: @@ -124,21 +61,6 @@ int access(const char *pathname, int mode) return 0; } -char *getcwd(char *buf, size_t size) -{ - return ax_getcwd(buf, size); -} - -int lstat(const char *path, struct stat *buf) -{ - return ax_lstat(path, buf); -} - -int stat(const char *path, struct stat *buf) -{ - return ax_stat(path, buf); -} - // TODO: ssize_t readlink(const char *path, char *buf, size_t bufsiz) { @@ -160,11 +82,6 @@ int rmdir(const char *pathname) return 0; } -off_t lseek(int fd, off_t offset, int whence) -{ - return ax_lseek(fd, offset, whence); -} - // TODO: int fsync(int fd) { @@ -211,11 +128,6 @@ int truncate(const char *path, off_t length) #ifdef AX_CONFIG_PIPE -int pipe(int fd[2]) -{ - return ax_pipe(&fd[0], &fd[1]); -} - int pipe2(int fd[2], int flag) { if (!flag) @@ -244,7 +156,7 @@ int pipe2(int fd[2], int flag) // TODO _Noreturn void _exit(int status) { - ax_exit(status); + exit(status); } // TODO diff --git a/ulib/axlibc/cbindgen.toml b/ulib/axlibc/cbindgen.toml deleted file mode 100644 index 4aa16d9801..0000000000 --- a/ulib/axlibc/cbindgen.toml +++ /dev/null @@ -1,29 +0,0 @@ -language = "C" -cpp_compat = true -no_includes = false -usize_is_size_t = true -header = "/* Generated by cbindgen and build.rs, DO NOT edit! */" -sys_includes = [ - "sys/types.h", - "sys/stat.h", - "stdio.h", - "time.h", - "sys/epoll.h", - "sys/socket.h", - "sys/select.h", - "sys/time.h", - "pthread.h", -] -includes = ["axconfig.h"] - -[export.rename] -"stat" = "struct stat" -"sockaddr" = "struct sockaddr" -"timespec" = "struct timespec" -"timeval" = "struct timeval" -"epoll_event" = "struct epoll_event" -"iovec" = "struct iovec" -"tm" = "struct tm" - -[fn] -no_return = "__attribute__((noreturn))" diff --git a/ulib/axlibc/ctypes.h b/ulib/axlibc/ctypes.h index e58d4dad7f..882ec691c7 100644 --- a/ulib/axlibc/ctypes.h +++ b/ulib/axlibc/ctypes.h @@ -1,16 +1,2 @@ -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include diff --git a/ulib/axlibc/include/netdb.h b/ulib/axlibc/include/netdb.h index 84f3bdfdd2..6272578b7f 100644 --- a/ulib/axlibc/include/netdb.h +++ b/ulib/axlibc/include/netdb.h @@ -1,8 +1,6 @@ #ifndef _NETDB_H #define _NETDB_H -#ifdef AX_CONFIG_NET - #include struct addrinfo { @@ -76,8 +74,9 @@ const char *hstrerror(int ecode); #define MAXSERVS 2 #define MAXADDRS 48 -int getaddrinfo(const char *__restrict, const char *__restrict, const struct addrinfo *__restrict, - struct addrinfo **__restrict); +#ifdef AX_CONFIG_NET + +int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); void freeaddrinfo(struct addrinfo *); const char *gai_strerror(int __ecode); diff --git a/ulib/axlibc/include_gen/.gitkeep b/ulib/axlibc/include_gen/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/ulib/axlibc/src/errno.rs b/ulib/axlibc/src/errno.rs index 581ea6879a..a804793269 100644 --- a/ulib/axlibc/src/errno.rs +++ b/ulib/axlibc/src/errno.rs @@ -2,8 +2,7 @@ use axerrno::LinuxError; use core::ffi::{c_char, c_int}; /// The global errno variable. -/// -/// TODO: this should be thread-local. +#[cfg_attr(feature = "tls", thread_local)] #[no_mangle] #[allow(non_upper_case_globals)] pub static mut errno: c_int = 0; @@ -22,7 +21,7 @@ pub unsafe extern "C" fn __errno_location() -> *mut c_int { /// Returns a pointer to the string representation of the given error code. #[no_mangle] -pub unsafe extern "C" fn ax_errno_string(e: c_int) -> *mut c_char { +pub unsafe extern "C" fn strerror(e: c_int) -> *mut c_char { #[allow(non_upper_case_globals)] static mut strerror_buf: [u8; 256] = [0; 256]; // TODO: thread safe diff --git a/ulib/axlibc/src/fd_ops.rs b/ulib/axlibc/src/fd_ops.rs index 38112a92ba..1b1a9d0001 100644 --- a/ulib/axlibc/src/fd_ops.rs +++ b/ulib/axlibc/src/fd_ops.rs @@ -1,182 +1,54 @@ -use alloc::sync::Arc; -use core::ffi::{c_int, c_void}; - -use axerrno::{LinuxError, LinuxResult}; -use axio::PollState; -use axstd::io::{stdin, stdout}; -use flatten_objects::FlattenObjects; -use spin::RwLock; - -use crate::ctypes; - -pub const AX_FILE_LIMIT: usize = 1024; - -pub trait FileLike: Send + Sync { - fn read(&self, buf: &mut [u8]) -> LinuxResult; - fn write(&self, buf: &[u8]) -> LinuxResult; - fn stat(&self) -> LinuxResult; - fn into_any(self: Arc) -> Arc; - fn poll(&self) -> LinuxResult; - fn set_nonblocking(&self, nonblocking: bool) -> LinuxResult; -} - -lazy_static::lazy_static! { - static ref FD_TABLE: RwLock, AX_FILE_LIMIT>> = { - let mut fd_table = FlattenObjects::new(); - fd_table.add_at(0, Arc::new(stdin()) as _).unwrap(); // stdin - fd_table.add_at(1, Arc::new(stdout()) as _).unwrap(); // stdout - fd_table.add_at(2, Arc::new(stdout()) as _).unwrap(); // stderr - RwLock::new(fd_table) - }; -} - -pub fn get_file_like(fd: c_int) -> LinuxResult> { - FD_TABLE - .read() - .get(fd as usize) - .cloned() - .ok_or(LinuxError::EBADF) -} - -pub fn add_file_like(f: Arc) -> LinuxResult { - Ok(FD_TABLE.write().add(f).ok_or(LinuxError::EMFILE)? as _) -} - -pub fn close_file_like(fd: c_int) -> LinuxResult { - let f = FD_TABLE - .write() - .remove(fd as usize) - .ok_or(LinuxError::EBADF)?; - drop(f); - Ok(()) -} +use crate::{ctypes, utils::e}; +use arceos_posix_api::{sys_close, sys_dup, sys_dup2, sys_fcntl}; +use axerrno::LinuxError; +use core::ffi::c_int; /// Close a file by `fd`. #[no_mangle] -pub unsafe extern "C" fn ax_close(fd: c_int) -> c_int { - debug!("ax_close <= {}", fd); - if (0..2).contains(&fd) { - return 0; // stdin, stdout, stderr - } - ax_call_body!(ax_close, close_file_like(fd).map(|_| 0)) +pub unsafe extern "C" fn close(fd: c_int) -> c_int { + e(sys_close(fd)) } -/// Read data from the file indicated by `fd`. -/// -/// Return the read size if success. +/// Duplicate a file descriptor. #[no_mangle] -pub unsafe extern "C" fn ax_read(fd: c_int, buf: *mut c_void, count: usize) -> ctypes::ssize_t { - debug!("ax_read <= {} {:#x} {}", fd, buf as usize, count); - ax_call_body!(ax_read, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, count) }; - get_file_like(fd)?.read(dst) - }) +pub unsafe extern "C" fn dup(old_fd: c_int) -> c_int { + e(sys_dup(old_fd)) } -/// Write data to the file indicated by `fd`. -/// -/// Return the written size if success. +/// Duplicate a file descriptor, use file descriptor specified in `new_fd`. #[no_mangle] -pub unsafe extern "C" fn ax_write(fd: c_int, buf: *const c_void, count: usize) -> ctypes::ssize_t { - debug!("ax_write <= {} {:#x} {}", fd, buf as usize, count); - ax_call_body!(ax_write, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - let src = unsafe { core::slice::from_raw_parts(buf as *const u8, count) }; - get_file_like(fd)?.write(src) - }) +pub unsafe extern "C" fn dup2(old_fd: c_int, new_fd: c_int) -> c_int { + e(sys_dup2(old_fd, new_fd)) } -/// Get file metadata by `fd` and write into `buf`. -/// -/// Return 0 if success. -#[no_mangle] -pub unsafe extern "C" fn ax_fstat(fd: c_int, buf: *mut ctypes::stat) -> ctypes::ssize_t { - debug!("ax_fstat <= {} {:#x}", fd, buf as usize); - ax_call_body!(ax_fstat, { - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - unsafe { *buf = get_file_like(fd)?.stat()? }; - Ok(0) - }) -} - -fn dup_fd(old_fd: c_int) -> LinuxResult { - let f = get_file_like(old_fd)?; - let new_fd = add_file_like(f)?; - Ok(new_fd) -} - -/// Duplicate a file descriptor -#[no_mangle] -pub unsafe extern "C" fn ax_dup(old_fd: c_int) -> c_int { - debug!("ax_dup <= {}", old_fd); - ax_call_body!(ax_dup, dup_fd(old_fd)) -} - -/// `dup3()` is the same as `dup2()`, except that: -/// -/// The caller can force the close-on-exec flag to be set for the new file descriptor by specifying `O_CLOEXEC` in flags. +/// Duplicate a file descriptor, the caller can force the close-on-exec flag to +/// be set for the new file descriptor by specifying `O_CLOEXEC` in flags. /// /// If oldfd equals newfd, then `dup3()` fails with the error `EINVAL`. #[no_mangle] -pub unsafe extern "C" fn ax_dup3(old_fd: c_int, new_fd: c_int, flags: c_int) -> c_int { - debug!( - "ax_dup3 <= old_fd: {}, new_fd: {}, flags: {}", - old_fd, new_fd, flags - ); - - ax_call_body!(ax_dup3, { - if old_fd == new_fd { - return Err(LinuxError::EINVAL); - } - if new_fd as usize >= AX_FILE_LIMIT { - return Err(LinuxError::EBADF); - } - - let f = get_file_like(old_fd)?; - FD_TABLE - .write() - .add_at(new_fd as usize, f) - .ok_or(LinuxError::EMFILE)?; - +pub unsafe extern "C" fn dup3(old_fd: c_int, new_fd: c_int, flags: c_int) -> c_int { + if old_fd == new_fd { + return e((LinuxError::EINVAL as c_int).wrapping_neg()); + } + let r = e(sys_dup2(old_fd, new_fd)); + if r < 0 { + r + } else { if flags as u32 & ctypes::O_CLOEXEC != 0 { - ax_fcntl( + e(sys_fcntl( new_fd, ctypes::F_SETFD as c_int, ctypes::FD_CLOEXEC as usize, - ); + )); } - Ok(new_fd) - }) + new_fd + } } -/// Fcntl implementation +/// Manipulate file descriptor. /// /// TODO: `SET/GET` command is ignored #[no_mangle] pub unsafe extern "C" fn ax_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int { - debug!("ax_fcntl <= fd: {} cmd: {} arg: {}", fd, cmd, arg); - ax_call_body!(ax_fcntl, { - match cmd as u32 { - ctypes::F_DUPFD => dup_fd(fd), - ctypes::F_DUPFD_CLOEXEC => { - // TODO: Change fd flags - dup_fd(fd) - } - ctypes::F_SETFL => { - get_file_like(fd)?.set_nonblocking(arg & (ctypes::O_NONBLOCK as usize) > 0)?; - Ok(0) - } - _ => { - warn!("unsupported fcntl parameters: cmd {}", cmd); - Ok(0) - } - } - }) + e(sys_fcntl(fd, cmd, arg)) } diff --git a/ulib/axlibc/src/fs.rs b/ulib/axlibc/src/fs.rs new file mode 100644 index 0000000000..bd93f8876b --- /dev/null +++ b/ulib/axlibc/src/fs.rs @@ -0,0 +1,67 @@ +use core::ffi::{c_char, c_int}; + +use arceos_posix_api::{ + sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_rename, sys_stat, +}; + +use crate::{ctypes, utils::e}; + +/// Open a file by `filename` and insert it into the file descriptor table. +/// +/// Return its index in the file table (`fd`). Return `EMFILE` if it already +/// has the maximum number of files open. +#[no_mangle] +pub unsafe extern "C" fn ax_open( + filename: *const c_char, + flags: c_int, + mode: ctypes::mode_t, +) -> c_int { + e(sys_open(filename, flags, mode)) +} + +/// Set the position of the file indicated by `fd`. +/// +/// Return its position after seek. +#[no_mangle] +pub unsafe extern "C" fn lseek(fd: c_int, offset: ctypes::off_t, whence: c_int) -> ctypes::off_t { + e(sys_lseek(fd, offset, whence) as _) as _ +} + +/// Get the file metadata by `path` and write into `buf`. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn stat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { + e(sys_stat(path, buf)) +} + +/// Get file metadata by `fd` and write into `buf`. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn fstat(fd: c_int, buf: *mut ctypes::stat) -> c_int { + e(sys_fstat(fd, buf)) +} + +/// Get the metadata of the symbolic link and write into `buf`. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { + e(sys_lstat(path, buf) as _) +} + +/// Get the path of the current directory. +#[no_mangle] +pub unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char { + sys_getcwd(buf, size) +} + +/// Rename `old` to `new` +/// If new exists, it is first removed. +/// +/// Return 0 if the operation succeeds, otherwise return -1. +#[no_mangle] +pub unsafe extern "C" fn rename(old: *const c_char, new: *const c_char) -> c_int { + e(sys_rename(old, new)) +} diff --git a/ulib/axlibc/src/io.rs b/ulib/axlibc/src/io.rs new file mode 100644 index 0000000000..ea6187b71f --- /dev/null +++ b/ulib/axlibc/src/io.rs @@ -0,0 +1,32 @@ +use core::ffi::{c_int, c_void}; + +use arceos_posix_api::{sys_read, sys_write, sys_writev}; + +use crate::{ctypes, utils::e}; + +/// Read data from the file indicated by `fd`. +/// +/// Return the read size if success. +#[no_mangle] +pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: usize) -> ctypes::ssize_t { + e(sys_read(fd, buf, count) as _) as _ +} + +/// Write data to the file indicated by `fd`. +/// +/// Return the written size if success. +#[no_mangle] +#[cfg(not(test))] +pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> ctypes::ssize_t { + e(sys_write(fd, buf, count) as _) as _ +} + +/// Write a vector. +#[no_mangle] +pub unsafe extern "C" fn writev( + fd: c_int, + iov: *const ctypes::iovec, + iocnt: c_int, +) -> ctypes::ssize_t { + e(sys_writev(fd, iov, iocnt) as _) as _ +} diff --git a/ulib/axlibc/src/io_mpx.rs b/ulib/axlibc/src/io_mpx.rs new file mode 100644 index 0000000000..2bcffc7e0d --- /dev/null +++ b/ulib/axlibc/src/io_mpx.rs @@ -0,0 +1,54 @@ +use crate::{ctypes, utils::e}; + +use core::ffi::c_int; + +#[cfg(feature = "select")] +use arceos_posix_api::sys_select; +#[cfg(feature = "epoll")] +use arceos_posix_api::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; + +/// Creates a new epoll instance. +/// +/// It returns a file descriptor referring to the new epoll instance. +#[cfg(feature = "epoll")] +#[no_mangle] +pub unsafe extern "C" fn epoll_create(size: c_int) -> c_int { + e(sys_epoll_create(size)) +} + +/// Control interface for an epoll file descriptor +#[cfg(feature = "epoll")] +#[no_mangle] +pub unsafe extern "C" fn epoll_ctl( + epfd: c_int, + op: c_int, + fd: c_int, + event: *mut ctypes::epoll_event, +) -> c_int { + e(sys_epoll_ctl(epfd, op, fd, event)) +} + +/// Waits for events on the epoll instance referred to by the file descriptor epfd. +#[cfg(feature = "epoll")] +#[no_mangle] +pub unsafe extern "C" fn epoll_wait( + epfd: c_int, + events: *mut ctypes::epoll_event, + maxevents: c_int, + timeout: c_int, +) -> c_int { + e(sys_epoll_wait(epfd, events, maxevents, 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 = "select")] +#[no_mangle] +pub unsafe extern "C" fn select( + nfds: c_int, + readfds: *mut ctypes::fd_set, + writefds: *mut ctypes::fd_set, + exceptfds: *mut ctypes::fd_set, + timeout: *mut ctypes::timeval, +) -> c_int { + e(sys_select(nfds, readfds, writefds, exceptfds, timeout)) +} diff --git a/ulib/axlibc/src/io_mpx/mod.rs b/ulib/axlibc/src/io_mpx/mod.rs deleted file mode 100644 index f7f1eb2b53..0000000000 --- a/ulib/axlibc/src/io_mpx/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! I/O multiplexing: -//! -//! * [`select`](select::ax_select) -//! * [`epoll_create`](epoll::ax_epoll_create) -//! * [`epoll_ctl`](epoll::ax_epoll_ctl) -//! * [`epoll_wait`](epoll::ax_epoll_wait) - -#[cfg(feature = "epoll")] -mod epoll; -#[cfg(feature = "select")] -mod select; - -#[cfg(feature = "epoll")] -pub use self::epoll::{ax_epoll_create, ax_epoll_ctl, ax_epoll_wait}; -#[cfg(feature = "select")] -pub use self::select::ax_select; diff --git a/ulib/axlibc/src/lib.rs b/ulib/axlibc/src/lib.rs index b2aadf429a..7bb8cc80cf 100644 --- a/ulib/axlibc/src/lib.rs +++ b/ulib/axlibc/src/lib.rs @@ -1,11 +1,25 @@ //! [ArceOS] user program library for C apps. //! -//! # Cargo Features +//! ## Cargo Features //! -//! - `fd`: Enable file descriptor table. -//! - `pipe`: Enable pipe support. -//! - `select`: Enable synchronous I/O multiplexing ([select]) support. -//! - `epoll`: Enable event polling ([epoll]) support. +//! - CPU +//! - `smp`: Enable SMP (symmetric multiprocessing) support. +//! - `fp_simd`: Enable floating point and SIMD support. +//! - Interrupts: +//! - `irq`: Enable interrupt handling support. +//! - Memory +//! - `alloc`: Enable dynamic memory allocation. +//! - `tls`: Enable thread-local storage. +//! - Task management +//! - `multitask`: Enable multi-threading support. +//! - Upperlayer stacks +//! - `fs`: Enable file system support. +//! - `net`: Enable networking support. +//! - Lib C functions +//! - `fd`: Enable file descriptor table. +//! - `pipe`: Enable pipe support. +//! - `select`: Enable synchronous I/O multiplexing ([select]) support. +//! - `epoll`: Enable event polling ([epoll]) support. //! //! [ArceOS]: https://github.com/rcore-os/arceos //! [select]: https://man7.org/linux/man-pages/man2/select.2.html @@ -14,23 +28,23 @@ #![cfg_attr(all(not(test), not(doc)), no_std)] #![feature(doc_cfg)] #![feature(doc_auto_cfg)] -#![feature(ip_in_core)] -#![feature(int_roundings)] #![feature(naked_functions)] -#![feature(result_option_inspect)] +#![feature(thread_local)] #![allow(clippy::missing_safety_doc)] -#[macro_use] -extern crate axlog; - #[cfg(feature = "alloc")] extern crate alloc; -/// cbindgen:ignore -#[rustfmt::skip] -#[path = "./ctypes_gen.rs"] -#[allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, clippy::upper_case_acronyms)] -mod ctypes; +#[path = "."] +mod ctypes { + #[rustfmt::skip] + #[path = "libctypes_gen.rs"] + #[allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, clippy::upper_case_acronyms)] + mod libctypes; + + pub use arceos_posix_api::ctypes::*; + pub use libctypes::*; +} #[macro_use] mod utils; @@ -38,86 +52,74 @@ mod utils; #[cfg(feature = "fd")] mod fd_ops; #[cfg(feature = "fs")] -mod file; +mod fs; #[cfg(any(feature = "select", feature = "epoll"))] mod io_mpx; #[cfg(feature = "alloc")] mod malloc; +#[cfg(feature = "net")] +mod net; #[cfg(feature = "pipe")] mod pipe; #[cfg(feature = "multitask")] mod pthread; -#[cfg(feature = "net")] -mod socket; #[cfg(feature = "alloc")] mod strftime; #[cfg(feature = "fp_simd")] mod strtod; -#[cfg(feature = "fd")] -mod uio; mod errno; +mod io; mod mktime; mod rand; +mod resource; mod setjmp; -mod stdio; mod sys; mod time; +mod unistd; -/// Abort the current process. -#[no_mangle] -pub unsafe extern "C" fn ax_panic() -> ! { - panic!() -} - -/// Exits the current thread. -#[no_mangle] -pub unsafe extern "C" fn ax_exit(exit_code: core::ffi::c_int) -> ! { - axstd::thread::exit(exit_code) -} +#[cfg(not(test))] +pub use self::io::write; +pub use self::io::{read, writev}; -pub use self::rand::{ax_rand_u32, ax_srand}; +pub use self::errno::strerror; +pub use self::mktime::mktime; +pub use self::rand::{rand, random, srand}; +pub use self::resource::{getrlimit, setrlimit}; +pub use self::setjmp::{longjmp, setjmp}; +pub use self::sys::sysconf; +pub use self::time::{clock_gettime, nanosleep}; +pub use self::unistd::{abort, exit, getpid}; #[cfg(feature = "alloc")] -pub use self::malloc::{ax_free, ax_malloc}; +pub use self::malloc::{free, malloc}; #[cfg(feature = "alloc")] -pub use self::strftime::ax_strftime; +pub use self::strftime::strftime; #[cfg(feature = "fd")] -pub use self::fd_ops::{ax_close, ax_dup, ax_dup3, ax_fcntl, ax_fstat, ax_read, ax_write}; -#[cfg(feature = "fd")] -pub use self::uio::ax_writev; +pub use self::fd_ops::{ax_fcntl, close, dup, dup2, dup3}; #[cfg(feature = "fs")] -pub use self::file::{ax_getcwd, ax_lseek, ax_lstat, ax_open, ax_stat}; +pub use self::fs::{ax_open, fstat, getcwd, lseek, lstat, rename, stat}; #[cfg(feature = "net")] -pub use self::socket::{ - ax_accept, ax_bind, ax_connect, ax_getaddrinfo, ax_getpeername, ax_getsockname, ax_listen, - ax_recv, ax_recvfrom, ax_send, ax_sendto, ax_shutdown, ax_socket, +pub use self::net::{ + accept, bind, connect, freeaddrinfo, getaddrinfo, getpeername, getsockname, listen, recv, + recvfrom, send, sendto, shutdown, socket, }; #[cfg(feature = "multitask")] -pub use self::pthread::mutex::{ - ax_pthread_mutex_init, ax_pthread_mutex_lock, ax_pthread_mutex_unlock, -}; +pub use self::pthread::{pthread_create, pthread_exit, pthread_join, pthread_self}; #[cfg(feature = "multitask")] -pub use self::pthread::{ax_getpid, ax_pthread_create, ax_pthread_exit, ax_pthread_join}; +pub use self::pthread::{pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock}; #[cfg(feature = "pipe")] -pub use self::pipe::ax_pipe; +pub use self::pipe::pipe; #[cfg(feature = "select")] -pub use self::io_mpx::ax_select; - +pub use self::io_mpx::select; #[cfg(feature = "epoll")] -pub use self::io_mpx::{ax_epoll_create, ax_epoll_ctl, ax_epoll_wait}; +pub use self::io_mpx::{epoll_create, epoll_ctl, epoll_wait}; #[cfg(feature = "fp_simd")] -pub use self::strtod::{ax_strtod, ax_strtof}; - -pub use self::errno::ax_errno_string; -pub use self::mktime::ax_mktime; -pub use self::stdio::{ax_print_str, ax_println_str}; -pub use self::sys::ax_sysconf; -pub use self::time::{ax_clock_gettime, ax_nanosleep}; +pub use self::strtod::{strtod, strtof}; diff --git a/ulib/axlibc/src/malloc.rs b/ulib/axlibc/src/malloc.rs index e45590c3f9..f635b7ff0a 100644 --- a/ulib/axlibc/src/malloc.rs +++ b/ulib/axlibc/src/malloc.rs @@ -10,6 +10,8 @@ use alloc::alloc::{alloc, dealloc}; use core::alloc::Layout; use core::ffi::c_void; +use crate::ctypes; + struct MemoryControlBlock { size: usize, } @@ -20,7 +22,7 @@ const CTRL_BLK_SIZE: usize = core::mem::size_of::(); /// /// Returns 0 on failure (the current implementation does not trigger an exception) #[no_mangle] -pub unsafe extern "C" fn ax_malloc(size: usize) -> *mut c_void { +pub unsafe extern "C" fn malloc(size: ctypes::size_t) -> *mut c_void { // Allocate `(actual length) + 8`. The lowest 8 Bytes are stored in the actual allocated space size. // This is because free(uintptr_t) has only one parameter representing the address, // So we need to save in advance to know the size of the memory space that needs to be released @@ -39,7 +41,10 @@ pub unsafe extern "C" fn ax_malloc(size: usize) -> *mut c_void { /// occur, but it will NOT be checked out. This is due to the global allocator `Buddy_system` /// (currently used) does not check the validity of address to be released. #[no_mangle] -pub unsafe extern "C" fn ax_free(ptr: *mut c_void) { +pub unsafe extern "C" fn free(ptr: *mut c_void) { + if ptr.is_null() { + return; + } let ptr = ptr.cast::(); assert!(ptr as usize > CTRL_BLK_SIZE, "free a null pointer"); unsafe { diff --git a/ulib/axlibc/src/mktime.rs b/ulib/axlibc/src/mktime.rs index 3f86a064ee..1caf3325b0 100644 --- a/ulib/axlibc/src/mktime.rs +++ b/ulib/axlibc/src/mktime.rs @@ -14,9 +14,9 @@ fn leap_year(year: c_int) -> bool { year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) } -/// `mktime` implementation +/// Convert broken-down time into time since the Epoch. #[no_mangle] -pub unsafe extern "C" fn ax_mktime(t: *mut ctypes::tm) -> ctypes::time_t { +pub unsafe extern "C" fn mktime(t: *mut ctypes::tm) -> ctypes::time_t { let mut year = (*t).tm_year + 1900; let mut month = (*t).tm_mon; let mut day = (*t).tm_mday as i64 - 1; diff --git a/ulib/axlibc/src/net.rs b/ulib/axlibc/src/net.rs new file mode 100644 index 0000000000..e092181570 --- /dev/null +++ b/ulib/axlibc/src/net.rs @@ -0,0 +1,180 @@ +use arceos_posix_api::{ + sys_accept, sys_bind, sys_connect, sys_freeaddrinfo, sys_getaddrinfo, sys_getpeername, + sys_getsockname, sys_listen, sys_recv, sys_recvfrom, sys_send, sys_sendto, sys_shutdown, + sys_socket, +}; +use core::ffi::{c_char, c_int, c_void}; + +use crate::{ctypes, utils::e}; + +/// Create an socket for communication. +/// +/// Return the socket file descriptor. +#[no_mangle] +pub unsafe extern "C" fn socket(domain: c_int, socktype: c_int, protocol: c_int) -> c_int { + e(sys_socket(domain, socktype, protocol)) +} + +/// Bind a address to a socket. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn bind( + socket_fd: c_int, + socket_addr: *const ctypes::sockaddr, + addrlen: ctypes::socklen_t, +) -> c_int { + e(sys_bind(socket_fd, socket_addr, addrlen)) +} + +/// Connects the socket to the address specified. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn connect( + socket_fd: c_int, + socket_addr: *const ctypes::sockaddr, + addrlen: ctypes::socklen_t, +) -> c_int { + e(sys_connect(socket_fd, socket_addr, addrlen)) +} + +/// Send a message on a socket to the address specified. +/// +/// Return the number of bytes sent if success. +#[no_mangle] +pub unsafe extern "C" fn sendto( + socket_fd: c_int, + buf_ptr: *const c_void, + len: ctypes::size_t, + flag: c_int, // currently not used + socket_addr: *const ctypes::sockaddr, + addrlen: ctypes::socklen_t, +) -> ctypes::ssize_t { + if socket_addr.is_null() && addrlen == 0 { + return e(sys_send(socket_fd, buf_ptr, len, flag) as _) as _; + } + e(sys_sendto(socket_fd, buf_ptr, len, flag, socket_addr, addrlen) as _) as _ +} + +/// Send a message on a socket to the address connected. +/// +/// Return the number of bytes sent if success. +#[no_mangle] +pub unsafe extern "C" fn send( + socket_fd: c_int, + buf_ptr: *const c_void, + len: ctypes::size_t, + flag: c_int, // currently not used +) -> ctypes::ssize_t { + e(sys_send(socket_fd, buf_ptr, len, flag) as _) as _ +} + +/// Receive a message on a socket and get its source address. +/// +/// Return the number of bytes received if success. +#[no_mangle] +pub unsafe extern "C" fn recvfrom( + socket_fd: c_int, + buf_ptr: *mut c_void, + len: ctypes::size_t, + flag: c_int, // currently not used + socket_addr: *mut ctypes::sockaddr, + addrlen: *mut ctypes::socklen_t, +) -> ctypes::ssize_t { + if socket_addr.is_null() { + return e(sys_recv(socket_fd, buf_ptr, len, flag) as _) as _; + } + e(sys_recvfrom(socket_fd, buf_ptr, len, flag, socket_addr, addrlen) as _) as _ +} + +/// Receive a message on a socket. +/// +/// Return the number of bytes received if success. +#[no_mangle] +pub unsafe extern "C" fn recv( + socket_fd: c_int, + buf_ptr: *mut c_void, + len: ctypes::size_t, + flag: c_int, // currently not used +) -> ctypes::ssize_t { + e(sys_recv(socket_fd, buf_ptr, len, flag) as _) as _ +} + +/// Listen for connections on a socket +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn listen( + socket_fd: c_int, + backlog: c_int, // currently not used +) -> c_int { + e(sys_listen(socket_fd, backlog)) +} + +/// Accept for connections on a socket +/// +/// Return file descriptor for the accepted socket if success. +#[no_mangle] +pub unsafe extern "C" fn accept( + socket_fd: c_int, + socket_addr: *mut ctypes::sockaddr, + socket_len: *mut ctypes::socklen_t, +) -> c_int { + e(sys_accept(socket_fd, socket_addr, socket_len)) +} + +/// Shut down a full-duplex connection. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn shutdown( + socket_fd: c_int, + flag: c_int, // currently not used +) -> c_int { + e(sys_shutdown(socket_fd, flag)) +} + +/// Query addresses for a domain name. +/// +/// Return address number if success. +#[no_mangle] +pub unsafe extern "C" fn getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + hints: *const ctypes::addrinfo, + res: *mut *mut ctypes::addrinfo, +) -> c_int { + let ret = e(sys_getaddrinfo(nodename, servname, hints, res)); + match ret { + r if r < 0 => ctypes::EAI_FAIL, + 0 => ctypes::EAI_NONAME, + _ => 0, + } +} + +/// Free queried `addrinfo` struct +#[no_mangle] +pub unsafe extern "C" fn freeaddrinfo(res: *mut ctypes::addrinfo) { + sys_freeaddrinfo(res); +} + +/// Get current address to which the socket sockfd is bound. +#[no_mangle] +pub unsafe extern "C" fn getsockname( + sock_fd: c_int, + addr: *mut ctypes::sockaddr, + addrlen: *mut ctypes::socklen_t, +) -> c_int { + e(sys_getsockname(sock_fd, addr, addrlen)) +} + +/// Get peer address to which the socket sockfd is connected. +#[no_mangle] +pub unsafe extern "C" fn getpeername( + sock_fd: c_int, + addr: *mut ctypes::sockaddr, + addrlen: *mut ctypes::socklen_t, +) -> c_int { + e(sys_getpeername(sock_fd, addr, addrlen)) +} diff --git a/ulib/axlibc/src/pipe.rs b/ulib/axlibc/src/pipe.rs index 6ace49f8b2..2bed253c0a 100644 --- a/ulib/axlibc/src/pipe.rs +++ b/ulib/axlibc/src/pipe.rs @@ -1,210 +1,14 @@ -use alloc::sync::Arc; use core::ffi::c_int; -use axerrno::{LinuxError, LinuxResult}; -use axio::PollState; -use axstd::sync::Mutex; -use axstd::thread::yield_now; +use arceos_posix_api::sys_pipe; -use crate::{ctypes, fd_ops::FileLike}; - -#[derive(Copy, Clone, PartialEq)] -enum RingBufferStatus { - Full, - Empty, - Normal, -} - -const RING_BUFFER_SIZE: usize = 256; - -pub struct PipeRingBuffer { - arr: [u8; RING_BUFFER_SIZE], - head: usize, - tail: usize, - status: RingBufferStatus, -} - -impl PipeRingBuffer { - pub const fn new() -> Self { - Self { - arr: [0; RING_BUFFER_SIZE], - head: 0, - tail: 0, - status: RingBufferStatus::Empty, - } - } - - pub fn write_byte(&mut self, byte: u8) { - self.status = RingBufferStatus::Normal; - self.arr[self.tail] = byte; - self.tail = (self.tail + 1) % RING_BUFFER_SIZE; - if self.tail == self.head { - self.status = RingBufferStatus::Full; - } - } - - pub fn read_byte(&mut self) -> u8 { - self.status = RingBufferStatus::Normal; - let c = self.arr[self.head]; - self.head = (self.head + 1) % RING_BUFFER_SIZE; - if self.head == self.tail { - self.status = RingBufferStatus::Empty; - } - c - } - - /// Get the length of remaining data in the buffer - pub const fn available_read(&self) -> usize { - if matches!(self.status, RingBufferStatus::Empty) { - 0 - } else if self.tail > self.head { - self.tail - self.head - } else { - self.tail + RING_BUFFER_SIZE - self.head - } - } - - /// Get the length of remaining space in the buffer - pub const fn available_write(&self) -> usize { - if matches!(self.status, RingBufferStatus::Full) { - 0 - } else { - RING_BUFFER_SIZE - self.available_read() - } - } -} - -pub struct Pipe { - readable: bool, - buffer: Arc>, -} - -impl Pipe { - pub fn new() -> (Pipe, Pipe) { - let buffer = Arc::new(Mutex::new(PipeRingBuffer::new())); - let read_end = Pipe { - readable: true, - buffer: buffer.clone(), - }; - let write_end = Pipe { - readable: false, - buffer, - }; - (read_end, write_end) - } - - pub const fn readable(&self) -> bool { - self.readable - } - - pub const fn writable(&self) -> bool { - !self.readable - } - - pub fn write_end_close(&self) -> bool { - Arc::strong_count(&self.buffer) == 1 - } -} - -impl FileLike for Pipe { - fn read(&self, buf: &mut [u8]) -> LinuxResult { - if !self.readable() { - return Err(LinuxError::EPERM); - } - let mut read_size = 0usize; - let max_len = buf.len(); - loop { - let mut ring_buffer = self.buffer.lock(); - let loop_read = ring_buffer.available_read(); - if loop_read == 0 { - if self.write_end_close() { - return Ok(read_size); - } - drop(ring_buffer); - // Data not ready, wait for write end - yield_now(); // TODO: use synconize primitive - continue; - } - for _ in 0..loop_read { - if read_size == max_len { - return Ok(read_size); - } - buf[read_size] = ring_buffer.read_byte(); - read_size += 1; - } - } - } - - fn write(&self, buf: &[u8]) -> LinuxResult { - if !self.writable() { - return Err(LinuxError::EPERM); - } - let mut write_size = 0usize; - let max_len = buf.len(); - loop { - let mut ring_buffer = self.buffer.lock(); - let loop_write = ring_buffer.available_write(); - if loop_write == 0 { - drop(ring_buffer); - // Buffer is full, wait for read end to consume - yield_now(); // TODO: use synconize primitive - continue; - } - for _ in 0..loop_write { - if write_size == max_len { - return Ok(write_size); - } - ring_buffer.write_byte(buf[write_size]); - write_size += 1; - } - } - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o10000 | 0o600u32; // S_IFIFO | rw------- - Ok(ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - st_uid: 1000, - st_gid: 1000, - st_blksize: 4096, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - let buf = self.buffer.lock(); - Ok(PollState { - readable: self.readable() && buf.available_read() > 0, - writable: self.writable() && buf.available_write() > 0, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} +use crate::utils::e; /// Create a pipe /// /// Return 0 if succeed #[no_mangle] -pub unsafe extern "C" fn ax_pipe(fd1: *mut c_int, fd2: *mut c_int) -> c_int { - ax_call_body!(ax_pipe, { - let (read_end, write_end) = Pipe::new(); - let read_fd = super::fd_ops::add_file_like(Arc::new(read_end))?; - let write_fd = super::fd_ops::add_file_like(Arc::new(write_end)).inspect_err(|_| { - super::fd_ops::close_file_like(read_fd).ok(); - })?; - unsafe { - *fd1 = read_fd as c_int; - *fd2 = write_fd as c_int; - } - Ok(0) - }) +pub unsafe extern "C" fn pipe(fd: *mut c_int) -> c_int { + let fds = unsafe { core::slice::from_raw_parts_mut(fd, 2) }; + e(sys_pipe(fds)) } diff --git a/ulib/axlibc/src/pthread.rs b/ulib/axlibc/src/pthread.rs new file mode 100644 index 0000000000..b170b8b7a0 --- /dev/null +++ b/ulib/axlibc/src/pthread.rs @@ -0,0 +1,59 @@ +use crate::{ctypes, utils::e}; +use arceos_posix_api as api; +use core::ffi::{c_int, c_void}; + +/// Returns the `pthread` struct of current thread. +#[no_mangle] +pub unsafe extern "C" fn pthread_self() -> ctypes::pthread_t { + api::sys_pthread_self() +} + +/// Create a new thread with the given entry point and argument. +/// +/// If successful, it stores the pointer to the newly created `struct __pthread` +/// in `res` and returns 0. +#[no_mangle] +pub unsafe extern "C" fn pthread_create( + res: *mut ctypes::pthread_t, + attr: *const ctypes::pthread_attr_t, + start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, + arg: *mut c_void, +) -> c_int { + e(api::sys_pthread_create(res, attr, start_routine, arg)) +} + +/// Exits the current thread. The value `retval` will be returned to the joiner. +#[no_mangle] +pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! { + api::sys_pthread_exit(retval) +} + +/// Waits for the given thread to exit, and stores the return value in `retval`. +#[no_mangle] +pub unsafe extern "C" fn pthread_join( + thread: ctypes::pthread_t, + retval: *mut *mut c_void, +) -> c_int { + e(api::sys_pthread_join(thread, retval)) +} + +/// Initialize a mutex. +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_init( + mutex: *mut ctypes::pthread_mutex_t, + attr: *const ctypes::pthread_mutexattr_t, +) -> c_int { + e(api::sys_pthread_mutex_init(mutex, attr)) +} + +/// Lock the given mutex. +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { + e(api::sys_pthread_mutex_lock(mutex)) +} + +/// Unlock the given mutex. +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { + e(api::sys_pthread_mutex_unlock(mutex)) +} diff --git a/ulib/axlibc/src/rand.rs b/ulib/axlibc/src/rand.rs index 5ac5daface..682f4231c1 100644 --- a/ulib/axlibc/src/rand.rs +++ b/ulib/axlibc/src/rand.rs @@ -1,19 +1,30 @@ //! Random number generator. -use core::sync::atomic::{AtomicU64, Ordering::SeqCst}; +use core::{ + ffi::{c_int, c_long, c_uint}, + sync::atomic::{AtomicU64, Ordering::SeqCst}, +}; static SEED: AtomicU64 = AtomicU64::new(0xa2ce_a2ce); /// Sets the seed for the random number generator. #[no_mangle] -pub unsafe extern "C" fn ax_srand(seed: u32) { +pub unsafe extern "C" fn srand(seed: c_uint) { SEED.store(seed.wrapping_sub(1) as u64, SeqCst); } /// Returns a 32-bit unsigned pseudo random interger. #[no_mangle] -pub unsafe extern "C" fn ax_rand_u32() -> u32 { +pub unsafe extern "C" fn rand() -> c_int { let new_seed = SEED.load(SeqCst).wrapping_mul(6364136223846793005) + 1; SEED.store(new_seed, SeqCst); - (new_seed >> 33) as u32 + (new_seed >> 33) as c_int +} + +/// Returns a 64-bit unsigned pseudo random number. +#[no_mangle] +pub unsafe extern "C" fn random() -> c_long { + let new_seed = SEED.load(SeqCst).wrapping_mul(6364136223846793005) + 1; + SEED.store(new_seed, SeqCst); + new_seed as c_long } diff --git a/ulib/axlibc/src/resource.rs b/ulib/axlibc/src/resource.rs new file mode 100644 index 0000000000..20e013e501 --- /dev/null +++ b/ulib/axlibc/src/resource.rs @@ -0,0 +1,17 @@ +use core::ffi::c_int; + +use arceos_posix_api::{sys_getrlimit, sys_setrlimit}; + +use crate::utils::e; + +/// Get resource limitations +#[no_mangle] +pub unsafe extern "C" fn getrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { + e(sys_getrlimit(resource, rlimits)) +} + +/// Set resource limitations +#[no_mangle] +pub unsafe extern "C" fn setrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { + e(sys_setrlimit(resource, rlimits)) +} diff --git a/ulib/axlibc/src/setjmp.rs b/ulib/axlibc/src/setjmp.rs index dd49583cea..aed4441ffc 100644 --- a/ulib/axlibc/src/setjmp.rs +++ b/ulib/axlibc/src/setjmp.rs @@ -1,11 +1,11 @@ use core::ffi::c_int; -use super::ctypes; +use crate::ctypes; /// `setjmp` implementation #[naked] #[no_mangle] -unsafe extern "C" fn setjmp(_buf: *mut ctypes::__jmp_buf_tag) { +pub unsafe extern "C" fn setjmp(_buf: *mut ctypes::__jmp_buf_tag) { #[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] core::arch::asm!( " @@ -122,7 +122,7 @@ unsafe extern "C" fn setjmp(_buf: *mut ctypes::__jmp_buf_tag) { /// `longjmp` implementation #[naked] #[no_mangle] -unsafe extern "C" fn longjmp(_buf: *mut ctypes::__jmp_buf_tag, _val: c_int) -> ! { +pub unsafe extern "C" fn longjmp(_buf: *mut ctypes::__jmp_buf_tag, _val: c_int) -> ! { #[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] core::arch::asm!( "ldp x19, x20, [x0,#0] diff --git a/ulib/axlibc/src/stdio.rs b/ulib/axlibc/src/stdio.rs deleted file mode 100644 index f3baec917d..0000000000 --- a/ulib/axlibc/src/stdio.rs +++ /dev/null @@ -1,109 +0,0 @@ -use core::ffi::{c_char, c_int}; - -use axerrno::LinuxError; -use axstd::io::{self, Write}; - -#[cfg(feature = "fd")] -use {alloc::sync::Arc, axerrno::LinuxResult, axio::PollState, axstd::io::Read}; - -/// Print a string to the global standard output stream. -#[no_mangle] -pub unsafe extern "C" fn ax_print_str(buf: *const c_char, count: usize) -> c_int { - ax_call_body_no_debug!({ - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - - let bytes = unsafe { core::slice::from_raw_parts(buf as *const u8, count as _) }; - let len = io::stdout().write(bytes)?; - Ok(len as c_int) - }) -} - -/// Print a string to the global standard output stream. Add a line break. -#[no_mangle] -pub unsafe extern "C" fn ax_println_str(buf: *const c_char, count: usize) -> c_int { - ax_call_body_no_debug!({ - if buf.is_null() { - return Err(LinuxError::EFAULT); - } - - let bytes = unsafe { core::slice::from_raw_parts(buf as *const u8, count as _) }; - let mut stdout = io::stdout().lock(); - let len = stdout.write(bytes)?; - let len = stdout.write(b"\n")? + len; - Ok(len as c_int) - }) -} - -#[cfg(feature = "fd")] -impl super::fd_ops::FileLike for axstd::io::Stdin { - fn read(&self, buf: &mut [u8]) -> LinuxResult { - Ok(self.lock().read(buf)?) - } - - fn write(&self, _buf: &[u8]) -> LinuxResult { - Err(LinuxError::EPERM) - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o20000 | 0o440u32; // S_IFCHR | r--r----- - Ok(super::ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - Ok(PollState { - readable: true, - writable: true, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} - -#[cfg(feature = "fd")] -impl super::fd_ops::FileLike for axstd::io::Stdout { - fn read(&self, _buf: &mut [u8]) -> LinuxResult { - Err(LinuxError::EPERM) - } - - fn write(&self, buf: &[u8]) -> LinuxResult { - Ok(self.lock().write(buf)?) - } - - fn stat(&self) -> LinuxResult { - let st_mode = 0o20000 | 0o220u32; // S_IFCHR | -w--w---- - Ok(super::ctypes::stat { - st_ino: 1, - st_nlink: 1, - st_mode, - ..Default::default() - }) - } - - fn into_any(self: Arc) -> Arc { - self - } - - fn poll(&self) -> LinuxResult { - Ok(PollState { - readable: true, - writable: true, - }) - } - - fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult { - Ok(()) - } -} diff --git a/ulib/axlibc/src/strftime.rs b/ulib/axlibc/src/strftime.rs index eec3643f9f..aa3c010a34 100644 --- a/ulib/axlibc/src/strftime.rs +++ b/ulib/axlibc/src/strftime.rs @@ -10,6 +10,7 @@ pub trait WriteByte: fmt::Write { } struct StringWriter(pub *mut u8, pub usize); + impl Write for StringWriter { fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { if self.1 > 1 { @@ -96,7 +97,7 @@ impl Write for CountingWriter { } } -unsafe fn strftime( +unsafe fn strftime_inner( w: W, format: *const c_char, t: *const ctypes::tm, @@ -208,7 +209,7 @@ unsafe fn strftime( b'r' => w!(recurse "%I:%M:%S %p"), b'R' => w!(recurse "%H:%M"), // Nothing is modified in mktime, but the C standard of course requires a mutable pointer ._. - b's' => w!("{}", super::ax_mktime(t as *mut ctypes::tm)), + b's' => w!("{}", super::mktime(t as *mut ctypes::tm)), b'S' => w!("{:02}", (*t).tm_sec), b'T' => w!(recurse "%H:%M:%S"), b'u' => w!("{}", ((*t).tm_wday + 7 - 1) % 7 + 1), @@ -236,15 +237,15 @@ unsafe fn strftime( w.written } -/// `strftime` implementation +/// Convert date and time to a string. #[no_mangle] -pub unsafe extern "C" fn ax_strftime( +pub unsafe extern "C" fn strftime( buf: *mut c_char, size: ctypes::size_t, format: *const c_char, timeptr: *const ctypes::tm, ) -> ctypes::size_t { - let ret = strftime(StringWriter(buf as *mut u8, size), format, timeptr); + let ret = strftime_inner(StringWriter(buf as *mut u8, size), format, timeptr); if ret < size { ret } else { diff --git a/ulib/axlibc/src/strtod.rs b/ulib/axlibc/src/strtod.rs index 4476496225..d930878929 100644 --- a/ulib/axlibc/src/strtod.rs +++ b/ulib/axlibc/src/strtod.rs @@ -118,14 +118,14 @@ fn isspace(c: c_int) -> bool { || c == 0x0c } -/// `strtod` implementation +/// Convert a string to a double-precision number. #[no_mangle] -pub unsafe extern "C" fn ax_strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { +pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { strto_float_impl!(c_double, s, endptr) } -/// `strtof`implementation +/// Convert a string to a float number. #[no_mangle] -pub unsafe extern "C" fn ax_strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float { +pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float { strto_float_impl!(c_float, s, endptr) } diff --git a/ulib/axlibc/src/sys.rs b/ulib/axlibc/src/sys.rs index d1d2ffa72b..253d76f1a6 100644 --- a/ulib/axlibc/src/sys.rs +++ b/ulib/axlibc/src/sys.rs @@ -1,29 +1,10 @@ -use super::ctypes; +use arceos_posix_api::sys_sysconf; use core::ffi::{c_int, c_long}; -const PAGE_SIZE_4K: usize = 4096; - /// Return system configuration infomation /// /// Notice: currently only support what unikraft covers #[no_mangle] -pub unsafe extern "C" fn ax_sysconf(name: c_int) -> c_long { - debug!("ax_sysconf <= {}", name); - ax_call_body!(ax_sysconf, { - match name as u32 { - // Page size - ctypes::_SC_PAGE_SIZE => Ok(PAGE_SIZE_4K as c_long), - // Total physical pages - ctypes::_SC_PHYS_PAGES => Ok((axconfig::PHYS_MEMORY_SIZE / PAGE_SIZE_4K) as c_long), - // Number of processors in use - ctypes::_SC_NPROCESSORS_ONLN => Ok(axconfig::SMP as c_long), - // Avaliable physical pages - #[cfg(feature = "alloc")] - ctypes::_SC_AVPHYS_PAGES => Ok(axalloc::global_allocator().available_pages() as c_long), - // Maximum number of files per process - #[cfg(feature = "fd")] - ctypes::_SC_OPEN_MAX => Ok(super::fd_ops::AX_FILE_LIMIT as c_long), - _ => Ok(0), - } - }) +pub unsafe extern "C" fn sysconf(name: c_int) -> c_long { + sys_sysconf(name) } diff --git a/ulib/axlibc/src/time.rs b/ulib/axlibc/src/time.rs index 845f277820..f478cd7f32 100644 --- a/ulib/axlibc/src/time.rs +++ b/ulib/axlibc/src/time.rs @@ -1,80 +1,21 @@ -use axerrno::LinuxError; -use axstd::time::Instant; -use core::ffi::{c_int, c_long}; -use core::time::Duration; +use arceos_posix_api::{sys_clock_gettime, sys_nanosleep}; +use core::ffi::c_int; -use super::ctypes; - -impl From for Duration { - fn from(ts: ctypes::timespec) -> Self { - Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32) - } -} - -impl From for Duration { - fn from(tv: ctypes::timeval) -> Self { - Duration::new(tv.tv_sec as u64, tv.tv_usec as u32 * 1000) - } -} - -impl From for ctypes::timespec { - fn from(d: Duration) -> Self { - ctypes::timespec { - tv_sec: d.as_secs() as c_long, - tv_nsec: d.subsec_nanos() as c_long, - } - } -} - -impl From for ctypes::timeval { - fn from(d: Duration) -> Self { - ctypes::timeval { - tv_sec: d.as_secs() as c_long, - tv_usec: d.subsec_micros() as c_long, - } - } -} +use crate::{ctypes, utils::e}; /// Get clock time since booting #[no_mangle] -pub unsafe extern "C" fn ax_clock_gettime(ts: *mut ctypes::timespec) -> c_int { - ax_call_body!(ax_clock_gettime, { - if ts.is_null() { - return Err(LinuxError::EFAULT); - } - let now = axhal::time::current_time().into(); - unsafe { *ts = now }; - debug!("ax_clock_gettime: {}.{:09}s", now.tv_sec, now.tv_nsec); - Ok(0) - }) +pub unsafe extern "C" fn clock_gettime(clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { + e(sys_clock_gettime(clk, ts)) } /// Sleep some nanoseconds /// /// TODO: should be woken by signals, and set errno #[no_mangle] -pub unsafe extern "C" fn ax_nanosleep( +pub unsafe extern "C" fn nanosleep( req: *const ctypes::timespec, rem: *mut ctypes::timespec, ) -> c_int { - ax_call_body!(ax_nanosleep, { - if req.is_null() || (*req).tv_nsec < 0 || (*req).tv_nsec > 999999999 { - return Err(LinuxError::EINVAL); - } - - debug!("ax_nanosleep <= {}.{:09}s", (*req).tv_sec, (*req).tv_nsec); - let dur = Duration::from(*req); - - let now = Instant::now(); - axstd::thread::sleep(dur); - let actual = now.elapsed(); - - if let Some(diff) = dur.checked_sub(actual) { - if !rem.is_null() { - unsafe { (*rem) = diff.into() }; - } - return Err(LinuxError::EINTR); - } - Ok(0) - }) + e(sys_nanosleep(req, rem)) } diff --git a/ulib/axlibc/src/uio.rs b/ulib/axlibc/src/uio.rs deleted file mode 100644 index 01bf9e0f0f..0000000000 --- a/ulib/axlibc/src/uio.rs +++ /dev/null @@ -1,27 +0,0 @@ -use core::ffi::c_int; - -use super::{ax_write, ctypes}; -use axerrno::LinuxError; - -/// `writev` implementation -#[no_mangle] -pub unsafe extern "C" fn ax_writev( - fd: c_int, - iov: *const ctypes::iovec, - iocnt: c_int, -) -> ctypes::ssize_t { - debug!("ax_writev <= fd: {}", fd); - ax_call_body!(ax_writev, { - if !(0..=1024).contains(&iocnt) { - return Err(LinuxError::EINVAL); - } - - let iovs = core::slice::from_raw_parts(iov, iocnt as usize); - let mut ret = 0; - for iov in iovs.iter() { - ret += ax_write(fd, iov.iov_base, iov.iov_len); - } - - Ok(ret) - }) -} diff --git a/ulib/axlibc/src/unistd.rs b/ulib/axlibc/src/unistd.rs new file mode 100644 index 0000000000..46c81bdd72 --- /dev/null +++ b/ulib/axlibc/src/unistd.rs @@ -0,0 +1,20 @@ +use arceos_posix_api::{sys_exit, sys_getpid}; +use core::ffi::c_int; + +/// Get current thread ID. +#[no_mangle] +pub unsafe extern "C" fn getpid() -> c_int { + sys_getpid() +} + +/// Abort the current process. +#[no_mangle] +pub unsafe extern "C" fn abort() -> ! { + panic!() +} + +/// Exits the current thread. +#[no_mangle] +pub unsafe extern "C" fn exit(exit_code: c_int) -> ! { + sys_exit(exit_code) +} diff --git a/ulib/axlibc/src/utils.rs b/ulib/axlibc/src/utils.rs index d35ce1063d..730f8c3de9 100644 --- a/ulib/axlibc/src/utils.rs +++ b/ulib/axlibc/src/utils.rs @@ -1,63 +1,10 @@ -#![allow(dead_code)] -#![allow(unused_macros)] +use core::ffi::c_int; -use axerrno::{LinuxError, LinuxResult}; -use core::ffi::{c_char, CStr}; - -pub fn char_ptr_to_str<'a>(str: *const c_char) -> LinuxResult<&'a str> { - if str.is_null() { - Err(LinuxError::EFAULT) +pub fn e(ret: c_int) -> c_int { + if ret < 0 { + crate::errno::set_errno(ret.abs()); + -1 } else { - unsafe { CStr::from_ptr(str) } - .to_str() - .map_err(|_| LinuxError::EINVAL) + ret as _ } } - -pub fn check_null_ptr(ptr: *const T) -> LinuxResult { - if ptr.is_null() { - Err(LinuxError::EFAULT) - } else { - Ok(()) - } -} - -pub fn check_null_mut_ptr(ptr: *mut T) -> LinuxResult { - if ptr.is_null() { - Err(LinuxError::EFAULT) - } else { - Ok(()) - } -} - -macro_rules! ax_call_body { - ($fn: ident, $($stmt: tt)*) => {{ - #[allow(clippy::redundant_closure_call)] - let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); - match res { - Ok(_) | Err(axerrno::LinuxError::EAGAIN) => debug!(concat!(stringify!($fn), " => {:?}"), res), - Err(_) => info!(concat!(stringify!($fn), " => {:?}"), res), - } - match res { - Ok(v) => v as _, - Err(e) => { - crate::errno::set_errno(e.code()); - -1 as _ - } - } - }}; -} - -macro_rules! ax_call_body_no_debug { - ($($stmt: tt)*) => {{ - #[allow(clippy::redundant_closure_call)] - let res = (|| -> axerrno::LinuxResult<_> { $($stmt)* })(); - match res { - Ok(v) => v as _, - Err(e) => { - crate::errno::set_errno(e.code()); - -1 as _ - } - } - }}; -}