diff --git a/crates/axfs_vfs/src/lib.rs b/crates/axfs_vfs/src/lib.rs index 6e0c4a232d..ee807a812e 100644 --- a/crates/axfs_vfs/src/lib.rs +++ b/crates/axfs_vfs/src/lib.rs @@ -155,6 +155,11 @@ pub trait VfsNodeOps: Send + Sync { ax_err!(Unsupported) } + /// Renames or moves existing file or directory. + fn rename(&self, _src_path: &str, _dst_path: &str) -> VfsResult { + ax_err!(Unsupported) + } + /// Convert `&self` to [`&dyn Any`][1] that can use /// [`Any::downcast_ref`][2]. /// diff --git a/modules/axfs/Cargo.toml b/modules/axfs/Cargo.toml index 9b3d9acab1..46df7ff337 100644 --- a/modules/axfs/Cargo.toml +++ b/modules/axfs/Cargo.toml @@ -12,11 +12,13 @@ documentation = "https://rcore-os.github.io/arceos/axfs/index.html" [features] devfs = ["dep:axfs_devfs"] ramfs = ["dep:axfs_ramfs"] +procfs = ["dep:axfs_ramfs"] +sysfs = ["dep:axfs_ramfs"] fatfs = ["dep:fatfs"] myfs = ["dep:crate_interface"] use-ramdisk = [] -default = ["devfs", "ramfs", "fatfs"] +default = ["devfs", "ramfs", "fatfs", "procfs", "sysfs"] [dependencies] log = "0.4" diff --git a/modules/axfs/src/api/mod.rs b/modules/axfs/src/api/mod.rs index 958ef77bc9..c8fb3aa30d 100644 --- a/modules/axfs/src/api/mod.rs +++ b/modules/axfs/src/api/mod.rs @@ -79,3 +79,11 @@ pub fn remove_dir(path: &str) -> io::Result<()> { pub fn remove_file(path: &str) -> io::Result<()> { crate::root::remove_file(None, path) } + +/// Rename a file or directory to a new name. +/// Delete the original file if `old` already exists. +/// +/// This only works then the new path is in the same mounted fs. +pub fn rename(old: &str, new: &str) -> io::Result<()> { + crate::root::rename(old, new) +} diff --git a/modules/axfs/src/fops.rs b/modules/axfs/src/fops.rs index a34c1f2edf..dea021e2a9 100644 --- a/modules/axfs/src/fops.rs +++ b/modules/axfs/src/fops.rs @@ -328,6 +328,14 @@ impl Directory { self.entry_idx += n; Ok(n) } + + /// Rename a file or directory to a new name. + /// Delete the original file if `old` already exists. + /// + /// This only works then the new path is in the same mounted fs. + pub fn rename(&self, old: &str, new: &str) -> AxResult { + crate::root::rename(old, new) + } } impl Drop for File { diff --git a/modules/axfs/src/fs/fatfs.rs b/modules/axfs/src/fs/fatfs.rs index 5df8f8a061..5d0c4c813f 100644 --- a/modules/axfs/src/fs/fatfs.rs +++ b/modules/axfs/src/fs/fatfs.rs @@ -184,6 +184,18 @@ impl VfsNodeOps for DirWrapper<'static> { } Ok(dirents.len()) } + + fn rename(&self, src_path: &str, dst_path: &str) -> VfsResult { + // `src_path` and `dst_path` should in the same mounted fs + debug!( + "rename at fatfs, src_path: {}, dst_path: {}", + src_path, dst_path + ); + + self.0 + .rename(src_path, &self.0, dst_path) + .map_err(as_vfs_err) + } } impl VfsOps for FatFileSystem { diff --git a/modules/axfs/src/lib.rs b/modules/axfs/src/lib.rs index c163d4a5aa..07baa2a7d8 100644 --- a/modules/axfs/src/lib.rs +++ b/modules/axfs/src/lib.rs @@ -28,6 +28,7 @@ extern crate alloc; mod dev; mod fs; +mod mounts; mod root; pub mod api; diff --git a/modules/axfs/src/mounts.rs b/modules/axfs/src/mounts.rs new file mode 100644 index 0000000000..d3a0e50936 --- /dev/null +++ b/modules/axfs/src/mounts.rs @@ -0,0 +1,80 @@ +use alloc::sync::Arc; +use axfs_vfs::{VfsNodeType, VfsOps, VfsResult}; + +use crate::fs; + +#[cfg(feature = "devfs")] +pub(crate) fn devfs() -> Arc { + let null = fs::devfs::NullDev; + let zero = fs::devfs::ZeroDev; + let bar = fs::devfs::ZeroDev; + let devfs = fs::devfs::DeviceFileSystem::new(); + let foo_dir = devfs.mkdir("foo"); + devfs.add("null", Arc::new(null)); + devfs.add("zero", Arc::new(zero)); + foo_dir.add("bar", Arc::new(bar)); + Arc::new(devfs) +} + +#[cfg(feature = "ramfs")] +pub(crate) fn ramfs() -> Arc { + Arc::new(fs::ramfs::RamFileSystem::new()) +} + +#[cfg(feature = "procfs")] +pub(crate) fn procfs() -> VfsResult> { + let procfs = fs::ramfs::RamFileSystem::new(); + let proc_root = procfs.root_dir(); + + // Create /proc/sys/net/core/somaxconn + proc_root.create("sys", VfsNodeType::Dir)?; + proc_root.create("sys/net", VfsNodeType::Dir)?; + proc_root.create("sys/net/core", VfsNodeType::Dir)?; + proc_root.create("sys/net/core/somaxconn", VfsNodeType::File)?; + let file_somaxconn = proc_root.clone().lookup("./sys/net/core/somaxconn")?; + file_somaxconn.write_at(0, b"4096\n")?; + + // Create /proc/sys/vm/overcommit_memory + proc_root.create("sys/vm", VfsNodeType::Dir)?; + proc_root.create("sys/vm/overcommit_memory", VfsNodeType::File)?; + let file_over = proc_root.clone().lookup("./sys/vm/overcommit_memory")?; + file_over.write_at(0, b"0\n")?; + + // Create /proc/self/stat + proc_root.create("self", VfsNodeType::Dir)?; + proc_root.create("self/stat", VfsNodeType::File)?; + + Ok(Arc::new(procfs)) +} + +#[cfg(feature = "sysfs")] +pub(crate) fn sysfs() -> VfsResult> { + let sysfs = fs::ramfs::RamFileSystem::new(); + let sys_root = sysfs.root_dir(); + + // Create /sys/kernel/mm/transparent_hugepage/enabled + sys_root.create("kernel", VfsNodeType::Dir)?; + sys_root.create("kernel/mm", VfsNodeType::Dir)?; + sys_root.create("kernel/mm/transparent_hugepage", VfsNodeType::Dir)?; + sys_root.create("kernel/mm/transparent_hugepage/enabled", VfsNodeType::File)?; + let file_hp = sys_root + .clone() + .lookup("./kernel/mm/transparent_hugepage/enabled")?; + file_hp.write_at(0, b"always [madvise] never\n")?; + + // Create /sys/devices/system/clocksource/clocksource0/current_clocksource + sys_root.create("devices", VfsNodeType::Dir)?; + sys_root.create("devices/system", VfsNodeType::Dir)?; + sys_root.create("devices/system/clocksource", VfsNodeType::Dir)?; + sys_root.create("devices/system/clocksource/clocksource0", VfsNodeType::Dir)?; + sys_root.create( + "devices/system/clocksource/clocksource0/current_clocksource", + VfsNodeType::File, + )?; + let file_cc = sys_root + .clone() + .lookup("devices/system/clocksource/clocksource0/current_clocksource")?; + file_cc.write_at(0, b"tsc\n")?; + + Ok(Arc::new(sysfs)) +} diff --git a/modules/axfs/src/root.rs b/modules/axfs/src/root.rs index e0c780a540..9bf02dce16 100644 --- a/modules/axfs/src/root.rs +++ b/modules/axfs/src/root.rs @@ -8,7 +8,7 @@ use axfs_vfs::{VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType, VfsOps, VfsResu use axsync::Mutex; use lazy_init::LazyInit; -use crate::{api::FileType, fs}; +use crate::{api::FileType, fs, mounts}; static CURRENT_DIR_PATH: Mutex = Mutex::new(String::new()); static CURRENT_DIR: LazyInit> = LazyInit::new(); @@ -131,6 +131,16 @@ impl VfsNodeOps for RootDirectory { } }) } + + fn rename(&self, src_path: &str, dst_path: &str) -> VfsResult { + self.lookup_mounted_fs(src_path, |fs, rest_path| { + if rest_path.is_empty() { + ax_err!(PermissionDenied) // cannot rename mount points + } else { + fs.root_dir().rename(rest_path, dst_path) + } + }) + } } pub(crate) fn init_rootfs(disk: crate::dev::Disk) { @@ -148,28 +158,26 @@ pub(crate) fn init_rootfs(disk: crate::dev::Disk) { let mut root_dir = RootDirectory::new(main_fs); #[cfg(feature = "devfs")] - { - let null = fs::devfs::NullDev; - let zero = fs::devfs::ZeroDev; - let bar = fs::devfs::ZeroDev; - let devfs = fs::devfs::DeviceFileSystem::new(); - let foo_dir = devfs.mkdir("foo"); - devfs.add("null", Arc::new(null)); - devfs.add("zero", Arc::new(zero)); - foo_dir.add("bar", Arc::new(bar)); - - root_dir - .mount("/dev", Arc::new(devfs)) - .expect("failed to mount devfs at /dev"); - } + root_dir + .mount("/dev", mounts::devfs()) + .expect("failed to mount devfs at /dev"); #[cfg(feature = "ramfs")] - { - let ramfs = fs::ramfs::RamFileSystem::new(); - root_dir - .mount("/tmp", Arc::new(ramfs)) - .expect("failed to mount ramfs at /tmp"); - } + root_dir + .mount("/tmp", mounts::ramfs()) + .expect("failed to mount ramfs at /tmp"); + + // Mount another ramfs as procfs + #[cfg(feature = "procfs")] + root_dir // should not fail + .mount("/proc", mounts::procfs().unwrap()) + .expect("fail to mount procfs at /proc"); + + // Mount another ramfs as sysfs + #[cfg(feature = "sysfs")] + root_dir // should not fail + .mount("/sys", mounts::sysfs().unwrap()) + .expect("fail to mount sysfs at /sys"); ROOT_DIR.init_by(Arc::new(root_dir)); CURRENT_DIR.init_by(Mutex::new(ROOT_DIR.clone())); @@ -292,3 +300,11 @@ pub(crate) fn set_current_dir(path: &str) -> AxResult { Ok(()) } } + +pub(crate) fn rename(old: &str, new: &str) -> AxResult { + if parent_node_of(None, new).lookup(new).is_ok() { + warn!("dst file already exist, now remove it"); + remove_file(None, new)?; + } + parent_node_of(None, old).rename(old, new) +} diff --git a/ulib/axlibc/build.rs b/ulib/axlibc/build.rs index afa8b748b7..286d525b77 100644 --- a/ulib/axlibc/build.rs +++ b/ulib/axlibc/build.rs @@ -68,6 +68,7 @@ typedef struct {{ "pthread_.*", "epoll_event", "iovec", + "tm", ]; let allow_vars = [ "O_.*", diff --git a/ulib/axlibc/c/env.c b/ulib/axlibc/c/env.c index 6bfdc60df1..131b2e16e9 100644 --- a/ulib/axlibc/c/env.c +++ b/ulib/axlibc/c/env.c @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -12,3 +14,17 @@ char *getenv(const char *name) return *e + l + 1; return 0; } + +// TODO +int setenv(const char *__name, const char *__value, int __replace) +{ + unimplemented(); + return 0; +} + +// TODO +int unsetenv(const char *__name) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/flock.c b/ulib/axlibc/c/flock.c new file mode 100644 index 0000000000..8ac9beec54 --- /dev/null +++ b/ulib/axlibc/c/flock.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int flock(int __fd, int __operation) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/glob.c b/ulib/axlibc/c/glob.c index 2baa1ea0fa..841a226dd1 100644 --- a/ulib/axlibc/c/glob.c +++ b/ulib/axlibc/c/glob.c @@ -1,20 +1,329 @@ #ifdef AX_CONFIG_FS +#include +#include +#include #include +#include +#include +#include #include +#include +#include +#include +#include + +struct match { + struct match *next; + char name[]; +}; + +static int append(struct match **tail, const char *name, size_t len, int mark) +{ + struct match *new = malloc(sizeof(struct match) + len + 2); + if (!new) + return -1; + (*tail)->next = new; + new->next = NULL; + memcpy(new->name, name, len + 1); + if (mark && len && name[len - 1] != '/') { + new->name[len] = '/'; + new->name[len + 1] = 0; + } + *tail = new; + return 0; +} + +static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, + int (*errfunc)(const char *path, int err), struct match **tail) +{ + /* If GLOB_MARK is unused, we don't care about type. */ + if (!type && !(flags & GLOB_MARK)) + type = DT_REG; + + /* Special-case the remaining pattern being all slashes, in + * which case we can use caller-passed type if it's a dir. */ + if (*pat && type != DT_DIR) + type = 0; + while (pos + 1 < PATH_MAX && *pat == '/') buf[pos++] = *pat++; + + /* Consume maximal [escaped-]literal prefix of pattern, copying + * and un-escaping it to the running buffer as we go. */ + long i = 0, j = 0; + int in_bracket = 0, overflow = 0; + for (; pat[i] != '*' && pat[i] != '?' && (!in_bracket || pat[i] != ']'); i++) { + if (!pat[i]) { + if (overflow) + return 0; + pat += i; + pos += j; + i = j = 0; + break; + } else if (pat[i] == '[') { + in_bracket = 1; + } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { + /* Backslashes inside a bracket are (at least by + * our interpretation) non-special, so if next + * char is ']' we have a complete expression. */ + if (in_bracket && pat[i + 1] == ']') + break; + /* Unpaired final backslash never matches. */ + if (!pat[i + 1]) + return 0; + i++; + } + if (pat[i] == '/') { + if (overflow) + return 0; + in_bracket = 0; + pat += i + 1; + i = -1; + pos += j + 1; + j = -1; + } + /* Only store a character if it fits in the buffer, but if + * a potential bracket expression is open, the overflow + * must be remembered and handled later only if the bracket + * is unterminated (and thereby a literal), so as not to + * disallow long bracket expressions with short matches. */ + if (pos + (j + 1) < PATH_MAX) { + buf[pos + j++] = pat[i]; + } else if (in_bracket) { + overflow = 1; + } else { + return 0; + } + /* If we consume any new components, the caller-passed type + * or dummy type from above is no longer valid. */ + type = 0; + } + buf[pos] = 0; + if (!*pat) { + /* If we consumed any components above, or if GLOB_MARK is + * requested and we don't yet know if the match is a dir, + * we must confirm the file exists and/or determine its type. + * + * If marking dirs, symlink type is inconclusive; we need the + * type for the symlink target, and therefore must try stat + * first unless type is known not to be a symlink. Otherwise, + * or if that fails, use lstat for determining existence to + * avoid false negatives in the case of broken symlinks. */ + struct stat st; + if ((flags & GLOB_MARK) && (!type || type == DT_LNK) && !stat(buf, &st)) { + if (S_ISDIR(st.st_mode)) + type = DT_DIR; + else + type = DT_REG; + } + if (!type && lstat(buf, &st)) { + if (errno != ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + return 0; + } + if (append(tail, buf, pos, (flags & GLOB_MARK) && type == DT_DIR)) + return GLOB_NOSPACE; + return 0; + } + char *p2 = strchr(pat, '/'), saved_sep = '/'; + /* Check if the '/' was escaped and, if so, remove the escape char + * so that it will not be unpaired when passed to fnmatch. */ + if (p2 && !(flags & GLOB_NOESCAPE)) { + char *p; + for (p = p2; p > pat && p[-1] == '\\'; p--) + ; + if ((p2 - p) % 2) { + p2--; + saved_sep = '\\'; + } + } + DIR *dir = opendir(pos ? buf : "."); + if (!dir) { + if (errfunc(buf, errno) || (flags & GLOB_ERR)) + return GLOB_ABORTED; + return 0; + } + int old_errno = errno; + struct dirent *de; + while (errno = 0, de = readdir(dir)) { + /* Quickly skip non-directories when there's pattern left. */ + if (p2 && de->d_type && de->d_type != DT_DIR && de->d_type != DT_LNK) + continue; + + size_t l = strlen(de->d_name); + if (l >= PATH_MAX - pos) + continue; + + if (p2) + *p2 = 0; + + int fnm_flags = ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | + ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); + + if (fnmatch(pat, de->d_name, fnm_flags)) + continue; + + /* With GLOB_PERIOD, don't allow matching . or .. unless + * fnmatch would match them with FNM_PERIOD rules in effect. */ + if (p2 && (flags & GLOB_PERIOD) && de->d_name[0] == '.' && + (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2])) && + fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) + continue; + + memcpy(buf + pos, de->d_name, l + 1); + if (p2) + *p2 = saved_sep; + int r = do_glob(buf, pos + l, de->d_type, p2 ? p2 : "", flags, errfunc, tail); + if (r) { + closedir(dir); + return r; + } + } + int readerr = errno; + if (p2) + *p2 = saved_sep; + closedir(dir); + if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + errno = old_errno; + return 0; +} + +static int ignore_err(const char *path, int err) +{ + return 0; +} + +static void freelist(struct match *head) +{ + struct match *match, *next; + for (match = head->next; match; match = next) { + next = match->next; + free(match); + } +} + +static int sort(const void *a, const void *b) +{ + return strcmp(*(const char **)a, *(const char **)b); +} + +static int expand_tilde(char **pat, char *buf, size_t *pos) +{ + char *p = *pat + 1; + size_t i = 0; + + char delim, *name_end = strchrnul(p, '/'); + if ((delim = *name_end)) + *name_end++ = 0; + *pat = name_end; + + char *home = *p ? NULL : getenv("HOME"); + if (!home) { + struct passwd pw, *res; + switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res) + : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) { + case ENOMEM: + return GLOB_NOSPACE; + case 0: + if (!res) + default: + return GLOB_NOMATCH; + } + home = pw.pw_dir; + } + while (i < PATH_MAX - 2 && *home) buf[i++] = *home++; + if (*home) + return GLOB_NOMATCH; + if ((buf[i] = delim)) + buf[++i] = 0; + *pos = i; + return 0; +} -// TODO int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g) { - unimplemented(); - return 0; + struct match head = {.next = NULL}, *tail = &head; + size_t cnt, i; + size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; + int error = 0; + char buf[PATH_MAX]; + + if (!errfunc) + errfunc = ignore_err; + + if (!(flags & GLOB_APPEND)) { + g->gl_offs = offs; + g->gl_pathc = 0; + g->gl_pathv = NULL; + } + + if (*pat) { + char *p = strdup(pat); + if (!p) + return GLOB_NOSPACE; + buf[0] = 0; + size_t pos = 0; + char *s = p; + if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~') + error = expand_tilde(&s, buf, &pos); + if (!error) + error = do_glob(buf, pos, 0, s, flags, errfunc, &tail); + free(p); + } + + if (error == GLOB_NOSPACE) { + freelist(&head); + return error; + } + + for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++) + ; + if (!cnt) { + if (flags & GLOB_NOCHECK) { + tail = &head; + if (append(&tail, pat, strlen(pat), 0)) + return GLOB_NOSPACE; + cnt++; + } else + return GLOB_NOMATCH; + } + + if (flags & GLOB_APPEND) { + char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); + if (!pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + g->gl_pathv = pathv; + offs += g->gl_pathc; + } else { + g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); + if (!g->gl_pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + for (i = 0; i < offs; i++) g->gl_pathv[i] = NULL; + } + for (i = 0, tail = head.next; i < cnt; tail = tail->next, i++) + g->gl_pathv[offs + i] = tail->name; + g->gl_pathv[offs + i] = NULL; + g->gl_pathc += cnt; + + if (!(flags & GLOB_NOSORT)) + qsort(g->gl_pathv + offs, cnt, sizeof(char *), sort); + + return error; } void globfree(glob_t *g) { - unimplemented(); - return; + size_t i; + for (i = 0; i < g->gl_pathc; i++) + free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); + free(g->gl_pathv); + g->gl_pathc = 0; + g->gl_pathv = NULL; } #endif // AX_CONFIG_FS diff --git a/ulib/axlibc/c/ioctl.c b/ulib/axlibc/c/ioctl.c new file mode 100644 index 0000000000..df2aad1678 --- /dev/null +++ b/ulib/axlibc/c/ioctl.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int ioctl(int __fd, int __request, ...) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/locale.c b/ulib/axlibc/c/locale.c new file mode 100644 index 0000000000..9c535ac3db --- /dev/null +++ b/ulib/axlibc/c/locale.c @@ -0,0 +1,42 @@ +#include +#include +#include + +// TODO +char *setlocale(int __category, const char *__locale) +{ + unimplemented(); + return NULL; +} + +static const struct lconv posix_lconv = { + .decimal_point = ".", + .thousands_sep = "", + .grouping = "", + .int_curr_symbol = "", + .currency_symbol = "", + .mon_decimal_point = "", + .mon_thousands_sep = "", + .mon_grouping = "", + .positive_sign = "", + .negative_sign = "", + .int_frac_digits = CHAR_MAX, + .frac_digits = CHAR_MAX, + .p_cs_precedes = CHAR_MAX, + .p_sep_by_space = CHAR_MAX, + .n_cs_precedes = CHAR_MAX, + .n_sep_by_space = CHAR_MAX, + .p_sign_posn = CHAR_MAX, + .n_sign_posn = CHAR_MAX, + .int_p_cs_precedes = CHAR_MAX, + .int_p_sep_by_space = CHAR_MAX, + .int_n_cs_precedes = CHAR_MAX, + .int_n_sep_by_space = CHAR_MAX, + .int_p_sign_posn = CHAR_MAX, + .int_n_sign_posn = CHAR_MAX, +}; + +struct lconv *localeconv(void) +{ + return (void *)&posix_lconv; +} diff --git a/ulib/axlibc/c/log.c b/ulib/axlibc/c/log.c new file mode 100644 index 0000000000..4e34aa0ac7 --- /dev/null +++ b/ulib/axlibc/c/log.c @@ -0,0 +1,395 @@ +#ifdef AX_CONFIG_FP_SIMD + +#include +#include +#include +#include + +#include "libm.h" + +struct log_data { + double ln2hi; + double ln2lo; + double poly[LOG_POLY_ORDER - 1]; + double poly1[LOG_POLY1_ORDER - 1]; + struct { + double invc, logc; + } tab[1 << LOG_TABLE_BITS]; +#if !__FP_FAST_FMA + struct { + double chi, clo; + } tab2[1 << LOG_TABLE_BITS]; +#endif +}; + +const struct log_data __log_data = { + .ln2hi = 0x1.62e42fefa3800p-1, + .ln2lo = 0x1.ef35793c76730p-45, + .poly1 = + { + -0x1p-1, + 0x1.5555555555577p-2, + -0x1.ffffffffffdcbp-3, + 0x1.999999995dd0cp-3, + -0x1.55555556745a7p-3, + 0x1.24924a344de3p-3, + -0x1.fffffa4423d65p-4, + 0x1.c7184282ad6cap-4, + -0x1.999eb43b068ffp-4, + 0x1.78182f7afd085p-4, + -0x1.5521375d145cdp-4, + }, + .poly = + { + -0x1.0000000000001p-1, + 0x1.555555551305bp-2, + -0x1.fffffffeb459p-3, + 0x1.999b324f10111p-3, + -0x1.55575e506c89fp-3, + }, + .tab = + { + {0x1.734f0c3e0de9fp+0, -0x1.7cc7f79e69000p-2}, + {0x1.713786a2ce91fp+0, -0x1.76feec20d0000p-2}, + {0x1.6f26008fab5a0p+0, -0x1.713e31351e000p-2}, + {0x1.6d1a61f138c7dp+0, -0x1.6b85b38287800p-2}, + {0x1.6b1490bc5b4d1p+0, -0x1.65d5590807800p-2}, + {0x1.69147332f0cbap+0, -0x1.602d076180000p-2}, + {0x1.6719f18224223p+0, -0x1.5a8ca86909000p-2}, + {0x1.6524f99a51ed9p+0, -0x1.54f4356035000p-2}, + {0x1.63356aa8f24c4p+0, -0x1.4f637c36b4000p-2}, + {0x1.614b36b9ddc14p+0, -0x1.49da7fda85000p-2}, + {0x1.5f66452c65c4cp+0, -0x1.445923989a800p-2}, + {0x1.5d867b5912c4fp+0, -0x1.3edf439b0b800p-2}, + {0x1.5babccb5b90dep+0, -0x1.396ce448f7000p-2}, + {0x1.59d61f2d91a78p+0, -0x1.3401e17bda000p-2}, + {0x1.5805612465687p+0, -0x1.2e9e2ef468000p-2}, + {0x1.56397cee76bd3p+0, -0x1.2941b3830e000p-2}, + {0x1.54725e2a77f93p+0, -0x1.23ec58cda8800p-2}, + {0x1.52aff42064583p+0, -0x1.1e9e129279000p-2}, + {0x1.50f22dbb2bddfp+0, -0x1.1956d2b48f800p-2}, + {0x1.4f38f4734ded7p+0, -0x1.141679ab9f800p-2}, + {0x1.4d843cfde2840p+0, -0x1.0edd094ef9800p-2}, + {0x1.4bd3ec078a3c8p+0, -0x1.09aa518db1000p-2}, + {0x1.4a27fc3e0258ap+0, -0x1.047e65263b800p-2}, + {0x1.4880524d48434p+0, -0x1.feb224586f000p-3}, + {0x1.46dce1b192d0bp+0, -0x1.f474a7517b000p-3}, + {0x1.453d9d3391854p+0, -0x1.ea4443d103000p-3}, + {0x1.43a2744b4845ap+0, -0x1.e020d44e9b000p-3}, + {0x1.420b54115f8fbp+0, -0x1.d60a22977f000p-3}, + {0x1.40782da3ef4b1p+0, -0x1.cc00104959000p-3}, + {0x1.3ee8f5d57fe8fp+0, -0x1.c202956891000p-3}, + {0x1.3d5d9a00b4ce9p+0, -0x1.b81178d811000p-3}, + {0x1.3bd60c010c12bp+0, -0x1.ae2c9ccd3d000p-3}, + {0x1.3a5242b75dab8p+0, -0x1.a45402e129000p-3}, + {0x1.38d22cd9fd002p+0, -0x1.9a877681df000p-3}, + {0x1.3755bc5847a1cp+0, -0x1.90c6d69483000p-3}, + {0x1.35dce49ad36e2p+0, -0x1.87120a645c000p-3}, + {0x1.34679984dd440p+0, -0x1.7d68fb4143000p-3}, + {0x1.32f5cceffcb24p+0, -0x1.73cb83c627000p-3}, + {0x1.3187775a10d49p+0, -0x1.6a39a9b376000p-3}, + {0x1.301c8373e3990p+0, -0x1.60b3154b7a000p-3}, + {0x1.2eb4ebb95f841p+0, -0x1.5737d76243000p-3}, + {0x1.2d50a0219a9d1p+0, -0x1.4dc7b8fc23000p-3}, + {0x1.2bef9a8b7fd2ap+0, -0x1.4462c51d20000p-3}, + {0x1.2a91c7a0c1babp+0, -0x1.3b08abc830000p-3}, + {0x1.293726014b530p+0, -0x1.31b996b490000p-3}, + {0x1.27dfa5757a1f5p+0, -0x1.2875490a44000p-3}, + {0x1.268b39b1d3bbfp+0, -0x1.1f3b9f879a000p-3}, + {0x1.2539d838ff5bdp+0, -0x1.160c8252ca000p-3}, + {0x1.23eb7aac9083bp+0, -0x1.0ce7f57f72000p-3}, + {0x1.22a012ba940b6p+0, -0x1.03cdc49fea000p-3}, + {0x1.2157996cc4132p+0, -0x1.f57bdbc4b8000p-4}, + {0x1.201201dd2fc9bp+0, -0x1.e370896404000p-4}, + {0x1.1ecf4494d480bp+0, -0x1.d17983ef94000p-4}, + {0x1.1d8f5528f6569p+0, -0x1.bf9674ed8a000p-4}, + {0x1.1c52311577e7cp+0, -0x1.adc79202f6000p-4}, + {0x1.1b17c74cb26e9p+0, -0x1.9c0c3e7288000p-4}, + {0x1.19e010c2c1ab6p+0, -0x1.8a646b372c000p-4}, + {0x1.18ab07bb670bdp+0, -0x1.78d01b3ac0000p-4}, + {0x1.1778a25efbcb6p+0, -0x1.674f145380000p-4}, + {0x1.1648d354c31dap+0, -0x1.55e0e6d878000p-4}, + {0x1.151b990275fddp+0, -0x1.4485cdea1e000p-4}, + {0x1.13f0ea432d24cp+0, -0x1.333d94d6aa000p-4}, + {0x1.12c8b7210f9dap+0, -0x1.22079f8c56000p-4}, + {0x1.11a3028ecb531p+0, -0x1.10e4698622000p-4}, + {0x1.107fbda8434afp+0, -0x1.ffa6c6ad20000p-5}, + {0x1.0f5ee0f4e6bb3p+0, -0x1.dda8d4a774000p-5}, + {0x1.0e4065d2a9fcep+0, -0x1.bbcece4850000p-5}, + {0x1.0d244632ca521p+0, -0x1.9a1894012c000p-5}, + {0x1.0c0a77ce2981ap+0, -0x1.788583302c000p-5}, + {0x1.0af2f83c636d1p+0, -0x1.5715e67d68000p-5}, + {0x1.09ddb98a01339p+0, -0x1.35c8a49658000p-5}, + {0x1.08cabaf52e7dfp+0, -0x1.149e364154000p-5}, + {0x1.07b9f2f4e28fbp+0, -0x1.e72c082eb8000p-6}, + {0x1.06ab58c358f19p+0, -0x1.a55f152528000p-6}, + {0x1.059eea5ecf92cp+0, -0x1.63d62cf818000p-6}, + {0x1.04949cdd12c90p+0, -0x1.228fb8caa0000p-6}, + {0x1.038c6c6f0ada9p+0, -0x1.c317b20f90000p-7}, + {0x1.02865137932a9p+0, -0x1.419355daa0000p-7}, + {0x1.0182427ea7348p+0, -0x1.81203c2ec0000p-8}, + {0x1.008040614b195p+0, -0x1.0040979240000p-9}, + {0x1.fe01ff726fa1ap-1, 0x1.feff384900000p-9}, + {0x1.fa11cc261ea74p-1, 0x1.7dc41353d0000p-7}, + {0x1.f6310b081992ep-1, 0x1.3cea3c4c28000p-6}, + {0x1.f25f63ceeadcdp-1, 0x1.b9fc114890000p-6}, + {0x1.ee9c8039113e7p-1, 0x1.1b0d8ce110000p-5}, + {0x1.eae8078cbb1abp-1, 0x1.58a5bd001c000p-5}, + {0x1.e741aa29d0c9bp-1, 0x1.95c8340d88000p-5}, + {0x1.e3a91830a99b5p-1, 0x1.d276aef578000p-5}, + {0x1.e01e009609a56p-1, 0x1.07598e598c000p-4}, + {0x1.dca01e577bb98p-1, 0x1.253f5e30d2000p-4}, + {0x1.d92f20b7c9103p-1, 0x1.42edd8b380000p-4}, + {0x1.d5cac66fb5ccep-1, 0x1.606598757c000p-4}, + {0x1.d272caa5ede9dp-1, 0x1.7da76356a0000p-4}, + {0x1.cf26e3e6b2ccdp-1, 0x1.9ab434e1c6000p-4}, + {0x1.cbe6da2a77902p-1, 0x1.b78c7bb0d6000p-4}, + {0x1.c8b266d37086dp-1, 0x1.d431332e72000p-4}, + {0x1.c5894bd5d5804p-1, 0x1.f0a3171de6000p-4}, + {0x1.c26b533bb9f8cp-1, 0x1.067152b914000p-3}, + {0x1.bf583eeece73fp-1, 0x1.147858292b000p-3}, + {0x1.bc4fd75db96c1p-1, 0x1.2266ecdca3000p-3}, + {0x1.b951e0c864a28p-1, 0x1.303d7a6c55000p-3}, + {0x1.b65e2c5ef3e2cp-1, 0x1.3dfc33c331000p-3}, + {0x1.b374867c9888bp-1, 0x1.4ba366b7a8000p-3}, + {0x1.b094b211d304ap-1, 0x1.5933928d1f000p-3}, + {0x1.adbe885f2ef7ep-1, 0x1.66acd2418f000p-3}, + {0x1.aaf1d31603da2p-1, 0x1.740f8ec669000p-3}, + {0x1.a82e63fd358a7p-1, 0x1.815c0f51af000p-3}, + {0x1.a5740ef09738bp-1, 0x1.8e92954f68000p-3}, + {0x1.a2c2a90ab4b27p-1, 0x1.9bb3602f84000p-3}, + {0x1.a01a01393f2d1p-1, 0x1.a8bed1c2c0000p-3}, + {0x1.9d79f24db3c1bp-1, 0x1.b5b515c01d000p-3}, + {0x1.9ae2505c7b190p-1, 0x1.c2967ccbcc000p-3}, + {0x1.9852ef297ce2fp-1, 0x1.cf635d5486000p-3}, + {0x1.95cbaeea44b75p-1, 0x1.dc1bd3446c000p-3}, + {0x1.934c69de74838p-1, 0x1.e8c01b8cfe000p-3}, + {0x1.90d4f2f6752e6p-1, 0x1.f5509c0179000p-3}, + {0x1.8e6528effd79dp-1, 0x1.00e6c121fb800p-2}, + {0x1.8bfce9fcc007cp-1, 0x1.071b80e93d000p-2}, + {0x1.899c0dabec30ep-1, 0x1.0d46b9e867000p-2}, + {0x1.87427aa2317fbp-1, 0x1.13687334bd000p-2}, + {0x1.84f00acb39a08p-1, 0x1.1980d67234800p-2}, + {0x1.82a49e8653e55p-1, 0x1.1f8ffe0cc8000p-2}, + {0x1.8060195f40260p-1, 0x1.2595fd7636800p-2}, + {0x1.7e22563e0a329p-1, 0x1.2b9300914a800p-2}, + {0x1.7beb377dcb5adp-1, 0x1.3187210436000p-2}, + {0x1.79baa679725c2p-1, 0x1.377266dec1800p-2}, + {0x1.77907f2170657p-1, 0x1.3d54ffbaf3000p-2}, + {0x1.756cadbd6130cp-1, 0x1.432eee32fe000p-2}, + }, +#if !__FP_FAST_FMA + .tab2 = + { + {0x1.61000014fb66bp-1, 0x1.e026c91425b3cp-56}, + {0x1.63000034db495p-1, 0x1.dbfea48005d41p-55}, + {0x1.650000d94d478p-1, 0x1.e7fa786d6a5b7p-55}, + {0x1.67000074e6fadp-1, 0x1.1fcea6b54254cp-57}, + {0x1.68ffffedf0faep-1, -0x1.c7e274c590efdp-56}, + {0x1.6b0000763c5bcp-1, -0x1.ac16848dcda01p-55}, + {0x1.6d0001e5cc1f6p-1, 0x1.33f1c9d499311p-55}, + {0x1.6efffeb05f63ep-1, -0x1.e80041ae22d53p-56}, + {0x1.710000e86978p-1, 0x1.bff6671097952p-56}, + {0x1.72ffffc67e912p-1, 0x1.c00e226bd8724p-55}, + {0x1.74fffdf81116ap-1, -0x1.e02916ef101d2p-57}, + {0x1.770000f679c9p-1, -0x1.7fc71cd549c74p-57}, + {0x1.78ffffa7ec835p-1, 0x1.1bec19ef50483p-55}, + {0x1.7affffe20c2e6p-1, -0x1.07e1729cc6465p-56}, + {0x1.7cfffed3fc9p-1, -0x1.08072087b8b1cp-55}, + {0x1.7efffe9261a76p-1, 0x1.dc0286d9df9aep-55}, + {0x1.81000049ca3e8p-1, 0x1.97fd251e54c33p-55}, + {0x1.8300017932c8fp-1, -0x1.afee9b630f381p-55}, + {0x1.850000633739cp-1, 0x1.9bfbf6b6535bcp-55}, + {0x1.87000204289c6p-1, -0x1.bbf65f3117b75p-55}, + {0x1.88fffebf57904p-1, -0x1.9006ea23dcb57p-55}, + {0x1.8b00022bc04dfp-1, -0x1.d00df38e04b0ap-56}, + {0x1.8cfffe50c1b8ap-1, -0x1.8007146ff9f05p-55}, + {0x1.8effffc918e43p-1, 0x1.3817bd07a7038p-55}, + {0x1.910001efa5fc7p-1, 0x1.93e9176dfb403p-55}, + {0x1.9300013467bb9p-1, 0x1.f804e4b980276p-56}, + {0x1.94fffe6ee076fp-1, -0x1.f7ef0d9ff622ep-55}, + {0x1.96fffde3c12d1p-1, -0x1.082aa962638bap-56}, + {0x1.98ffff4458a0dp-1, -0x1.7801b9164a8efp-55}, + {0x1.9afffdd982e3ep-1, -0x1.740e08a5a9337p-55}, + {0x1.9cfffed49fb66p-1, 0x1.fce08c19bep-60}, + {0x1.9f00020f19c51p-1, -0x1.a3faa27885b0ap-55}, + {0x1.a10001145b006p-1, 0x1.4ff489958da56p-56}, + {0x1.a300007bbf6fap-1, 0x1.cbeab8a2b6d18p-55}, + {0x1.a500010971d79p-1, 0x1.8fecadd78793p-55}, + {0x1.a70001df52e48p-1, -0x1.f41763dd8abdbp-55}, + {0x1.a90001c593352p-1, -0x1.ebf0284c27612p-55}, + {0x1.ab0002a4f3e4bp-1, -0x1.9fd043cff3f5fp-57}, + {0x1.acfffd7ae1ed1p-1, -0x1.23ee7129070b4p-55}, + {0x1.aefffee510478p-1, 0x1.a063ee00edea3p-57}, + {0x1.b0fffdb650d5bp-1, 0x1.a06c8381f0ab9p-58}, + {0x1.b2ffffeaaca57p-1, -0x1.9011e74233c1dp-56}, + {0x1.b4fffd995badcp-1, -0x1.9ff1068862a9fp-56}, + {0x1.b7000249e659cp-1, 0x1.aff45d0864f3ep-55}, + {0x1.b8ffff987164p-1, 0x1.cfe7796c2c3f9p-56}, + {0x1.bafffd204cb4fp-1, -0x1.3ff27eef22bc4p-57}, + {0x1.bcfffd2415c45p-1, -0x1.cffb7ee3bea21p-57}, + {0x1.beffff86309dfp-1, -0x1.14103972e0b5cp-55}, + {0x1.c0fffe1b57653p-1, 0x1.bc16494b76a19p-55}, + {0x1.c2ffff1fa57e3p-1, -0x1.4feef8d30c6edp-57}, + {0x1.c4fffdcbfe424p-1, -0x1.43f68bcec4775p-55}, + {0x1.c6fffed54b9f7p-1, 0x1.47ea3f053e0ecp-55}, + {0x1.c8fffeb998fd5p-1, 0x1.383068df992f1p-56}, + {0x1.cb0002125219ap-1, -0x1.8fd8e64180e04p-57}, + {0x1.ccfffdd94469cp-1, 0x1.e7ebe1cc7ea72p-55}, + {0x1.cefffeafdc476p-1, 0x1.ebe39ad9f88fep-55}, + {0x1.d1000169af82bp-1, 0x1.57d91a8b95a71p-56}, + {0x1.d30000d0ff71dp-1, 0x1.9c1906970c7dap-55}, + {0x1.d4fffea790fc4p-1, -0x1.80e37c558fe0cp-58}, + {0x1.d70002edc87e5p-1, -0x1.f80d64dc10f44p-56}, + {0x1.d900021dc82aap-1, -0x1.47c8f94fd5c5cp-56}, + {0x1.dafffd86b0283p-1, 0x1.c7f1dc521617ep-55}, + {0x1.dd000296c4739p-1, 0x1.8019eb2ffb153p-55}, + {0x1.defffe54490f5p-1, 0x1.e00d2c652cc89p-57}, + {0x1.e0fffcdabf694p-1, -0x1.f8340202d69d2p-56}, + {0x1.e2fffdb52c8ddp-1, 0x1.b00c1ca1b0864p-56}, + {0x1.e4ffff24216efp-1, 0x1.2ffa8b094ab51p-56}, + {0x1.e6fffe88a5e11p-1, -0x1.7f673b1efbe59p-58}, + {0x1.e9000119eff0dp-1, -0x1.4808d5e0bc801p-55}, + {0x1.eafffdfa51744p-1, 0x1.80006d54320b5p-56}, + {0x1.ed0001a127fa1p-1, -0x1.002f860565c92p-58}, + {0x1.ef00007babcc4p-1, -0x1.540445d35e611p-55}, + {0x1.f0ffff57a8d02p-1, -0x1.ffb3139ef9105p-59}, + {0x1.f30001ee58ac7p-1, 0x1.a81acf2731155p-55}, + {0x1.f4ffff5823494p-1, 0x1.a3f41d4d7c743p-55}, + {0x1.f6ffffca94c6bp-1, -0x1.202f41c987875p-57}, + {0x1.f8fffe1f9c441p-1, 0x1.77dd1f477e74bp-56}, + {0x1.fafffd2e0e37ep-1, -0x1.f01199a7ca331p-57}, + {0x1.fd0001c77e49ep-1, 0x1.181ee4bceacb1p-56}, + {0x1.feffff7e0c331p-1, -0x1.e05370170875ap-57}, + {0x1.00ffff465606ep+0, -0x1.a7ead491c0adap-55}, + {0x1.02ffff3867a58p+0, -0x1.77f69c3fcb2ep-54}, + {0x1.04ffffdfc0d17p+0, 0x1.7bffe34cb945bp-54}, + {0x1.0700003cd4d82p+0, 0x1.20083c0e456cbp-55}, + {0x1.08ffff9f2cbe8p+0, -0x1.dffdfbe37751ap-57}, + {0x1.0b000010cda65p+0, -0x1.13f7faee626ebp-54}, + {0x1.0d00001a4d338p+0, 0x1.07dfa79489ff7p-55}, + {0x1.0effffadafdfdp+0, -0x1.7040570d66bcp-56}, + {0x1.110000bbafd96p+0, 0x1.e80d4846d0b62p-55}, + {0x1.12ffffae5f45dp+0, 0x1.dbffa64fd36efp-54}, + {0x1.150000dd59ad9p+0, 0x1.a0077701250aep-54}, + {0x1.170000f21559ap+0, 0x1.dfdf9e2e3deeep-55}, + {0x1.18ffffc275426p+0, 0x1.10030dc3b7273p-54}, + {0x1.1b000123d3c59p+0, 0x1.97f7980030188p-54}, + {0x1.1cffff8299eb7p+0, -0x1.5f932ab9f8c67p-57}, + {0x1.1effff48ad4p+0, 0x1.37fbf9da75bebp-54}, + {0x1.210000c8b86a4p+0, 0x1.f806b91fd5b22p-54}, + {0x1.2300003854303p+0, 0x1.3ffc2eb9fbf33p-54}, + {0x1.24fffffbcf684p+0, 0x1.601e77e2e2e72p-56}, + {0x1.26ffff52921d9p+0, 0x1.ffcbb767f0c61p-56}, + {0x1.2900014933a3cp+0, -0x1.202ca3c02412bp-56}, + {0x1.2b00014556313p+0, -0x1.2808233f21f02p-54}, + {0x1.2cfffebfe523bp+0, -0x1.8ff7e384fdcf2p-55}, + {0x1.2f0000bb8ad96p+0, -0x1.5ff51503041c5p-55}, + {0x1.30ffffb7ae2afp+0, -0x1.10071885e289dp-55}, + {0x1.32ffffeac5f7fp+0, -0x1.1ff5d3fb7b715p-54}, + {0x1.350000ca66756p+0, 0x1.57f82228b82bdp-54}, + {0x1.3700011fbf721p+0, 0x1.000bac40dd5ccp-55}, + {0x1.38ffff9592fb9p+0, -0x1.43f9d2db2a751p-54}, + {0x1.3b00004ddd242p+0, 0x1.57f6b707638e1p-55}, + {0x1.3cffff5b2c957p+0, 0x1.a023a10bf1231p-56}, + {0x1.3efffeab0b418p+0, 0x1.87f6d66b152bp-54}, + {0x1.410001532aff4p+0, 0x1.7f8375f198524p-57}, + {0x1.4300017478b29p+0, 0x1.301e672dc5143p-55}, + {0x1.44fffe795b463p+0, 0x1.9ff69b8b2895ap-55}, + {0x1.46fffe80475ep+0, -0x1.5c0b19bc2f254p-54}, + {0x1.48fffef6fc1e7p+0, 0x1.b4009f23a2a72p-54}, + {0x1.4afffe5bea704p+0, -0x1.4ffb7bf0d7d45p-54}, + {0x1.4d000171027dep+0, -0x1.9c06471dc6a3dp-54}, + {0x1.4f0000ff03ee2p+0, 0x1.77f890b85531cp-54}, + {0x1.5100012dc4bd1p+0, 0x1.004657166a436p-57}, + {0x1.530001605277ap+0, -0x1.6bfcece233209p-54}, + {0x1.54fffecdb704cp+0, -0x1.902720505a1d7p-55}, + {0x1.56fffef5f54a9p+0, 0x1.bbfe60ec96412p-54}, + {0x1.5900017e61012p+0, 0x1.87ec581afef9p-55}, + {0x1.5b00003c93e92p+0, -0x1.f41080abf0ccp-54}, + {0x1.5d0001d4919bcp+0, -0x1.8812afb254729p-54}, + {0x1.5efffe7b87a89p+0, -0x1.47eb780ed6904p-54}, + }, +#endif +}; + +#define T __log_data.tab +#define T2 __log_data.tab2 +#define B __log_data.poly1 +#define A __log_data.poly +#define Ln2hi __log_data.ln2hi +#define Ln2lo __log_data.ln2lo +#define N (1 << LOG_TABLE_BITS) +#define OFF 0x3fe6000000000000 + +static inline uint32_t top16(double x) +{ + return asuint64(x) >> 48; +} + +double log(double x) +{ + double_t w, z, r, r2, r3, y, invc, logc, kd, hi, lo; + uint64_t ix, iz, tmp; + uint32_t top; + int k, i; + + ix = asuint64(x); + top = top16(x); +#define LO asuint64(1.0 - 0x1p-4) +#define HI asuint64(1.0 + 0x1.09p-4) + if (predict_false(ix - LO < HI - LO)) { + if (WANT_ROUNDING && predict_false(ix == asuint64(1.0))) + return 0; + r = x - 1.0; + r2 = r * r; + r3 = r * r2; + y = r3 * + (B[1] + r * B[2] + r2 * B[3] + + r3 * (B[4] + r * B[5] + r2 * B[6] + r3 * (B[7] + r * B[8] + r2 * B[9] + r3 * B[10]))); + w = r * 0x1p27; + double_t rhi = r + w - w; + double_t rlo = r - rhi; + w = rhi * rhi * B[0]; + hi = r + w; + lo = r - hi + w; + lo += B[0] * rlo * (rhi + r); + y += lo; + y += hi; + return eval_as_double(y); + } + if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) { + if (ix * 2 == 0) + return __math_divzero(1); + if (ix == asuint64(INFINITY)) + return x; + if ((top & 0x8000) || (top & 0x7ff0) == 0x7ff0) + return __math_invalid(x); + ix = asuint64(x * 0x1p52); + ix -= 52ULL << 52; + } + + tmp = ix - OFF; + i = (tmp >> (52 - LOG_TABLE_BITS)) % N; + k = (int64_t)tmp >> 52; + iz = ix - (tmp & 0xfffULL << 52); + invc = T[i].invc; + logc = T[i].logc; + z = asdouble(iz); + +#if __FP_FAST_FMA + r = __builtin_fma(z, invc, -1.0); +#else + r = (z - T2[i].chi - T2[i].clo) * invc; +#endif + + kd = (double_t)k; + w = kd * Ln2hi + logc; + hi = w + r; + lo = w - hi + r + kd * Ln2lo; + r2 = r * r; + y = lo + r2 * A[0] + r * r2 * (A[1] + r * A[2] + r2 * (A[3] + r * A[4])) + hi; + return eval_as_double(y); +} + +#endif // AX_CONFIG_FP_SIMD diff --git a/ulib/axlibc/c/math.c b/ulib/axlibc/c/math.c index d2c574d9da..04ee1e7c32 100644 --- a/ulib/axlibc/c/math.c +++ b/ulib/axlibc/c/math.c @@ -568,16 +568,4 @@ long double fabsl(long double x) } #endif -double log(double x) -{ - unimplemented(); - return 0; -} - -double pow(double x, double y) -{ - unimplemented(); - return 0; -} - #endif // AX_CONFIG_FP_SIMD diff --git a/ulib/axlibc/c/mmap.c b/ulib/axlibc/c/mmap.c index 8ba0894080..5382180af6 100644 --- a/ulib/axlibc/c/mmap.c +++ b/ulib/axlibc/c/mmap.c @@ -22,3 +22,17 @@ void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, unimplemented(); return NULL; } + +// TODO +int mprotect(void *addr, size_t len, int prot) +{ + unimplemented(); + return 0; +} + +// TODO +int madvise(void *addr, size_t len, int advice) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/network.c b/ulib/axlibc/c/network.c index 2e2c31f599..de5065665e 100644 --- a/ulib/axlibc/c/network.c +++ b/ulib/axlibc/c/network.c @@ -1,8 +1,8 @@ #ifdef AX_CONFIG_NET +#include #include #include -#include #include #include #include @@ -31,6 +31,9 @@ int getaddrinfo(const char *__restrict node, const char *__restrict service, (_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; @@ -44,6 +47,31 @@ void freeaddrinfo(struct addrinfo *__restrict res) return; } +static const char gai_msgs[] = "Invalid flags\0" + "Name does not resolve\0" + "Try again\0" + "Non-recoverable error\0" + "Unknown error\0" + "Unrecognized address family or invalid length\0" + "Unrecognized socket type\0" + "Unrecognized service\0" + "Unknown error\0" + "Out of memory\0" + "System error\0" + "Overflow\0" + "\0Unknown error"; + +const char *gai_strerror(int ecode) +{ + const char *s; + for (s = gai_msgs, ecode++; ecode && *s; ecode++, s++) + for (; *s; s++) + ; + if (!*s) + s++; + return s; +} + static const char msgs[] = "Host not found\0" "Try again\0" "Non-recoverable error\0" diff --git a/ulib/axlibc/c/poll.c b/ulib/axlibc/c/poll.c new file mode 100644 index 0000000000..5474246f34 --- /dev/null +++ b/ulib/axlibc/c/poll.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/pow.c b/ulib/axlibc/c/pow.c new file mode 100644 index 0000000000..2172011768 --- /dev/null +++ b/ulib/axlibc/c/pow.c @@ -0,0 +1,815 @@ +#if defined(AX_CONFIG_FP_SIMD) + +#include +#include +#include +#include +#include + +#include "libm.h" + +#define OFF 0x3fe6955500000000 + +#define POW_LOG_TABLE_BITS 7 +#define POW_LOG_POLY_ORDER 8 +#define N (1 << POW_LOG_TABLE_BITS) +struct pow_log_data { + double ln2hi; + double ln2lo; + double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */ + /* Note: the pad field is unused, but allows slightly faster indexing. */ + struct { + double invc, pad, logc, logctail; + } tab[1 << POW_LOG_TABLE_BITS]; +}; + +const struct + pow_log_data + __pow_log_data = + { + .ln2hi = 0x1.62e42fefa3800p-1, + .ln2lo = 0x1.ef35793c76730p-45, + .poly = + { + -0x1p-1, + 0x1.555555555556p-2 * -2, + -0x1.0000000000006p-2 * -2, + 0x1.999999959554ep-3 * 4, + -0x1.555555529a47ap-3 * 4, + 0x1.2495b9b4845e9p-3 * -8, + -0x1.0002b8b263fc3p-3 * -8, + }, + .tab = + { +#define A(a, b, c) {a, 0, b, c}, + A(0x1.6a00000000000p+0, -0x1.62c82f2b9c800p-2, 0x1.ab42428375680p-48) + A(0x1.6800000000000p+0, -0x1.5d1bdbf580800p-2, -0x1.ca508d8e0f720p-46) + A(0x1.6600000000000p+0, -0x1.5767717455800p-2, + -0x1.362a4d5b6506dp-45) + A(0x1.6400000000000p+0, -0x1.51aad872df800p-2, + -0x1.684e49eb067d5p-49) A(0x1.6200000000000p+0, + -0x1.4be5f95777800p-2, + -0x1.41b6993293ee0p-47) A(0x1.6000000000000p+0, -0x1.4618bc21c6000p-2, 0x1.3d82f484c84ccp-46) A(0x1.5e00000000000p+0, -0x1.404308686a800p-2, 0x1.c42f3ed820b3ap-50) A(0x1.5c00000000000p+0, -0x1.3a64c55694800p-2, 0x1.0b1c686519460p-45) A(0x1.5a00000000000p+0, -0x1.347dd9a988000p-2, 0x1.5594dd4c58092p-45) A(0x1.5800000000000p+0, -0x1.2e8e2bae12000p-2, 0x1.67b1e99b72bd8p-45) A(0x1.5600000000000p+0, + -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) A(0x1.5600000000000p+0, + -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) A(0x1.5400000000000p+0, + -0x1.22941fbcf7800p-2, + -0x1.65a242853da76p-46) A(0x1.5200000000000p+0, + -0x1.1c898c1699800p-2, + -0x1.fafbc68e75404p-46) A(0x1.5000000000000p+0, + -0x1.1675cababa800p-2, 0x1.f1fc63382a8f0p-46) A(0x1.4e00000000000p+0, + -0x1.1058bf9ae4800p-2, + -0x1.6a8c4fd055a66p-45) A(0x1.4c00000000000p+0, + -0x1.0a324e2739000p-2, -0x1.c6bee7ef4030ep-47) A(0x1.4a00000000000p+0, + -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) A(0x1.4a00000000000p+0, + -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) A(0x1.4800000000000p+0, + -0x1.fb9186d5e4000p-3, + 0x1.d572aab993c87p-47) A(0x1.4600000000000p+0, + -0x1.ef0adcbdc6000p-3, + 0x1.b26b79c86af24p-45) A(0x1.4400000000000p+0, + -0x1.e27076e2af000p-3, -0x1.72f4f543fff10p-46) A(0x1.4200000000000p+0, + -0x1.d5c216b4fc000p-3, 0x1.1ba91bbca681bp-45) A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) A(0x1.3e00000000000p+0, + -0x1.bc286742d9000p-3, 0x1.94eb0318bb78fp-46) A(0x1.3c00000000000p+0, + -0x1.af3c94e80c000p-3, 0x1.a4e633fcd9066p-52) A(0x1.3a00000000000p+0, + -0x1.a23bc1fe2b000p-3, + -0x1.58c64dc46c1eap-45) A(0x1.3a00000000000p+0, + -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45) A(0x1.3800000000000p+0, + -0x1.9525a9cf45000p-3, -0x1.ad1d904c1d4e3p-45) A(0x1.3600000000000p+0, + -0x1.87fa06520d000p-3, 0x1.bbdbf7fdbfa09p-45) A(0x1.3400000000000p+0, + -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) A(0x1.3400000000000p+0, + -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) A(0x1.3200000000000p+0, -0x1.6d60fe719d000p-3, -0x1.0e46aa3b2e266p-46) A(0x1.3000000000000p+0, + -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) A(0x1.3000000000000p+0, + -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) A(0x1.2e00000000000p+0, + -0x1.526e5e3a1b000p-3, -0x1.0de8b90075b8fp-45) A(0x1.2c00000000000p+0, + -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) A(0x1.2a00000000000p+0, + -0x1.371fc201e9000p-3, 0x1.178864d27543ap-48) A(0x1.2800000000000p+0, + -0x1.29552f81ff000p-3, -0x1.48d301771c408p-45) A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) A(0x1.2400000000000p+0, + -0x1.0d77e7cd09000p-3, + 0x1.a699688e85bf4p-47) A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47) A(0x1.2200000000000p+0, -0x1.fec9131dbe000p-4, -0x1.575545ca333f2p-45) A(0x1.2000000000000p+0, + -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) A(0x1.1e00000000000p+0, -0x1.c5e548f5bc000p-4, -0x1.d0c57585fbe06p-46) A(0x1.1c00000000000p+0, + -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) A(0x1.1c00000000000p+0, + -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46) A(0x1.1a00000000000p+0, + -0x1.8c345d631a000p-4, + 0x1.37c294d2f5668p-46) A(0x1.1800000000000p+0, -0x1.6f0d28ae56000p-4, + -0x1.69737c93373dap-45) A(0x1.1600000000000p+0, + -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) A(0x1.1600000000000p+0, + -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) A(0x1.1400000000000p+0, + -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) A(0x1.1200000000000p+0, -0x1.16536eea38000p-4, 0x1.47c5e768fa309p-46) A(0x1.1000000000000p+0, + -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45) A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, + 0x1.d599e83368e91p-45) A(0x1.0e00000000000p+0, + -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) A(0x1.0e00000000000p+0, + -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) A(0x1.0c00000000000p+0, + -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) A(0x1.0a00000000000p+0, + -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) A(0x1.0600000000000p+0, + -0x1.7b91b07d58000p-6, -0x1.88d5493faa639p-45) A(0x1.0400000000000p+0, + -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46) A(0x1.0200000000000p+0, + -0x1.fe02a6b100000p-8, + -0x1.9e23f0dda40e4p-46) A(0x1.0000000000000p+0, + 0x0.0000000000000p+0, 0x0.0000000000000p+0) A(0x1.0000000000000p+0, + 0x0.0000000000000p+0, + 0x0.0000000000000p+0) A(0x1.fc00000000000p-1, + 0x1.0101575890000p-7, -0x1.0c76b999d2be8p-46) A(0x1.f800000000000p-1, + 0x1.0205658938000p-6, -0x1.3dc5b06e2f7d2p-45) A(0x1.f400000000000p-1, + 0x1.8492528c90000p-6, + -0x1.aa0ba325a0c34p-45) A(0x1.f000000000000p-1, + 0x1.0415d89e74000p-5, + 0x1.111c05cf1d753p-47) A(0x1.ec00000000000p-1, 0x1.466aed42e0000p-5, -0x1.c167375bdfd28p-45) A(0x1.e800000000000p-1, + 0x1.894aa149fc000p-5, + -0x1.97995d05a267dp-46) A(0x1.e400000000000p-1, + 0x1.ccb73cdddc000p-5, -0x1.a68f247d82807p-46) A(0x1.e200000000000p-1, + 0x1.eea31c006c000p-5, + -0x1.e113e4fc93b7bp-47) A(0x1.de00000000000p-1, + 0x1.1973bd1466000p-4, + -0x1.5325d560d9e9bp-45) A(0x1.da00000000000p-1, 0x1.3bdf5a7d1e000p-4, 0x1.cc85ea5db4ed7p-45) A(0x1.d600000000000p-1, 0x1.5e95a4d97a000p-4, -0x1.c69063c5d1d1ep-45) A(0x1.d400000000000p-1, 0x1.700d30aeac000p-4, 0x1.c1e8da99ded32p-49) A(0x1.d000000000000p-1, + 0x1.9335e5d594000p-4, + 0x1.3115c3abd47dap-45) A(0x1.cc00000000000p-1, + 0x1.b6ac88dad6000p-4, + -0x1.390802bf768e5p-46) A(0x1.ca00000000000p-1, + 0x1.c885801bc4000p-4, + 0x1.646d1c65aacd3p-45) A(0x1.c600000000000p-1, + 0x1.ec739830a2000p-4, + -0x1.dc068afe645e0p-45) A(0x1.c400000000000p-1, + 0x1.fe89139dbe000p-4, + -0x1.534d64fa10afdp-45) A(0x1.c000000000000p-1, 0x1.1178e8227e000p-3, 0x1.1ef78ce2d07f2p-45) A(0x1.be00000000000p-1, 0x1.1aa2b7e23f000p-3, 0x1.ca78e44389934p-45) A(0x1.ba00000000000p-1, 0x1.2d1610c868000p-3, 0x1.39d6ccb81b4a1p-47) A(0x1.b800000000000p-1, 0x1.365fcb0159000p-3, 0x1.62fa8234b7289p-51) A(0x1.b400000000000p-1, 0x1.4913d8333b000p-3, 0x1.5837954fdb678p-45) A(0x1.b200000000000p-1, 0x1.527e5e4a1b000p-3, + 0x1.633e8e5697dc7p-45) A(0x1.ae00000000000p-1, + 0x1.6574ebe8c1000p-3, + 0x1.9cf8b2c3c2e78p-46) A(0x1.ac00000000000p-1, + 0x1.6f0128b757000p-3, -0x1.5118de59c21e1p-45) A(0x1.aa00000000000p-1, 0x1.7898d85445000p-3, -0x1.c661070914305p-46) A(0x1.a600000000000p-1, + 0x1.8beafeb390000p-3, -0x1.73d54aae92cd1p-47) A(0x1.a400000000000p-1, 0x1.95a5adcf70000p-3, 0x1.7f22858a0ff6fp-47) A(0x1.a000000000000p-1, 0x1.a93ed3c8ae000p-3, -0x1.8724350562169p-45) A(0x1.9e00000000000p-1, 0x1.b31d8575bd000p-3, -0x1.c358d4eace1aap-47) A(0x1.9c00000000000p-1, 0x1.bd087383be000p-3, -0x1.d4bc4595412b6p-45) A(0x1.9a00000000000p-1, 0x1.c6ffbc6f01000p-3, -0x1.1ec72c5962bd2p-48) A(0x1.9600000000000p-1, 0x1.db13db0d49000p-3, -0x1.aff2af715b035p-45) A(0x1.9400000000000p-1, + 0x1.e530effe71000p-3, + 0x1.212276041f430p-51) A(0x1.9200000000000p-1, 0x1.ef5ade4dd0000p-3, -0x1.a211565bb8e11p-51) A(0x1.9000000000000p-1, 0x1.f991c6cb3b000p-3, 0x1.bcbecca0cdf30p-46) A(0x1.8c00000000000p-1, 0x1.07138604d5800p-2, 0x1.89cdb16ed4e91p-48) A(0x1.8a00000000000p-1, + 0x1.0c42d67616000p-2, + 0x1.7188b163ceae9p-45) A(0x1.8800000000000p-1, 0x1.1178e8227e800p-2, -0x1.c210e63a5f01cp-45) A(0x1.8600000000000p-1, + 0x1.16b5ccbacf800p-2, + 0x1.b9acdf7a51681p-45) A(0x1.8400000000000p-1, + 0x1.1bf99635a6800p-2, + 0x1.ca6ed5147bdb7p-45) A(0x1.8200000000000p-1, + 0x1.214456d0eb800p-2, + 0x1.a87deba46baeap-47) A(0x1.7e00000000000p-1, + 0x1.2bef07cdc9000p-2, 0x1.a9cfa4a5004f4p-45) A(0x1.7c00000000000p-1, 0x1.314f1e1d36000p-2, -0x1.8e27ad3213cb8p-45) A(0x1.7a00000000000p-1, 0x1.36b6776be1000p-2, 0x1.16ecdb0f177c8p-46) A(0x1.7800000000000p-1, + 0x1.3c25277333000p-2, + 0x1.83b54b606bd5cp-46) A(0x1.7600000000000p-1, + 0x1.419b423d5e800p-2, + 0x1.8e436ec90e09dp-47) A(0x1.7400000000000p-1, 0x1.4718dc271c800p-2, -0x1.f27ce0967d675p-45) A(0x1.7200000000000p-1, 0x1.4c9e09e173000p-2, -0x1.e20891b0ad8a4p-45) A(0x1.7000000000000p-1, + 0x1.522ae0738a000p-2, + 0x1.ebe708164c759p-45) A(0x1.6e00000000000p-1, 0x1.57bf753c8d000p-2, 0x1.fadedee5d40efp-46) A(0x1.6c00000000000p-1, + 0x1.5d5bddf596000p-2, + -0x1.a0b2a08a465dcp-47)}, +}; + +#define T __pow_log_data.tab +#undef A +#define A __pow_log_data.poly +#define Ln2hi __pow_log_data.ln2hi +#define Ln2lo __pow_log_data.ln2lo + +/* Top 12 bits of a double (sign and exponent bits). */ +static inline uint32_t top12(double x) +{ + return asuint64(x) >> 52; +} + +/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about + additional 15 bits precision. IX is the bit representation of x, but + normalized in the subnormal range using the sign bit for the exponent. */ +static inline double_t log_inline(uint64_t ix, double_t *tail) +{ + /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ + double_t z, r, y, invc, logc, logctail, kd, hi, t1, t2, lo, lo1, lo2, p; + uint64_t iz, tmp; + int k, i; + + /* x = 2^k z; where z is in range [OFF,2*OFF) and exact. + The range is split into N subintervals. + The ith subinterval contains z and c is near its center. */ + tmp = ix - OFF; + i = (tmp >> (52 - POW_LOG_TABLE_BITS)) % N; + k = (int64_t)tmp >> 52; /* arithmetic shift */ + iz = ix - (tmp & 0xfffULL << 52); + z = asdouble(iz); + kd = (double_t)k; + + /* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */ + invc = T[i].invc; + logc = T[i].logc; + logctail = T[i].logctail; + + /* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and + |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */ +#if __FP_FAST_FMA + r = __builtin_fma(z, invc, -1.0); +#else + /* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */ + double_t zhi = asdouble((iz + (1ULL << 31)) & (-1ULL << 32)); + double_t zlo = z - zhi; + double_t rhi = zhi * invc - 1.0; + double_t rlo = zlo * invc; + r = rhi + rlo; +#endif + + /* k*Ln2 + log(c) + r. */ + t1 = kd * Ln2hi + logc; + t2 = t1 + r; + lo1 = kd * Ln2lo + logctail; + lo2 = t1 - t2 + r; + + /* Evaluation is optimized assuming superscalar pipelined execution. */ + double_t ar, ar2, ar3, lo3, lo4; + ar = A[0] * r; /* A[0] = -0.5. */ + ar2 = r * ar; + ar3 = r * ar2; + /* k*Ln2 + log(c) + r + A[0]*r*r. */ +#if __FP_FAST_FMA + hi = t2 + ar2; + lo3 = __builtin_fma(ar, r, -ar2); + lo4 = t2 - hi + ar2; +#else + double_t arhi = A[0] * rhi; + double_t arhi2 = rhi * arhi; + hi = t2 + arhi2; + lo3 = rlo * (ar + arhi); + lo4 = t2 - hi + arhi2; +#endif + /* p = log1p(r) - r - A[0]*r*r. */ + p = (ar3 * (A[1] + r * A[2] + ar2 * (A[3] + r * A[4] + ar2 * (A[5] + r * A[6])))); + lo = lo1 + lo2 + lo3 + lo4 + p; + y = hi + lo; + *tail = hi - y + lo; + return y; +} + +#undef N +#undef T +#define EXP_TABLE_BITS 7 +#define EXP_POLY_ORDER 5 +#define EXP_USE_TOINT_NARROW 0 +#define EXP2_POLY_ORDER 5 +struct exp_data { + double invln2N; + double shift; + double negln2hiN; + double negln2loN; + double poly[4]; /* Last four coefficients. */ + double exp2_shift; + double exp2_poly[EXP2_POLY_ORDER]; + uint64_t tab[2 * (1 << EXP_TABLE_BITS)]; +}; +#define N (1 << EXP_TABLE_BITS) + +const struct exp_data __exp_data = { + // N/ln2 + .invln2N = 0x1.71547652b82fep0 * N, + // -ln2/N + .negln2hiN = -0x1.62e42fefa0000p-8, + .negln2loN = -0x1.cf79abc9e3b3ap-47, +// Used for rounding when !TOINT_INTRINSICS +#if EXP_USE_TOINT_NARROW + .shift = 0x1800000000.8p0, +#else + .shift = 0x1.8p52, +#endif + // exp polynomial coefficients. + .poly = + { + // abs error: 1.555*2^-66 + // ulp error: 0.509 (0.511 without fma) + // if |x| < ln2/256+eps + // abs error if |x| < ln2/256+0x1p-15: 1.09*2^-65 + // abs error if |x| < ln2/128: 1.7145*2^-56 + 0x1.ffffffffffdbdp-2, + 0x1.555555555543cp-3, + 0x1.55555cf172b91p-5, + 0x1.1111167a4d017p-7, + }, + .exp2_shift = 0x1.8p52 / N, + // exp2 polynomial coefficients. + .exp2_poly = + { + // abs error: 1.2195*2^-65 + // ulp error: 0.507 (0.511 without fma) + // if |x| < 1/256 + // abs error if |x| < 1/128: 1.9941*2^-56 + 0x1.62e42fefa39efp-1, + 0x1.ebfbdff82c424p-3, + 0x1.c6b08d70cf4b5p-5, + 0x1.3b2abd24650ccp-7, + 0x1.5d7e09b4e3a84p-10, + }, + // 2^(k/N) ~= H[k]*(1 + T[k]) for int k in [0,N) + // tab[2*k] = asuint64(T[k]) + // tab[2*k+1] = asuint64(H[k]) - (k << 52)/N + .tab = + { + 0x0, + 0x3ff0000000000000, + 0x3c9b3b4f1a88bf6e, + 0x3feff63da9fb3335, + 0xbc7160139cd8dc5d, + 0x3fefec9a3e778061, + 0xbc905e7a108766d1, + 0x3fefe315e86e7f85, + 0x3c8cd2523567f613, + 0x3fefd9b0d3158574, + 0xbc8bce8023f98efa, + 0x3fefd06b29ddf6de, + 0x3c60f74e61e6c861, + 0x3fefc74518759bc8, + 0x3c90a3e45b33d399, + 0x3fefbe3ecac6f383, + 0x3c979aa65d837b6d, + 0x3fefb5586cf9890f, + 0x3c8eb51a92fdeffc, + 0x3fefac922b7247f7, + 0x3c3ebe3d702f9cd1, + 0x3fefa3ec32d3d1a2, + 0xbc6a033489906e0b, + 0x3fef9b66affed31b, + 0xbc9556522a2fbd0e, + 0x3fef9301d0125b51, + 0xbc5080ef8c4eea55, + 0x3fef8abdc06c31cc, + 0xbc91c923b9d5f416, + 0x3fef829aaea92de0, + 0x3c80d3e3e95c55af, + 0x3fef7a98c8a58e51, + 0xbc801b15eaa59348, + 0x3fef72b83c7d517b, + 0xbc8f1ff055de323d, + 0x3fef6af9388c8dea, + 0x3c8b898c3f1353bf, + 0x3fef635beb6fcb75, + 0xbc96d99c7611eb26, + 0x3fef5be084045cd4, + 0x3c9aecf73e3a2f60, + 0x3fef54873168b9aa, + 0xbc8fe782cb86389d, + 0x3fef4d5022fcd91d, + 0x3c8a6f4144a6c38d, + 0x3fef463b88628cd6, + 0x3c807a05b0e4047d, + 0x3fef3f49917ddc96, + 0x3c968efde3a8a894, + 0x3fef387a6e756238, + 0x3c875e18f274487d, + 0x3fef31ce4fb2a63f, + 0x3c80472b981fe7f2, + 0x3fef2b4565e27cdd, + 0xbc96b87b3f71085e, + 0x3fef24dfe1f56381, + 0x3c82f7e16d09ab31, + 0x3fef1e9df51fdee1, + 0xbc3d219b1a6fbffa, + 0x3fef187fd0dad990, + 0x3c8b3782720c0ab4, + 0x3fef1285a6e4030b, + 0x3c6e149289cecb8f, + 0x3fef0cafa93e2f56, + 0x3c834d754db0abb6, + 0x3fef06fe0a31b715, + 0x3c864201e2ac744c, + 0x3fef0170fc4cd831, + 0x3c8fdd395dd3f84a, + 0x3feefc08b26416ff, + 0xbc86a3803b8e5b04, + 0x3feef6c55f929ff1, + 0xbc924aedcc4b5068, + 0x3feef1a7373aa9cb, + 0xbc9907f81b512d8e, + 0x3feeecae6d05d866, + 0xbc71d1e83e9436d2, + 0x3feee7db34e59ff7, + 0xbc991919b3ce1b15, + 0x3feee32dc313a8e5, + 0x3c859f48a72a4c6d, + 0x3feedea64c123422, + 0xbc9312607a28698a, + 0x3feeda4504ac801c, + 0xbc58a78f4817895b, + 0x3feed60a21f72e2a, + 0xbc7c2c9b67499a1b, + 0x3feed1f5d950a897, + 0x3c4363ed60c2ac11, + 0x3feece086061892d, + 0x3c9666093b0664ef, + 0x3feeca41ed1d0057, + 0x3c6ecce1daa10379, + 0x3feec6a2b5c13cd0, + 0x3c93ff8e3f0f1230, + 0x3feec32af0d7d3de, + 0x3c7690cebb7aafb0, + 0x3feebfdad5362a27, + 0x3c931dbdeb54e077, + 0x3feebcb299fddd0d, + 0xbc8f94340071a38e, + 0x3feeb9b2769d2ca7, + 0xbc87deccdc93a349, + 0x3feeb6daa2cf6642, + 0xbc78dec6bd0f385f, + 0x3feeb42b569d4f82, + 0xbc861246ec7b5cf6, + 0x3feeb1a4ca5d920f, + 0x3c93350518fdd78e, + 0x3feeaf4736b527da, + 0x3c7b98b72f8a9b05, + 0x3feead12d497c7fd, + 0x3c9063e1e21c5409, + 0x3feeab07dd485429, + 0x3c34c7855019c6ea, + 0x3feea9268a5946b7, + 0x3c9432e62b64c035, + 0x3feea76f15ad2148, + 0xbc8ce44a6199769f, + 0x3feea5e1b976dc09, + 0xbc8c33c53bef4da8, + 0x3feea47eb03a5585, + 0xbc845378892be9ae, + 0x3feea34634ccc320, + 0xbc93cedd78565858, + 0x3feea23882552225, + 0x3c5710aa807e1964, + 0x3feea155d44ca973, + 0xbc93b3efbf5e2228, + 0x3feea09e667f3bcd, + 0xbc6a12ad8734b982, + 0x3feea012750bdabf, + 0xbc6367efb86da9ee, + 0x3fee9fb23c651a2f, + 0xbc80dc3d54e08851, + 0x3fee9f7df9519484, + 0xbc781f647e5a3ecf, + 0x3fee9f75e8ec5f74, + 0xbc86ee4ac08b7db0, + 0x3fee9f9a48a58174, + 0xbc8619321e55e68a, + 0x3fee9feb564267c9, + 0x3c909ccb5e09d4d3, + 0x3feea0694fde5d3f, + 0xbc7b32dcb94da51d, + 0x3feea11473eb0187, + 0x3c94ecfd5467c06b, + 0x3feea1ed0130c132, + 0x3c65ebe1abd66c55, + 0x3feea2f336cf4e62, + 0xbc88a1c52fb3cf42, + 0x3feea427543e1a12, + 0xbc9369b6f13b3734, + 0x3feea589994cce13, + 0xbc805e843a19ff1e, + 0x3feea71a4623c7ad, + 0xbc94d450d872576e, + 0x3feea8d99b4492ed, + 0x3c90ad675b0e8a00, + 0x3feeaac7d98a6699, + 0x3c8db72fc1f0eab4, + 0x3feeace5422aa0db, + 0xbc65b6609cc5e7ff, + 0x3feeaf3216b5448c, + 0x3c7bf68359f35f44, + 0x3feeb1ae99157736, + 0xbc93091fa71e3d83, + 0x3feeb45b0b91ffc6, + 0xbc5da9b88b6c1e29, + 0x3feeb737b0cdc5e5, + 0xbc6c23f97c90b959, + 0x3feeba44cbc8520f, + 0xbc92434322f4f9aa, + 0x3feebd829fde4e50, + 0xbc85ca6cd7668e4b, + 0x3feec0f170ca07ba, + 0x3c71affc2b91ce27, + 0x3feec49182a3f090, + 0x3c6dd235e10a73bb, + 0x3feec86319e32323, + 0xbc87c50422622263, + 0x3feecc667b5de565, + 0x3c8b1c86e3e231d5, + 0x3feed09bec4a2d33, + 0xbc91bbd1d3bcbb15, + 0x3feed503b23e255d, + 0x3c90cc319cee31d2, + 0x3feed99e1330b358, + 0x3c8469846e735ab3, + 0x3feede6b5579fdbf, + 0xbc82dfcd978e9db4, + 0x3feee36bbfd3f37a, + 0x3c8c1a7792cb3387, + 0x3feee89f995ad3ad, + 0xbc907b8f4ad1d9fa, + 0x3feeee07298db666, + 0xbc55c3d956dcaeba, + 0x3feef3a2b84f15fb, + 0xbc90a40e3da6f640, + 0x3feef9728de5593a, + 0xbc68d6f438ad9334, + 0x3feeff76f2fb5e47, + 0xbc91eee26b588a35, + 0x3fef05b030a1064a, + 0x3c74ffd70a5fddcd, + 0x3fef0c1e904bc1d2, + 0xbc91bdfbfa9298ac, + 0x3fef12c25bd71e09, + 0x3c736eae30af0cb3, + 0x3fef199bdd85529c, + 0x3c8ee3325c9ffd94, + 0x3fef20ab5fffd07a, + 0x3c84e08fd10959ac, + 0x3fef27f12e57d14b, + 0x3c63cdaf384e1a67, + 0x3fef2f6d9406e7b5, + 0x3c676b2c6c921968, + 0x3fef3720dcef9069, + 0xbc808a1883ccb5d2, + 0x3fef3f0b555dc3fa, + 0xbc8fad5d3ffffa6f, + 0x3fef472d4a07897c, + 0xbc900dae3875a949, + 0x3fef4f87080d89f2, + 0x3c74a385a63d07a7, + 0x3fef5818dcfba487, + 0xbc82919e2040220f, + 0x3fef60e316c98398, + 0x3c8e5a50d5c192ac, + 0x3fef69e603db3285, + 0x3c843a59ac016b4b, + 0x3fef7321f301b460, + 0xbc82d52107b43e1f, + 0x3fef7c97337b9b5f, + 0xbc892ab93b470dc9, + 0x3fef864614f5a129, + 0x3c74b604603a88d3, + 0x3fef902ee78b3ff6, + 0x3c83c5ec519d7271, + 0x3fef9a51fbc74c83, + 0xbc8ff7128fd391f0, + 0x3fefa4afa2a490da, + 0xbc8dae98e223747d, + 0x3fefaf482d8e67f1, + 0x3c8ec3bc41aa2008, + 0x3fefba1bee615a27, + 0x3c842b94c3a9eb32, + 0x3fefc52b376bba97, + 0x3c8a64a931d185ee, + 0x3fefd0765b6e4540, + 0xbc8e37bae43be3ed, + 0x3fefdbfdad9cbe14, + 0x3c77893b4d91cd9d, + 0x3fefe7c1819e90d8, + 0x3c5305c14160cc89, + 0x3feff3c22b8f71f1, + }, +}; + +#define InvLn2N __exp_data.invln2N +#define NegLn2hiN __exp_data.negln2hiN +#define NegLn2loN __exp_data.negln2loN +#define Shift __exp_data.shift +#define T __exp_data.tab +#define C2 __exp_data.poly[5 - EXP_POLY_ORDER] +#define C3 __exp_data.poly[6 - EXP_POLY_ORDER] +#define C4 __exp_data.poly[7 - EXP_POLY_ORDER] +#define C5 __exp_data.poly[8 - EXP_POLY_ORDER] +#define C6 __exp_data.poly[9 - EXP_POLY_ORDER] + +static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) +{ + double_t scale, y; + + if ((ki & 0x80000000) == 0) { + /* k > 0, the exponent of scale might have overflowed by <= 460. */ + sbits -= 1009ull << 52; + scale = asdouble(sbits); + y = 0x1p1009 * (scale + scale * tmp); + return eval_as_double(y); + } + /* k < 0, need special care in the subnormal range. */ + sbits += 1022ull << 52; + /* Note: sbits is signed scale. */ + scale = asdouble(sbits); + y = scale + scale * tmp; + if (fabs(y) < 1.0) { + /* Round y to the right precision before scaling it into the subnormal + range to avoid double rounding that can cause 0.5+E/2 ulp error where + E is the worst-case ulp error outside the subnormal range. So this + is only useful if the goal is better than 1 ulp worst-case error. */ + double_t hi, lo, one = 1.0; + if (y < 0.0) + one = -1.0; + lo = scale - y + scale * tmp; + hi = one + y; + lo = one - hi + y + lo; + y = eval_as_double(hi + lo) - one; + /* Fix the sign of 0. */ + if (y == 0.0) + y = asdouble(sbits & 0x8000000000000000); + /* The underflow exception needs to be signaled explicitly. */ + fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); + } + y = 0x1p-1022 * y; + return eval_as_double(y); +} + +#define SIGN_BIAS (0x800 << EXP_TABLE_BITS) + +double __math_xflow(uint32_t sign, double y) +{ + return eval_as_double(fp_barrier(sign ? -y : y) * y); +} + +double __math_uflow(uint32_t sign) +{ + return __math_xflow(sign, 0x1p-767); +} + +double __math_oflow(uint32_t sign) +{ + return __math_xflow(sign, 0x1p769); +} + +/* Computes sign*exp(x+xtail) where |xtail| < 2^-8/N and |xtail| <= |x|. + The sign_bias argument is SIGN_BIAS or 0 and sets the sign to -1 or 1. */ +static inline double exp_inline(double_t x, double_t xtail, uint32_t sign_bias) +{ + uint32_t abstop; + uint64_t ki, idx, top, sbits; + /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ + double_t kd, z, r, r2, scale, tail, tmp; + + abstop = top12(x) & 0x7ff; + if (predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) { + if (abstop - top12(0x1p-54) >= 0x80000000) { + /* Avoid spurious underflow for tiny x. */ + /* Note: 0 is common input. */ + double_t one = WANT_ROUNDING ? 1.0 + x : 1.0; + return sign_bias ? -one : one; + } + if (abstop >= top12(1024.0)) { + /* Note: inf and nan are already handled. */ + if (asuint64(x) >> 63) + return __math_uflow(sign_bias); + else + return __math_oflow(sign_bias); + } + /* Large x is special cased below. */ + abstop = 0; + } + + /* exp(x) = 2^(k/N) * exp(r), with exp(r) in [2^(-1/2N),2^(1/2N)]. */ + /* x = ln2/N*k + r, with int k and r in [-ln2/2N, ln2/2N]. */ + z = InvLn2N * x; +#if TOINT_INTRINSICS + kd = roundtoint(z); + ki = converttoint(z); +#elif EXP_USE_TOINT_NARROW + /* z - kd is in [-0.5-2^-16, 0.5] in all rounding modes. */ + kd = eval_as_double(z + Shift); + ki = asuint64(kd) >> 16; + kd = (double_t)(int32_t)ki; +#else + /* z - kd is in [-1, 1] in non-nearest rounding modes. */ + kd = eval_as_double(z + Shift); + ki = asuint64(kd); + kd -= Shift; +#endif + r = x + kd * NegLn2hiN + kd * NegLn2loN; + /* The code assumes 2^-200 < |xtail| < 2^-8/N. */ + r += xtail; + /* 2^(k/N) ~= scale * (1 + tail). */ + idx = 2 * (ki % N); + top = (ki + sign_bias) << (52 - EXP_TABLE_BITS); + tail = asdouble(T[idx]); + /* This is only a valid scale when -1023*N < k < 1024*N. */ + sbits = T[idx + 1] + top; + /* exp(x) = 2^(k/N) * exp(r) ~= scale + scale * (tail + exp(r) - 1). */ + /* Evaluation is optimized assuming superscalar pipelined execution. */ + r2 = r * r; + /* Without fma the worst case error is 0.25/N ulp larger. */ + /* Worst case error is less than 0.5+1.11/N+(abs poly error * 2^53) ulp. */ + tmp = tail + r + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5); + if (predict_false(abstop == 0)) + return specialcase(tmp, sbits, ki); + scale = asdouble(sbits); + /* Note: tmp == 0 or |tmp| > 2^-200 and scale > 2^-739, so there + is no spurious underflow here even without fma. */ + return eval_as_double(scale + scale * tmp); +} + +/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is + the bit representation of a non-zero finite floating-point value. */ +static inline int checkint(uint64_t iy) +{ + int e = iy >> 52 & 0x7ff; + if (e < 0x3ff) + return 0; + if (e > 0x3ff + 52) + return 2; + if (iy & ((1ULL << (0x3ff + 52 - e)) - 1)) + return 0; + if (iy & (1ULL << (0x3ff + 52 - e))) + return 1; + return 2; +} + +#if 100 * __GNUC__ + __GNUC_MINOR__ >= 303 +#define NAN __builtin_nanf("") +#define INFINITY __builtin_inff() +#else +#define NAN (0.0f / 0.0f) +#define INFINITY 1e5000f +#endif + +static inline int zeroinfnan(uint64_t i) +{ + return 2 * i - 1 >= 2 * asuint64(INFINITY) - 1; +} + +#if WANT_SNAN +#error SNaN is unsupported +#else +#define issignalingf_inline(x) 0 +#define issignaling_inline(x) 0 +#endif + +double pow(double x, double y) +{ + uint32_t sign_bias = 0; + uint64_t ix, iy; + uint32_t topx, topy; + + ix = asuint64(x); + iy = asuint64(y); + topx = top12(x); + topy = top12(y); + if (predict_false(topx - 0x001 >= 0x7ff - 0x001 || (topy & 0x7ff) - 0x3be >= 0x43e - 0x3be)) { + /* Note: if |y| > 1075 * ln2 * 2^53 ~= 0x1.749p62 then pow(x,y) = inf/0 + and if |y| < 2^-54 / 1075 ~= 0x1.e7b6p-65 then pow(x,y) = +-1. */ + /* Special cases: (x < 0x1p-126 or inf or nan) or + (|y| < 0x1p-65 or |y| >= 0x1p63 or nan). */ + if (predict_false(zeroinfnan(iy))) { + if (2 * iy == 0) + return issignaling_inline(x) ? x + y : 1.0; + if (ix == asuint64(1.0)) + return issignaling_inline(y) ? x + y : 1.0; + if (2 * ix > 2 * asuint64(INFINITY) || 2 * iy > 2 * asuint64(INFINITY)) + return x + y; + if (2 * ix == 2 * asuint64(1.0)) + return 1.0; + if ((2 * ix < 2 * asuint64(1.0)) == !(iy >> 63)) + return 0.0; /* |x|<1 && y==inf or |x|>1 && y==-inf. */ + return y * y; + } + if (predict_false(zeroinfnan(ix))) { + double_t x2 = x * x; + if (ix >> 63 && checkint(iy) == 1) + x2 = -x2; + /* Without the barrier some versions of clang hoist the 1/x2 and + thus division by zero exception can be signaled spuriously. */ + return iy >> 63 ? fp_barrier(1 / x2) : x2; + } + /* Here x and y are non-zero finite. */ + if (ix >> 63) { + /* Finite x < 0. */ + int yint = checkint(iy); + if (yint == 0) + return __math_invalid(x); + if (yint == 1) + sign_bias = SIGN_BIAS; + ix &= 0x7fffffffffffffff; + topx &= 0x7ff; + } + if ((topy & 0x7ff) - 0x3be >= 0x43e - 0x3be) { + /* Note: sign_bias == 0 here because y is not odd. */ + if (ix == asuint64(1.0)) + return 1.0; + if ((topy & 0x7ff) < 0x3be) { + /* |y| < 2^-65, x^y ~= 1 + y*log(x). */ + if (WANT_ROUNDING) + return ix > asuint64(1.0) ? 1.0 + y : 1.0 - y; + else + return 1.0; + } + return (ix > asuint64(1.0)) == (topy < 0x800) ? __math_oflow(0) : __math_uflow(0); + } + if (topx == 0) { + /* Normalize subnormal x so exponent becomes negative. */ + ix = asuint64(x * 0x1p52); + ix &= 0x7fffffffffffffff; + ix -= 52ULL << 52; + } + } + + double_t lo; + double_t hi = log_inline(ix, &lo); + double_t ehi, elo; +#if __FP_FAST_FMA + ehi = y * hi; + elo = y * lo + __builtin_fma(y, hi, -ehi); +#else + double_t yhi = asdouble(iy & -1ULL << 27); + double_t ylo = y - yhi; + double_t lhi = asdouble(asuint64(hi) & -1ULL << 27); + double_t llo = hi - lhi + lo; + ehi = yhi * lhi; + elo = ylo * lhi + y * llo; /* |elo| < |ehi| * 2^-25. */ +#endif + return exp_inline(ehi, elo, sign_bias); +} +#endif diff --git a/ulib/axlibc/c/pthread.c b/ulib/axlibc/c/pthread.c index 36a3a16fd1..ac6bc26a6d 100644 --- a/ulib/axlibc/c/pthread.c +++ b/ulib/axlibc/c/pthread.c @@ -1,6 +1,8 @@ #ifdef AX_CONFIG_MULTITASK #include +#include +#include #include #include @@ -37,21 +39,107 @@ int pthread_setcanceltype(int new, int *old) return 0; } -int pthread_mutex_init(pthread_mutex_t *restrict m, const pthread_mutexattr_t *restrict a) +// TODO +void pthread_testcancel(void) { - ax_pthread_mutex_init(m, a); + unimplemented(); + return; +} + +// TODO +int pthread_cancel(pthread_t t) +{ + unimplemented(); 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) { - ax_pthread_mutex_lock(m); - return 0; + return ax_pthread_mutex_lock(m); } int pthread_mutex_unlock(pthread_mutex_t *m) { - ax_pthread_mutex_unlock(m); + return ax_pthread_mutex_unlock(m); +} + +// TODO +int pthread_mutex_trylock(pthread_mutex_t *m) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_setname_np(pthread_t thread, const char *name) +{ + unimplemented(); + return 0; +} + +int pthread_cond_init(pthread_cond_t *restrict c, const pthread_condattr_t *restrict a) +{ + *c = (pthread_cond_t){0}; + if (a) { + c->_c_clock = a->__attr & 0x7fffffff; + if (a->__attr >> 31) + c->_c_shared = (void *)-1; + } + return 0; +} + +// TODO +int pthread_cond_signal(pthread_cond_t *__cond) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_cond_broadcast(pthread_cond_t *c) +{ + unimplemented(); + return 0; +} + +#define DEFAULT_STACK_SIZE 131072 +#define DEFAULT_GUARD_SIZE 8192 + +// TODO +int pthread_attr_init(pthread_attr_t *a) +{ + *a = (pthread_attr_t){0}; + // __acquire_ptc(); + a->_a_stacksize = DEFAULT_STACK_SIZE; + a->_a_guardsize = DEFAULT_GUARD_SIZE; + // __release_ptc(); + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t *restrict a, size_t *restrict size) +{ + *size = a->_a_stacksize; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t *a, size_t size) +{ + if (size - PTHREAD_STACK_MIN > SIZE_MAX / 4) + return EINVAL; + a->_a_stackaddr = 0; + a->_a_stacksize = size; return 0; } diff --git a/ulib/axlibc/c/pwd.c b/ulib/axlibc/c/pwd.c new file mode 100644 index 0000000000..61f32f4ae2 --- /dev/null +++ b/ulib/axlibc/c/pwd.c @@ -0,0 +1,14 @@ +#include +#include + +int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ + unimplemented(); + return 0; +} + +int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/sched.c b/ulib/axlibc/c/sched.c new file mode 100644 index 0000000000..21203c465f --- /dev/null +++ b/ulib/axlibc/c/sched.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int sched_setaffinity(pid_t __pid, size_t __cpusetsize, const cpu_set_t *__cpuset) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/signal.c b/ulib/axlibc/c/signal.c index a324e8b8c0..de2164767e 100644 --- a/ulib/axlibc/c/signal.c +++ b/ulib/axlibc/c/signal.c @@ -32,3 +32,56 @@ int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *r { return sigaction_helper(sig, act, oact, sizeof(sigset_t)); } + +// TODO +int kill(pid_t __pid, int __sig) +{ + unimplemented(); + return 0; +} + +int sigemptyset(sigset_t *set) +{ + set->__bits[0] = 0; + if (sizeof(long) == 4 || _NSIG > 65) + set->__bits[1] = 0; + if (sizeof(long) == 4 && _NSIG > 65) { + set->__bits[2] = 0; + set->__bits[3] = 0; + } + return 0; +} + +// TODO +int raise(int __sig) +{ + unimplemented(); + return 0; +} + +int sigaddset(sigset_t *set, int sig) +{ + unsigned s = sig - 1; + if (s >= _NSIG - 1 || sig - 32U < 3) { + errno = EINVAL; + return -1; + } + set->__bits[s / 8 / sizeof *set->__bits] |= 1UL << (s & (8 * sizeof *set->__bits - 1)); + return 0; +} + +// TODO +int pthread_sigmask(int __how, const sigset_t *restrict __newmask, sigset_t *restrict __oldmask) +{ + unimplemented(); + return 0; +} + +#ifdef AX_CONFIG_MULTITASK +// TODO +int pthread_kill(pthread_t t, int sig) +{ + unimplemented(); + return 0; +} +#endif diff --git a/ulib/axlibc/c/stdlib.c b/ulib/axlibc/c/stdlib.c index 5f18da3155..b622273571 100644 --- a/ulib/axlibc/c/stdlib.c +++ b/ulib/axlibc/c/stdlib.c @@ -9,6 +9,9 @@ #include +char *program_invocation_short_name = NULL; +char *program_invocation_name = NULL; + #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) void srand(unsigned s) @@ -21,6 +24,16 @@ int rand(void) return ax_rand_u32(); } +long random(void) +{ + return (long)ax_rand_u32(); +} + +void srandom(unsigned int s) +{ + ax_srand(s); +} + #ifdef AX_CONFIG_ALLOC void *malloc(size_t size) @@ -383,4 +396,31 @@ 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) +{ + return (long double)strtod(s, p); +} + #endif // AX_CONFIG_FP_SIMD + +// TODO +void qsort(void *, size_t, size_t, int (*)(const void *, const void *)) +{ + unimplemented(); + return; +} + +// TODO +int mkostemp(char *__template, int __flags) +{ + unimplemented(); + return 0; +} + +// TODO +int system(const char *) +{ + unimplemented(); + return 0; +} diff --git a/ulib/axlibc/c/time.c b/ulib/axlibc/c/time.c index 540b1ff5a3..8f806013ea 100644 --- a/ulib/axlibc/c/time.c +++ b/ulib/axlibc/c/time.c @@ -216,9 +216,7 @@ double difftime(time_t t1, time_t t0) } #endif -// TODO time_t mktime(struct tm *tm) { - unimplemented(); - return 0; + return ax_mktime(tm); } diff --git a/ulib/axlibc/cbindgen.toml b/ulib/axlibc/cbindgen.toml index 1c4175ab0f..4aa16d9801 100644 --- a/ulib/axlibc/cbindgen.toml +++ b/ulib/axlibc/cbindgen.toml @@ -23,6 +23,7 @@ includes = ["axconfig.h"] "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 b749c51c58..e58d4dad7f 100644 --- a/ulib/axlibc/ctypes.h +++ b/ulib/axlibc/ctypes.h @@ -12,4 +12,5 @@ #include #include #include +#include #include diff --git a/ulib/axlibc/include/errno.h b/ulib/axlibc/include/errno.h index 537a7504e4..f99d2c578e 100644 --- a/ulib/axlibc/include/errno.h +++ b/ulib/axlibc/include/errno.h @@ -136,7 +136,11 @@ #define ERFKILL 132 /* Operation not possible due to RF-kill */ #define EHWPOISON 133 /* Memory page has hardware error */ +#ifndef ENOTSUP +#define ENOTSUP EOPNOTSUPP +#endif + int *__errno_location(void); #define errno (*__errno_location()) -#endif +#endif // __ERRNO_H__ diff --git a/ulib/axlibc/include/locale.h b/ulib/axlibc/include/locale.h index 2e352630de..e33b137128 100644 --- a/ulib/axlibc/include/locale.h +++ b/ulib/axlibc/include/locale.h @@ -53,4 +53,7 @@ struct __locale_struct { typedef struct __locale_struct *locale_t; -#endif +char *setlocale(int, const char *); +struct lconv *localeconv(void); + +#endif // _LOCALE_H diff --git a/ulib/axlibc/include/math.h b/ulib/axlibc/include/math.h index f011205f8b..8b6105b378 100644 --- a/ulib/axlibc/include/math.h +++ b/ulib/axlibc/include/math.h @@ -24,6 +24,10 @@ typedef double double_t; #define FP_ILOGBNAN (-1 - 0x7fffffff) #define FP_ILOGB0 FP_ILOGBNAN +#define LOG_TABLE_BITS 7 +#define LOG_POLY_ORDER 6 +#define LOG_POLY1_ORDER 12 + #define FP_NAN 0 #define FP_INFINITE 1 #define FP_ZERO 2 diff --git a/ulib/axlibc/include/memory.h b/ulib/axlibc/include/memory.h new file mode 100644 index 0000000000..d51b932ee5 --- /dev/null +++ b/ulib/axlibc/include/memory.h @@ -0,0 +1,6 @@ +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include + +#endif // __MEMORY_H__ diff --git a/ulib/axlibc/include/netdb.h b/ulib/axlibc/include/netdb.h index d908bb8085..84f3bdfdd2 100644 --- a/ulib/axlibc/include/netdb.h +++ b/ulib/axlibc/include/netdb.h @@ -16,6 +16,28 @@ struct addrinfo { struct addrinfo *ai_next; }; +struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + volatile int lock[1]; + short slot, ref; +}; + +struct service { + uint16_t port; + unsigned char proto, socktype; +}; + +struct address { + int family; + unsigned scopeid; + uint8_t addr[16]; + int sortkey; +}; + #define AI_PASSIVE 0x01 #define AI_CANONNAME 0x02 #define AI_NUMERICHOST 0x04 @@ -51,10 +73,13 @@ struct addrinfo { extern int h_errno; 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); void freeaddrinfo(struct addrinfo *); +const char *gai_strerror(int __ecode); #endif // AX_CONFIG_NET diff --git a/ulib/axlibc/include/netinet/in.h b/ulib/axlibc/include/netinet/in.h index 3fad6963f1..370f3b17bf 100644 --- a/ulib/axlibc/include/netinet/in.h +++ b/ulib/axlibc/include/netinet/in.h @@ -47,6 +47,52 @@ uint16_t ntohs(uint16_t); #define IPPROTO_MPTCP 262 #define IPPROTO_MAX 263 +#define IPV6_ADDRFORM 1 +#define IPV6_2292PKTINFO 2 +#define IPV6_2292HOPOPTS 3 +#define IPV6_2292DSTOPTS 4 +#define IPV6_2292RTHDR 5 +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_CHECKSUM 7 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_NEXTHOP 9 +#define IPV6_AUTHHDR 10 +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_ROUTER_ALERT 22 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_JOIN_ANYCAST 27 +#define IPV6_LEAVE_ANYCAST 28 +#define IPV6_MULTICAST_ALL 29 +#define IPV6_ROUTER_ALERT_ISOLATE 30 +#define IPV6_IPSEC_POLICY 34 +#define IPV6_XFRM_POLICY 35 +#define IPV6_HDRINCL 36 + +#define IN6ADDR_ANY_INIT \ + { \ + { \ + { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + } \ + } \ + } +#define IN6ADDR_LOOPBACK_INIT \ + { \ + { \ + { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \ + } \ + } \ + } + typedef uint16_t in_port_t; typedef uint32_t in_addr_t; @@ -79,4 +125,5 @@ struct sockaddr_in6 { struct in6_addr sin6_addr; uint32_t sin6_scope_id; }; -#endif + +#endif // _NETINET_IN_H diff --git a/ulib/axlibc/include/netinet/tcp.h b/ulib/axlibc/include/netinet/tcp.h index 6375b9dc59..dfe65d108e 100644 --- a/ulib/axlibc/include/netinet/tcp.h +++ b/ulib/axlibc/include/netinet/tcp.h @@ -38,4 +38,8 @@ #define TCP_INQ 36 #define TCP_TX_DELAY 37 -#endif \ No newline at end of file +#define TCP_REPAIR_ON 1 +#define TCP_REPAIR_OFF 0 +#define TCP_REPAIR_OFF_NO_WP -1 + +#endif // _NETINET_TCP_H diff --git a/ulib/axlibc/include/poll.h b/ulib/axlibc/include/poll.h new file mode 100644 index 0000000000..e5903f2491 --- /dev/null +++ b/ulib/axlibc/include/poll.h @@ -0,0 +1,21 @@ +#ifndef _POLL_H +#define _POLL_H + +struct pollfd { + int fd; + short events; + short revents; +}; + +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 + +typedef unsigned long nfds_t; + +int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout); + +#endif // _POLL_H diff --git a/ulib/axlibc/include/pthread.h b/ulib/axlibc/include/pthread.h index b7f3e5d801..eb686cc3d3 100644 --- a/ulib/axlibc/include/pthread.h +++ b/ulib/axlibc/include/pthread.h @@ -1,7 +1,6 @@ #ifndef _PTHREAD_H #define _PTHREAD_H -#include #include #include @@ -52,16 +51,33 @@ typedef void *pthread_t; _Noreturn void pthread_exit(void *); pthread_t pthread_self(void); + int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); int pthread_join(pthread_t t, void **res); int pthread_setcancelstate(int, int *); int pthread_setcanceltype(int, int *); +void pthread_testcancel(void); +int pthread_cancel(pthread_t); int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); int pthread_mutex_lock(pthread_mutex_t *); int pthread_mutex_unlock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); + +int pthread_setname_np(pthread_t, const char *); + +int pthread_cond_init(pthread_cond_t *__restrict__ __cond, + const pthread_condattr_t *__restrict__ __cond_attr); +int pthread_cond_signal(pthread_cond_t *__cond); +int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex); +int pthread_cond_broadcast(pthread_cond_t *); + +int pthread_attr_init(pthread_attr_t *__attr); +int pthread_attr_getstacksize(const pthread_attr_t *__restrict__ __attr, + size_t *__restrict__ __stacksize); +int pthread_attr_setstacksize(pthread_attr_t *__attr, size_t __stacksize); #endif // AX_CONFIG_MULTITASK diff --git a/ulib/axlibc/include/pwd.h b/ulib/axlibc/include/pwd.h new file mode 100644 index 0000000000..3548546197 --- /dev/null +++ b/ulib/axlibc/include/pwd.h @@ -0,0 +1,45 @@ +#ifndef _PWD_H +#define _PWD_H + +#include +#include +#include +#include + +#define NSCDVERSION 2 +#define GETPWBYNAME 0 +#define GETPWBYUID 1 +#define GETGRBYNAME 2 +#define GETGRBYGID 3 +#define GETINITGR 15 + +#define PWVERSION 0 +#define PWFOUND 1 +#define PWNAMELEN 2 +#define PWPASSWDLEN 3 +#define PWUID 4 +#define PWGID 5 +#define PWGECOSLEN 6 +#define PWDIRLEN 7 +#define PWSHELLLEN 8 +#define PW_LEN 9 + +#define REQVERSION 0 +#define REQTYPE 1 +#define REQKEYLEN 2 +#define REQ_LEN 3 + +struct passwd { + char *pw_name; + char *pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char *pw_gecos; + char *pw_dir; + char *pw_shell; +}; + +int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); +int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **); + +#endif // _PWD_H diff --git a/ulib/axlibc/include/regex.h b/ulib/axlibc/include/regex.h new file mode 100644 index 0000000000..50b382885d --- /dev/null +++ b/ulib/axlibc/include/regex.h @@ -0,0 +1,4 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#endif // _REGEX_H diff --git a/ulib/axlibc/include/sched.h b/ulib/axlibc/include/sched.h new file mode 100644 index 0000000000..ed201c5849 --- /dev/null +++ b/ulib/axlibc/include/sched.h @@ -0,0 +1,23 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include + +typedef struct cpu_set_t { + unsigned long __bits[128 / sizeof(long)]; +} cpu_set_t; + +#define __CPU_op_S(i, size, set, op) \ + ((i) / 8U >= (size) ? 0 \ + : (((unsigned long *)(set))[(i) / 8 / sizeof(long)] op( \ + 1UL << ((i) % (8 * sizeof(long)))))) + +#define CPU_SET_S(i, size, set) __CPU_op_S(i, size, set, |=) +#define CPU_ZERO_S(size, set) memset(set, 0, size) + +#define CPU_SET(i, set) CPU_SET_S(i, sizeof(cpu_set_t), set); +#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t), set) + +int sched_setaffinity(pid_t, size_t, const cpu_set_t *); + +#endif // _SCHED_H diff --git a/ulib/axlibc/include/signal.h b/ulib/axlibc/include/signal.h index 299faa1bce..52e21cee70 100644 --- a/ulib/axlibc/include/signal.h +++ b/ulib/axlibc/include/signal.h @@ -1,6 +1,7 @@ #ifndef _SIGNAL_H #define _SIGNAL_H +#include #include #include @@ -13,9 +14,6 @@ union sigval { typedef union sigval __sigval_t; -#define __SI_MAX_SIZE 128 -#define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof(int)) - 4) - #define SA_NOCLDSTOP 1 #define SA_NOCLDWAIT 2 #define SA_SIGINFO 4 @@ -167,5 +165,15 @@ struct sigaction { void (*signal(int, void (*)(int)))(int); int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict); +int sigemptyset(sigset_t *); +int raise(int); +int sigaddset(sigset_t *, int); +int pthread_sigmask(int, const sigset_t *__restrict, sigset_t *__restrict); + +int kill(pid_t, int); +#ifdef AX_CONFIG_MULTITASK +int pthread_kill(pthread_t t, int sig); #endif + +#endif // _SIGNAL_H diff --git a/ulib/axlibc/include/stdint.h b/ulib/axlibc/include/stdint.h index bcf7b8be73..3081bf0116 100644 --- a/ulib/axlibc/include/stdint.h +++ b/ulib/axlibc/include/stdint.h @@ -12,8 +12,27 @@ typedef long long int64_t; typedef unsigned long long uint64_t; typedef int64_t int_fast64_t; - typedef int64_t intmax_t; + +#define INT8_MIN (-1 - 0x7f) +#define INT16_MIN (-1 - 0x7fff) +#define INT32_MIN (-1 - 0x7fffffff) +#define INT64_MIN (-1 - 0x7fffffffffffffff) + +#define INT8_MAX (0x7f) +#define INT16_MAX (0x7fff) +#define INT32_MAX (0x7fffffff) +#define INT64_MAX (0x7fffffffffffffff) + +#define UINT8_MAX (0xff) +#define UINT16_MAX (0xffff) +#define UINT32_MAX (0xffffffffu) +#define UINT64_MAX (0xffffffffffffffffu) + +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX + /* * * Pointers and addresses are 32 bits long. * We use pointer types to represent addresses, @@ -27,4 +46,21 @@ typedef int32_t intptr_t; typedef uint32_t uintptr_t; #endif +typedef uint8_t uint_fast8_t; +typedef uint64_t uint_fast64_t; + +#if UINTPTR_MAX == UINT64_MAX +#define INT64_C(c) c##L +#define UINT64_C(c) c##UL +#define INTMAX_C(c) c##L +#define UINTMAX_C(c) c##UL +#else +#define INT64_C(c) c##LL +#define UINT64_C(c) c##ULL +#define INTMAX_C(c) c##LL +#define UINTMAX_C(c) c##ULL +#endif + +#define SIZE_MAX UINT64_MAX + #endif // __STDINT_H__ diff --git a/ulib/axlibc/include/stdlib.h b/ulib/axlibc/include/stdlib.h index c5707f67c9..db259ba66c 100644 --- a/ulib/axlibc/include/stdlib.h +++ b/ulib/axlibc/include/stdlib.h @@ -3,6 +3,16 @@ #include +#define RAND_MAX (0x7fffffff) + +#define WEXITSTATUS(s) (((s)&0xff00) >> 8) +#define WTERMSIG(s) ((s)&0x7f) +#define WIFEXITED(s) (!WTERMSIG(s)) +#define WIFSIGNALED(s) (((s)&0xffff) - 1U < 0xffu) + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + long long atoll(const char *nptr); float strtof(const char *__restrict, char **__restrict); @@ -15,6 +25,16 @@ unsigned long long strtoull(const char *nptr, char **endptr, int base); int rand(void); void srand(unsigned); +long random(void); +void srandom(unsigned int); + +#ifdef AX_CONFIG_FP_SIMD +float strtof(const char *__restrict, char **__restrict); +double strtod(const char *__restrict, char **__restrict); +long double strtold(const char *__restrict, char **__restrict); +#endif + +void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); void *malloc(size_t); void *calloc(size_t, size_t); @@ -30,4 +50,9 @@ int abs(int); long labs(long); long long llabs(long long); +int mkostemp(char *, int); +int setenv(const char *, const char *, int); +int unsetenv(const char *); +int system(const char *); + #endif //__STDLIB_H__ diff --git a/ulib/axlibc/include/strings.h b/ulib/axlibc/include/strings.h new file mode 100644 index 0000000000..3616bae19f --- /dev/null +++ b/ulib/axlibc/include/strings.h @@ -0,0 +1,4 @@ +#ifndef __STRINGS_H__ +#define __STRINGS_H__ + +#endif // __STRINGS_H__ diff --git a/ulib/axlibc/include/sys/file.h b/ulib/axlibc/include/sys/file.h new file mode 100644 index 0000000000..d5e15a67f7 --- /dev/null +++ b/ulib/axlibc/include/sys/file.h @@ -0,0 +1,23 @@ +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#define L_SET 0 +#define L_INCR 1 +#define L_XTND 2 + +int flock(int, int); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_FILE_H diff --git a/ulib/axlibc/include/sys/ioctl.h b/ulib/axlibc/include/sys/ioctl.h index 4c1f53a3c5..e43c510131 100644 --- a/ulib/axlibc/include/sys/ioctl.h +++ b/ulib/axlibc/include/sys/ioctl.h @@ -1,4 +1,65 @@ -#ifdef __SYS_IOCTL_H__ +#ifndef __SYS_IOCTL_H__ #define __SYS_IOCTL_H__ -#endif +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN 0x80045430 +#define TIOCSPTLCK 0x40045431 +#define TIOCGDEV 0x80045432 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x40045436 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 0x80045438 +#define TIOCGPTLCK 0x80045439 +#define TIOCGEXCL 0x80045440 +#define TIOCGPTPEER 0x5441 +#define TIOCGISO7816 0x80285442 +#define TIOCSISO7816 0xc0285443 + +int ioctl(int, int, ...); + +#endif // __SYS_IOCTL_H__ diff --git a/ulib/axlibc/include/sys/mman.h b/ulib/axlibc/include/sys/mman.h index 0ba591d4f7..3d35023450 100644 --- a/ulib/axlibc/include/sys/mman.h +++ b/ulib/axlibc/include/sys/mman.h @@ -46,5 +46,7 @@ void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); int munmap(void *addr, size_t length); void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, ... /* void *new_address */); +int mprotect(void *addr, size_t len, int prot); +int madvise(void *addr, size_t length, int advice); #endif diff --git a/ulib/axlibc/include/sys/param.h b/ulib/axlibc/include/sys/param.h new file mode 100644 index 0000000000..bbb762f542 --- /dev/null +++ b/ulib/axlibc/include/sys/param.h @@ -0,0 +1,6 @@ +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#define MAXPATHLEN 4096 + +#endif // _SYS_PARAM_H diff --git a/ulib/axlibc/include/sys/prctl.h b/ulib/axlibc/include/sys/prctl.h new file mode 100644 index 0000000000..1ed9cc10ed --- /dev/null +++ b/ulib/axlibc/include/sys/prctl.h @@ -0,0 +1,4 @@ +#ifndef _SYS_PRCTL_H +#define _SYS_PRCTL_H + +#endif // _SYS_PRCTL_H diff --git a/ulib/axlibc/include/sys/types.h b/ulib/axlibc/include/sys/types.h index 3624d27031..adb6c3531b 100644 --- a/ulib/axlibc/include/sys/types.h +++ b/ulib/axlibc/include/sys/types.h @@ -1,7 +1,7 @@ #ifndef __SYS_TYPES_H__ #define __SYS_TYPES_H__ -#include +#include typedef unsigned char u_char; diff --git a/ulib/axlibc/include/sys/un.h b/ulib/axlibc/include/sys/un.h new file mode 100644 index 0000000000..85e43ea7b3 --- /dev/null +++ b/ulib/axlibc/include/sys/un.h @@ -0,0 +1,11 @@ +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#include + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +#endif // _SYS_UN_H diff --git a/ulib/axlibc/include/termios.h b/ulib/axlibc/include/termios.h new file mode 100644 index 0000000000..d319c5b811 --- /dev/null +++ b/ulib/axlibc/include/termios.h @@ -0,0 +1,8 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +struct winsize { + unsigned short ws_row, ws_col, ws_xpixel, ws_ypixel; +}; + +#endif // _TERMIOS_H diff --git a/ulib/axlibc/src/file.rs b/ulib/axlibc/src/file.rs index f3898bf6ff..26ed7a6abb 100644 --- a/ulib/axlibc/src/file.rs +++ b/ulib/axlibc/src/file.rs @@ -192,3 +192,18 @@ pub unsafe extern "C" fn ax_getcwd(buf: *mut c_char, size: usize) -> *mut c_char } }) } + +/// 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 ax_rename(old: *const c_char, new: *const c_char) -> c_int { + ax_call_body!(ax_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)?; + Ok(0) + }) +} diff --git a/ulib/axlibc/src/lib.rs b/ulib/axlibc/src/lib.rs index 952dc002a8..b2aadf429a 100644 --- a/ulib/axlibc/src/lib.rs +++ b/ulib/axlibc/src/lib.rs @@ -49,12 +49,15 @@ mod pipe; 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 mktime; mod rand; mod setjmp; mod stdio; @@ -77,6 +80,8 @@ pub use self::rand::{ax_rand_u32, ax_srand}; #[cfg(feature = "alloc")] pub use self::malloc::{ax_free, ax_malloc}; +#[cfg(feature = "alloc")] +pub use self::strftime::ax_strftime; #[cfg(feature = "fd")] pub use self::fd_ops::{ax_close, ax_dup, ax_dup3, ax_fcntl, ax_fstat, ax_read, ax_write}; @@ -112,6 +117,7 @@ pub use self::io_mpx::{ax_epoll_create, ax_epoll_ctl, ax_epoll_wait}; 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}; diff --git a/ulib/axlibc/src/mktime.rs b/ulib/axlibc/src/mktime.rs new file mode 100644 index 0000000000..3f86a064ee --- /dev/null +++ b/ulib/axlibc/src/mktime.rs @@ -0,0 +1,58 @@ +use core::ffi::c_int; + +use crate::ctypes; + +const MONTH_DAYS: [[c_int; 12]; 2] = [ + // Non-leap years: + [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + // Leap years: + [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], +]; + +#[inline(always)] +fn leap_year(year: c_int) -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) +} + +/// `mktime` implementation +#[no_mangle] +pub unsafe extern "C" fn ax_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; + + let leap = if leap_year(year) { 1 } else { 0 }; + + if year < 1970 { + day = MONTH_DAYS[if leap_year(year) { 1 } else { 0 }][(*t).tm_mon as usize] as i64 - day; + + while year < 1969 { + year += 1; + day += if leap_year(year) { 366 } else { 365 }; + } + + while month < 11 { + month += 1; + day += MONTH_DAYS[leap][month as usize] as i64; + } + + (-(day * (60 * 60 * 24) + - (((*t).tm_hour as i64) * (60 * 60) + ((*t).tm_min as i64) * 60 + (*t).tm_sec as i64))) + as ctypes::time_t + } else { + while year > 1970 { + year -= 1; + day += if leap_year(year) { 366 } else { 365 }; + } + + while month > 0 { + month -= 1; + day += MONTH_DAYS[leap][month as usize] as i64; + } + + (day * (60 * 60 * 24) + + ((*t).tm_hour as i64) * (60 * 60) + + ((*t).tm_min as i64) * 60 + + (*t).tm_sec as i64) as ctypes::time_t + } +} diff --git a/ulib/axlibc/src/strftime.rs b/ulib/axlibc/src/strftime.rs new file mode 100644 index 0000000000..eec3643f9f --- /dev/null +++ b/ulib/axlibc/src/strftime.rs @@ -0,0 +1,253 @@ +use alloc::string::String; +use core::{ffi::c_char, fmt}; + +use axio::Write; + +use crate::ctypes; + +pub trait WriteByte: fmt::Write { + fn write_u8(&mut self, byte: u8) -> fmt::Result; +} + +struct StringWriter(pub *mut u8, pub usize); +impl Write for StringWriter { + fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { + if self.1 > 1 { + let copy_size = buf.len().min(self.1 - 1); + unsafe { + core::ptr::copy_nonoverlapping(buf.as_ptr(), self.0, copy_size); + self.1 -= copy_size; + + self.0 = self.0.add(copy_size); + *self.0 = 0; + } + } + Ok(buf.len()) + } + fn flush(&mut self) -> axerrno::AxResult { + Ok(()) + } +} + +impl fmt::Write for StringWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + // can't fail + self.write(s.as_bytes()).unwrap(); + Ok(()) + } +} + +impl WriteByte for StringWriter { + fn write_u8(&mut self, byte: u8) -> fmt::Result { + // can't fail + self.write(&[byte]).unwrap(); + Ok(()) + } +} + +struct CountingWriter { + pub inner: T, + pub written: usize, +} + +impl CountingWriter { + pub fn new(writer: T) -> Self { + Self { + inner: writer, + written: 0, + } + } +} + +impl fmt::Write for CountingWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.written += s.len(); + self.inner.write_str(s) + } +} + +impl WriteByte for CountingWriter { + fn write_u8(&mut self, byte: u8) -> fmt::Result { + self.written += 1; + self.inner.write_u8(byte) + } +} + +impl Write for CountingWriter { + fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { + let res = self.inner.write(buf); + if let Ok(written) = res { + self.written += written; + } + res + } + + fn write_all(&mut self, buf: &[u8]) -> axerrno::AxResult { + match self.inner.write_all(buf) { + Ok(()) => (), + Err(err) => return Err(err), + } + self.written += buf.len(); + Ok(()) + } + + fn flush(&mut self) -> axerrno::AxResult { + self.inner.flush() + } +} + +unsafe fn strftime( + w: W, + format: *const c_char, + t: *const ctypes::tm, +) -> ctypes::size_t { + pub unsafe fn inner_strftime( + w: &mut W, + mut format: *const c_char, + t: *const ctypes::tm, + ) -> bool { + macro_rules! w { + (byte $b:expr) => {{ + if w.write_u8($b).is_err() { + return false; + } + }}; + (char $chr:expr) => {{ + if w.write_char($chr).is_err() { + return false; + } + }}; + (recurse $fmt:expr) => {{ + let mut fmt = String::with_capacity($fmt.len() + 1); + fmt.push_str($fmt); + fmt.push('\0'); + + if !inner_strftime(w, fmt.as_ptr() as *mut c_char, t) { + return false; + } + }}; + ($str:expr) => {{ + if w.write_str($str).is_err() { + return false; + } + }}; + ($fmt:expr, $($args:expr),+) => {{ + // Would use write!() if I could get the length written + if write!(w, $fmt, $($args),+).is_err() { + return false; + } + }}; + } + const WDAYS: [&str; 7] = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + ]; + const MONTHS: [&str; 12] = [ + "January", + "Febuary", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + + while *format != 0 { + if *format as u8 != b'%' { + w!(byte * format as u8); + format = format.offset(1); + continue; + } + + format = format.offset(1); + + if *format as u8 == b'E' || *format as u8 == b'O' { + // Ignore because these do nothing without locale + format = format.offset(1); + } + + match *format as u8 { + b'%' => w!(byte b'%'), + b'n' => w!(byte b'\n'), + b't' => w!(byte b'\t'), + b'a' => w!(&WDAYS[(*t).tm_wday as usize][..3]), + b'A' => w!(WDAYS[(*t).tm_wday as usize]), + b'b' | b'h' => w!(&MONTHS[(*t).tm_mon as usize][..3]), + b'B' => w!(MONTHS[(*t).tm_mon as usize]), + b'C' => { + let mut year = (*t).tm_year / 100; + // Round up + if (*t).tm_year % 100 != 0 { + year += 1; + } + w!("{:02}", year + 19); + } + b'd' => w!("{:02}", (*t).tm_mday), + b'D' => w!(recurse "%m/%d/%y"), + b'e' => w!("{:2}", (*t).tm_mday), + b'F' => w!(recurse "%Y-%m-%d"), + b'H' => w!("{:02}", (*t).tm_hour), + b'I' => w!("{:02}", ((*t).tm_hour + 12 - 1) % 12 + 1), + b'j' => w!("{:03}", (*t).tm_yday), + b'k' => w!("{:2}", (*t).tm_hour), + b'l' => w!("{:2}", ((*t).tm_hour + 12 - 1) % 12 + 1), + b'm' => w!("{:02}", (*t).tm_mon + 1), + b'M' => w!("{:02}", (*t).tm_min), + b'p' => w!(if (*t).tm_hour < 12 { "AM" } else { "PM" }), + b'P' => w!(if (*t).tm_hour < 12 { "am" } else { "pm" }), + 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!("{:02}", (*t).tm_sec), + b'T' => w!(recurse "%H:%M:%S"), + b'u' => w!("{}", ((*t).tm_wday + 7 - 1) % 7 + 1), + b'U' => w!("{}", ((*t).tm_yday + 7 - (*t).tm_wday) / 7), + b'w' => w!("{}", (*t).tm_wday), + b'W' => w!("{}", ((*t).tm_yday + 7 - ((*t).tm_wday + 6) % 7) / 7), + b'y' => w!("{:02}", (*t).tm_year % 100), + b'Y' => w!("{}", (*t).tm_year + 1900), + b'z' => w!("+0000"), // TODO + b'Z' => w!("UTC"), // TODO + b'+' => w!(recurse "%a %b %d %T %Z %Y"), + _ => return false, + } + + format = format.offset(1); + } + true + } + + let mut w: CountingWriter = CountingWriter::new(w); + if !inner_strftime(&mut w, format, t) { + return 0; + } + + w.written +} + +/// `strftime` implementation +#[no_mangle] +pub unsafe extern "C" fn ax_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); + if ret < size { + ret + } else { + 0 + } +} diff --git a/ulib/axstd/src/fs.rs b/ulib/axstd/src/fs.rs index 67760fad46..92e8068a2f 100644 --- a/ulib/axstd/src/fs.rs +++ b/ulib/axstd/src/fs.rs @@ -1,5 +1,5 @@ //! Filesystem manipulation operations. pub use axfs::api::{canonicalize, metadata, read, read_to_string, remove_file, write}; -pub use axfs::api::{create_dir, create_dir_all, read_dir, remove_dir}; +pub use axfs::api::{create_dir, create_dir_all, read_dir, remove_dir, rename}; pub use axfs::api::{DirEntry, File, FileType, Metadata, OpenOptions, Permissions, ReadDir};