diff --git a/examples/getcpucount.c b/examples/getcpucount.c index 66184743a..4efb385ee 100644 --- a/examples/getcpucount.c +++ b/examples/getcpucount.c @@ -7,9 +7,26 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/fmt/itoa.h" #include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" + +// this implementation uses cosmopolitan specific apis so that the +// resulting program will be 28kb in size. the proper way to do it +// though is use sysconf(_SC_NPROCESSORS_ONLN), which is humongous int main() { - kprintf("%d\n", _getcpucount()); + int count; + if ((count = __get_cpu_count()) != -1) { + char ibuf[12]; + FormatInt32(ibuf, count); + tinyprint(1, ibuf, "\n", NULL); + return 0; + } else { + perror("__get_cpu_count"); + return 1; + } } diff --git a/examples/greenbean.c b/examples/greenbean.c index a66f84e36..fd3c44abd 100644 --- a/examples/greenbean.c +++ b/examples/greenbean.c @@ -298,7 +298,7 @@ int main(int argc, char *argv[]) { PORT); } - threads = argc > 1 ? atoi(argv[1]) : _getcpucount(); + threads = argc > 1 ? atoi(argv[1]) : __get_cpu_count(); if (!(1 <= threads && threads <= 100000)) { kprintf("error: invalid number of threads: %d\n", threads); exit(1); diff --git a/examples/sysconf.c b/examples/sysconf.c new file mode 100644 index 000000000..937c4b231 --- /dev/null +++ b/examples/sysconf.c @@ -0,0 +1,25 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/runtime/sysconf.h" +#include "libc/stdio/stdio.h" + +#define SYSCONF(NAME) printf("%s %,ld\n", #NAME, sysconf(NAME)) + +int main(int argc, char *argv[]) { + SYSCONF(_SC_CLK_TCK); + SYSCONF(_SC_PAGESIZE); + SYSCONF(_SC_ARG_MAX); + SYSCONF(_SC_CHILD_MAX); + SYSCONF(_SC_OPEN_MAX); + SYSCONF(_SC_NPROCESSORS_CONF); + SYSCONF(_SC_NPROCESSORS_ONLN); + SYSCONF(_SC_PHYS_PAGES); + SYSCONF(_SC_AVPHYS_PAGES); +} diff --git a/libc/calls/calls.h b/libc/calls/calls.h index fcc10416a..9fa9f03ce 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -24,6 +24,7 @@ #define _POSIX_SEMAPHORES _POSIX_VERSION #define _POSIX_SHARED_MEMORY_OBJECTS _POSIX_VERSION #define _POSIX_MEMLOCK_RANGE _POSIX_VERSION +#define _POSIX_SPAWN _POSIX_VERSION #define EOF -1 /* end of file */ #define WEOF -1u /* end of file (multibyte) */ diff --git a/libc/calls/fchmod.c b/libc/calls/fchmod.c index 27996c8fb..092a8e57c 100644 --- a/libc/calls/fchmod.c +++ b/libc/calls/fchmod.c @@ -29,6 +29,6 @@ * @see chmod() */ int fchmod(int fd, uint32_t mode) { - /* TODO(jart): Windows */ + // TODO(jart): Windows return sys_fchmod(fd, mode); } diff --git a/libc/calls/fchmodat.c b/libc/calls/fchmodat.c index 7090a9f11..8e35e5c37 100644 --- a/libc/calls/fchmodat.c +++ b/libc/calls/fchmodat.c @@ -24,8 +24,8 @@ #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" -#include "libc/sysv/errfuns.h" #include "libc/runtime/zipos.internal.h" +#include "libc/sysv/errfuns.h" int sys_fchmodat_linux(int, const char *, unsigned, int); @@ -39,7 +39,7 @@ int sys_fchmodat_linux(int, const char *, unsigned, int); * @param path must exist * @param mode contains octal flags (base 8) * @param flags can have `AT_SYMLINK_NOFOLLOW` - * @raise ENOTSUP if `dirfd` or `path` use zip file system + * @raise EROFS if `dirfd` or `path` use zip file system * @errors ENOENT, ENOTDIR, ENOSYS * @asyncsignalsafe * @see fchmod() @@ -50,7 +50,7 @@ int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) { rc = efault(); } else if (_weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { - rc = enotsup(); + rc = erofs(); } else if (!IsWindows()) { if (IsLinux() && flags) { rc = sys_fchmodat_linux(dirfd, path, mode, flags); diff --git a/libc/calls/fchownat.c b/libc/calls/fchownat.c index ee9951637..e1648da42 100644 --- a/libc/calls/fchownat.c +++ b/libc/calls/fchownat.c @@ -23,8 +23,8 @@ #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" -#include "libc/sysv/errfuns.h" #include "libc/runtime/zipos.internal.h" +#include "libc/sysv/errfuns.h" /** * Changes owner and/or group of path. @@ -34,7 +34,7 @@ * @param gid is group id, or -1 to not change * @param flags can have AT_SYMLINK_NOFOLLOW, etc. * @return 0 on success, or -1 w/ errno - * @raise ENOTSUP if `dirfd` or `path` use zip file system + * @raise EROFS if `dirfd` or `path` use zip file system * @see chown(), lchown() for shorthand notation * @see /etc/passwd for user ids * @see /etc/group for group ids @@ -47,7 +47,7 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid, rc = efault(); } else if (_weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { - rc = enotsup(); + rc = erofs(); } else { rc = sys_fchownat(dirfd, path, uid, gid, flags); } diff --git a/libc/calls/ftruncate.c b/libc/calls/ftruncate.c index a8cb392fa..4f7ef83c7 100644 --- a/libc/calls/ftruncate.c +++ b/libc/calls/ftruncate.c @@ -53,10 +53,10 @@ * @raise ECANCELED if thread was cancelled in masked mode * @raise EIO if a low-level i/o error happened * @raise EFBIG or EINVAL if `length` is too huge - * @raise ENOTSUP if `fd` is a zip file descriptor * @raise EBADF if `fd` isn't an open file descriptor * @raise EINVAL if `fd` is a non-file, e.g. pipe, socket * @raise EINVAL if `fd` wasn't opened in a writeable mode + * @raise EROFS if `fd` is on a read-only filesystem (e.g. zipos) * @raise ENOSYS on bare metal * @cancellationpoint * @asyncsignalsafe @@ -69,7 +69,7 @@ int ftruncate(int fd, int64_t length) { if (fd < 0) { rc = ebadf(); } else if (__isfdkind(fd, kFdZip)) { - rc = enotsup(); + rc = erofs(); } else if (IsMetal()) { rc = enosys(); } else if (!IsWindows()) { diff --git a/libc/calls/futimens.c b/libc/calls/futimens.c index d53957468..c25e37dc8 100644 --- a/libc/calls/futimens.c +++ b/libc/calls/futimens.c @@ -32,10 +32,10 @@ * @param fd is file descriptor of file whose timestamps will change * @param ts is {access, modified} timestamps, or null for current time * @return 0 on success, or -1 w/ errno - * @raise ENOTSUP if `fd` is on the zip filesystem * @raise EINVAL if `flags` had an unrecognized value * @raise EPERM if pledge() is in play without `fattr` promise * @raise EINVAL if `ts` specifies a nanosecond value that's out of range + * @raise EROFS if `fd` is a zip file or on a read-only filesystem * @raise EBADF if `fd` isn't an open file descriptor * @raise EFAULT if `ts` memory was invalid * @raise ENOSYS on RHEL5 or bare metal diff --git a/libc/calls/futimes.c b/libc/calls/futimes.c index bb0436617..900ec18f0 100644 --- a/libc/calls/futimes.c +++ b/libc/calls/futimes.c @@ -30,8 +30,8 @@ * * @param ts is atime/mtime, or null for current time * @return 0 on success, or -1 w/ errno - * @raise ENOTSUP if `fd` is on zip filesystem * @raise EBADF if `fd` isn't an open file descriptor + * @raise EROFS if `fd` is on zip or read-only filesystem * @raise EPERM if pledge() is in play without `fattr` promise * @raise EINVAL if `tv` specifies a microsecond value that's out of range * @raise ENOSYS on RHEL5 or bare metal diff --git a/libc/calls/getcpucount.c b/libc/calls/getcpucount.c index f1433d7f8..ab846a091 100644 --- a/libc/calls/getcpucount.c +++ b/libc/calls/getcpucount.c @@ -19,13 +19,9 @@ #include "libc/calls/calls.h" #include "libc/calls/sched-sysv.internal.h" #include "libc/calls/struct/cpuset.h" -#include "libc/calls/weirdtypes.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" -#include "libc/macros.internal.h" #include "libc/nt/accounting.h" -#include "libc/nt/dll.h" -#include "libc/nt/struct/systeminfo.h" -#include "libc/nt/systeminfo.h" #include "libc/runtime/runtime.h" #define CTL_HW 6 @@ -34,16 +30,16 @@ #define HW_NCPUONLINE_NETBSD 16 #define ALL_PROCESSOR_GROUPS 0xffff -static unsigned _getcpucount_linux(void) { - cpu_set_t s = {0}; - if (sys_sched_getaffinity(0, sizeof(s), &s) != -1) { - return CPU_COUNT(&s); +static int __get_cpu_count_linux(void) { + cpu_set_t cs = {0}; + if (sys_sched_getaffinity(0, sizeof(cs), &cs) != -1) { + return CPU_COUNT(&cs); } else { - return 0; + return -1; } } -static unsigned _getcpucount_bsd(void) { +static int __get_cpu_count_bsd(void) { size_t n; int c, cmd[2]; n = sizeof(c); @@ -58,29 +54,19 @@ static unsigned _getcpucount_bsd(void) { if (!sys_sysctl(cmd, 2, &c, &n, 0, 0)) { return c; } else { - return 0; + return -1; } } -static unsigned _getcpucount_impl(void) { - if (!IsWindows()) { - if (!IsBsd()) { - return _getcpucount_linux(); - } else { - return _getcpucount_bsd(); - } +static textwindows int __get_cpu_count_nt(void) { + uint32_t res; + if ((res = GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS))) { + return res; } else { - return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS); + return __winerr(); } } -static int g_cpucount; - -// precompute because process affinity on linux may change later -__attribute__((__constructor__)) static void _getcpucount_init(void) { - g_cpucount = _getcpucount_impl(); -} - /** * Returns number of CPUs in system. * @@ -88,13 +74,20 @@ __attribute__((__constructor__)) static void _getcpucount_init(void) { * * sysconf(_SC_NPROCESSORS_ONLN); * - * Except this function isn't a bloated diamond dependency. - * * On Intel systems with HyperThreading this will return the number of - * cores multiplied by two. + * cores multiplied by two. On Linux, if you change cpu affinity it'll + * change the cpu count, which also gets inherited by child processes. * - * @return cpu count or 0 if it couldn't be determined + * @return cpu count, or -1 w/ errno */ -int _getcpucount(void) { - return g_cpucount; +int __get_cpu_count(void) { + if (!IsWindows()) { + if (!IsBsd()) { + return __get_cpu_count_linux(); + } else { + return __get_cpu_count_bsd(); + } + } else { + return __get_cpu_count_nt(); + } } diff --git a/libc/calls/getloadavg-nt.c b/libc/calls/getloadavg-nt.c index d8325576a..65fda675a 100644 --- a/libc/calls/getloadavg-nt.c +++ b/libc/calls/getloadavg-nt.c @@ -60,7 +60,7 @@ static textstartup void sys_getloadavg_nt_init(void) { double a[3]; if (IsWindows()) { load = 1; - cpus = _getcpucount() / 2; + cpus = __get_cpu_count() / 2; cpus = MAX(1, cpus); GetSystemTimes(&idle1, &kern1, &user1); } diff --git a/libc/calls/getloadavg.c b/libc/calls/getloadavg.c index 1608effd4..17f260008 100644 --- a/libc/calls/getloadavg.c +++ b/libc/calls/getloadavg.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/struct/sysinfo.h" +#include "libc/calls/struct/sysinfo.internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/strace.internal.h" @@ -40,7 +41,7 @@ struct loadavg { * @raise ENOSYS on metal */ int getloadavg(double *a, int n) { - /* cat /proc/loadavg */ + // cat /proc/loadavg int i, rc; if (n > 3) n = 3; if (!n) { @@ -51,7 +52,7 @@ int getloadavg(double *a, int n) { return sys_getloadavg_nt(a, n); } else if (IsLinux()) { struct sysinfo si; - if ((rc = sysinfo(&si)) != -1) { + if ((rc = sys_sysinfo(&si)) != -1) { for (i = 0; i < n; i++) { a[i] = 1. / 65536 * si.loads[i]; } diff --git a/libc/calls/getsid.c b/libc/calls/getsid.c index 510dbce55..72f70426f 100644 --- a/libc/calls/getsid.c +++ b/libc/calls/getsid.c @@ -24,8 +24,7 @@ * Creates session and sets the process group id. */ int getsid(int pid) { - int rc; - rc = sys_getsid(pid); + int rc = sys_getsid(pid); STRACE("%s(%d) → %d% m", "getsid", pid, rc); return rc; } diff --git a/libc/calls/grantpt.c b/libc/calls/grantpt.c index c1bb1d495..b4f27f576 100644 --- a/libc/calls/grantpt.c +++ b/libc/calls/grantpt.c @@ -16,11 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/struct/fd.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/dce.h" #include "libc/intrin/strace.internal.h" +#include "libc/sysv/errfuns.h" #define TIOCPTYGRANT 0x20007454 @@ -34,7 +37,9 @@ */ int grantpt(int fd) { int rc; - if (IsXnu()) { + if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { + rc = enotty(); + } else if (IsXnu()) { rc = sys_ioctl(fd, TIOCPTYGRANT); } else { rc = _isptmaster(fd); diff --git a/libc/calls/nanos.internal.h b/libc/calls/nanos.internal.h deleted file mode 100644 index 547557290..000000000 --- a/libc/calls/nanos.internal.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_CALLS_NANOS_H_ -#define COSMOPOLITAN_LIBC_CALLS_NANOS_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -int128_t _nanos(int); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_CALLS_NANOS_H_ */ diff --git a/libc/calls/pipe2.c b/libc/calls/pipe2.c index 8b05aa0a4..2cfcc625c 100644 --- a/libc/calls/pipe2.c +++ b/libc/calls/pipe2.c @@ -27,6 +27,12 @@ /** * Creates file-less file descriptors for interprocess communication. * + * This function offers atomic operation on all supported platforms + * except for XNU and RHEL5 where it's polyfilled. + * + * @params flags may contain `O_CLOEXEC`, `O_NONBLOCK`, and `O_DIRECT` + * @raise EINVAL if flags has invalid or unsupported bits + * @raise EFAULT if `pipefd` doesn't point to valid memory * @raise EMFILE if process `RLIMIT_NOFILE` has been reached * @raise ENFILE if system-wide file limit has been reached * @param pipefd is used to return (reader, writer) file descriptors diff --git a/libc/calls/ptsname.c b/libc/calls/ptsname.c index 5102b6f4a..8532af1c9 100644 --- a/libc/calls/ptsname.c +++ b/libc/calls/ptsname.c @@ -16,10 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/struct/fd.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/errno.h" #include "libc/intrin/strace.internal.h" +#include "libc/sysv/errfuns.h" static char g_ptsname[16]; @@ -30,7 +33,10 @@ static char g_ptsname[16]; */ char *ptsname(int fd) { char *res; - if (!_ptsname(fd, g_ptsname, sizeof(g_ptsname))) { + if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { + enotty(); + res = 0; + } else if (!_ptsname(fd, g_ptsname, sizeof(g_ptsname))) { res = g_ptsname; } else { res = 0; diff --git a/libc/calls/sysinfo.c b/libc/calls/sysinfo.c index f0a1138d3..245dc161a 100644 --- a/libc/calls/sysinfo.c +++ b/libc/calls/sysinfo.c @@ -53,6 +53,8 @@ static int64_t GetPhysmem(void) { static int sys_sysinfo_bsd(struct sysinfo *info) { info->uptime = GetUptime(); info->totalram = GetPhysmem(); + info->bufferram = GetPhysmem(); + info->mem_unit = 1; return 0; } diff --git a/libc/calls/truncate.c b/libc/calls/truncate.c index 796fafbfc..ebd252c2c 100644 --- a/libc/calls/truncate.c +++ b/libc/calls/truncate.c @@ -25,8 +25,8 @@ #include "libc/intrin/asan.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" -#include "libc/sysv/errfuns.h" #include "libc/runtime/zipos.internal.h" +#include "libc/sysv/errfuns.h" /** * Changes size of file. @@ -50,15 +50,14 @@ * @raise ECANCELED if thread was cancelled in masked mode * @raise EFBIG or EINVAL if `length` is too huge * @raise EFAULT if `path` points to invalid memory - * @raise ENOTSUP if `path` is a zip filesystem path * @raise EACCES if we don't have permission to search a component of `path` * @raise ENOTDIR if a directory component in `path` exists as non-directory * @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX` * @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX` * @raise ELOOP if a loop was detected resolving components of `path` + * @raise EROFS if `path` is on a read-only filesystem (e.g. zip) * @raise ENOENT if `path` doesn't exist or is an empty string * @raise ETXTBSY if `path` is an executable being executed - * @raise EROFS if `path` is on a read-only filesystem * @raise ENOSYS on bare metal * @cancellationpoint * @see ftruncate() @@ -75,7 +74,7 @@ int truncate(const char *path, int64_t length) { rc = efault(); } else if (_weaken(__zipos_parseuri) && _weaken(__zipos_parseuri)(path, &zipname) != -1) { - rc = enotsup(); + rc = erofs(); } else if (!IsWindows()) { rc = sys_truncate(path, length, length); if (IsNetbsd() && rc == -1 && errno == ENOSPC) { diff --git a/libc/calls/unlockpt.c b/libc/calls/unlockpt.c index bbeed8ddf..5d45ebe09 100644 --- a/libc/calls/unlockpt.c +++ b/libc/calls/unlockpt.c @@ -17,6 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/fd.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/termios.h" @@ -37,7 +39,9 @@ */ int unlockpt(int fd) { int rc, unlock = 0; - if (IsFreebsd() || IsOpenbsd() || IsNetbsd()) { + if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { + rc = enotty(); + } else if (IsFreebsd() || IsOpenbsd() || IsNetbsd()) { rc = _isptmaster(fd); } else if (IsXnu()) { rc = sys_ioctl(fd, TIOCPTYUNLK); diff --git a/libc/calls/utimens.c b/libc/calls/utimens.c index 7f00c8f54..b37c6f147 100644 --- a/libc/calls/utimens.c +++ b/libc/calls/utimens.c @@ -28,9 +28,9 @@ #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" +#include "libc/runtime/zipos.internal.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/errfuns.h" -#include "libc/runtime/zipos.internal.h" int __utimens(int fd, const char *path, const struct timespec ts[2], int flags) { @@ -47,7 +47,7 @@ int __utimens(int fd, const char *path, const struct timespec ts[2], } else if (__isfdkind(fd, kFdZip) || (path && (_weaken(__zipos_parseuri) && _weaken(__zipos_parseuri)(path, &zipname) != -1))) { - rc = enotsup(); + rc = erofs(); } else if (IsLinux() && !__is_linux_2_6_23() && fd == AT_FDCWD && !flags) { rc = sys_utimes(path, (void *)ts); // rhel5 truncates to seconds } else if (!IsWindows()) { diff --git a/libc/calls/utimensat.c b/libc/calls/utimensat.c index b97d3ce6e..318fe447f 100644 --- a/libc/calls/utimensat.c +++ b/libc/calls/utimensat.c @@ -25,9 +25,9 @@ #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" +#include "libc/runtime/zipos.internal.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/errfuns.h" -#include "libc/runtime/zipos.internal.h" /** * Sets access/modified time on file, the modern way. @@ -48,13 +48,12 @@ * @raise EINVAL if `flags` had an unrecognized value * @raise EPERM if pledge() is in play without `fattr` promise * @raise EACCES if unveil() is in play and `path` isn't unveiled - * @raise ENOTSUP if `path` is a zip filesystem path or `dirfd` is zip * @raise EINVAL if `ts` specifies a nanosecond value that's out of range * @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX` * @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX` * @raise EBADF if `dirfd` isn't a valid fd or `AT_FDCWD` * @raise EFAULT if `path` or `ts` memory was invalid - * @raise EROFS if `path` is on read-only filesystem + * @raise EROFS if `path` is on read-only filesystem (e.g. zipos) * @raise ENOSYS on bare metal or on rhel5 when `dirfd` or `flags` is used * @asyncsignalsafe * @threadsafe diff --git a/libc/intrin/divmodti4.c b/libc/intrin/divmodti4.c index eb572e555..465555c27 100644 --- a/libc/intrin/divmodti4.c +++ b/libc/intrin/divmodti4.c @@ -18,7 +18,7 @@ * @return quotient or result of division * @note rounds towards zero */ -COMPILER_RT_ABI ti_int __divmodti4(ti_int a, ti_int b, tu_int *opt_out_rem) { +ti_int __divmodti4(ti_int a, ti_int b, tu_int *opt_out_rem) { int k; tu_int r; ti_int sa, sb, sq, sr, x, y, q; diff --git a/libc/intrin/divti3.c b/libc/intrin/divti3.c index b2bbc7aaa..f878fab4b 100644 --- a/libc/intrin/divti3.c +++ b/libc/intrin/divti3.c @@ -17,6 +17,6 @@ * @return quotient or result of division * @note rounds towards zero */ -COMPILER_RT_ABI ti_int __divti3(ti_int a, ti_int b) { +ti_int __divti3(ti_int a, ti_int b) { return __divmodti4(a, b, NULL); } diff --git a/libc/mem/critbit0_clear.c b/libc/mem/critbit0_clear.c index 714dbe8ad..79e598756 100644 --- a/libc/mem/critbit0_clear.c +++ b/libc/mem/critbit0_clear.c @@ -26,9 +26,9 @@ static void critbit0_clear_traverse(void *top) { struct CritbitNode *q = (void *)(p - 1); critbit0_clear_traverse(q->child[0]); critbit0_clear_traverse(q->child[1]); - free(q), q = NULL; + free(q); } else { - free(p), p = NULL; + free(p); } } diff --git a/libc/runtime/cocmd.c b/libc/runtime/cocmd.c index e4e1f3ded..ca47e5282 100644 --- a/libc/runtime/cocmd.c +++ b/libc/runtime/cocmd.c @@ -218,64 +218,69 @@ static const char *GetOptArg(int c, int *i, int j) { static int Echo(void) { int i = 1; bool once = false; - const char *l = " "; - if (i < n && !strcmp(args[i], "-l")) { - ++i, l = "\n"; + bool print_newline = true; + if (i < n && args[i][0] == '-' && args[i][1] == 'n' && !args[i][2]) { + ++i, print_newline = false; } for (; i < n; ++i) { if (once) { - Write(1, l); + Write(1, " "); } else { once = true; } Write(1, args[i]); } - Write(1, "\n"); + if (print_newline) { + Write(1, "\n"); + } + return 0; +} + +static int CatDump(const char *path, int fd, bool dontclose) { + ssize_t rc; + char buf[512]; + for (;;) { + rc = read(fd, buf, sizeof(buf)); + if (rc == -1) { + perror(path); + if (!dontclose) { + close(fd); + } + return 1; + } + if (!rc) break; + rc = write(1, buf, rc); + if (rc == -1) { + perror("write"); + if (!dontclose) { + close(fd); + } + return 1; + } + } + if (!dontclose && close(fd)) { + perror(path); + return 1; + } return 0; } static int Cat(void) { - int i, fd; - ssize_t rc; - char buf[512]; + int i, fd, rc; if (n < 2) { - for (;;) { - rc = read(0, buf, sizeof(buf)); - if (rc == -1) { - perror("read"); - return 1; - } - if (!rc) break; - rc = write(1, buf, rc); - if (rc == -1) { - perror("write"); - return 1; - } - } + return CatDump("", 0, true); } else { for (i = 1; i < n; ++i) { - if ((fd = open(args[i], O_RDONLY)) == -1) { + bool dontclose = false; + if (args[i][0] == '-' && !args[i][1]) { + dontclose = true; + fd = 0; + } else if ((fd = open(args[i], O_RDONLY)) == -1) { perror(args[i]); return 1; } - for (;;) { - rc = read(fd, buf, sizeof(buf)); - if (rc == -1) { - perror(args[i]); - close(fd); - return 1; - } - if (!rc) break; - rc = write(1, buf, rc); - if (rc == -1) { - perror("write"); - close(fd); - return 1; - } - } - if (close(fd)) { - perror(args[i]); - return 1; + if ((rc = CatDump(args[i], fd, dontclose))) { + return rc; } } } diff --git a/libc/runtime/getargmax.c b/libc/runtime/getargmax.c index 25aabc1ae..7792e50f9 100644 --- a/libc/runtime/getargmax.c +++ b/libc/runtime/getargmax.c @@ -17,17 +17,50 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" +#include "libc/macros.internal.h" #include "libc/runtime/runtime.h" +#include "libc/sysv/consts/limits.h" +#include "libc/sysv/consts/rlimit.h" + +#define CTL_KERN 1 +#define KERN_ARGMAX 8 /** - * Returns `ARG_MAX` for host platform. + * Returns expensive but more correct version of `ARG_MAX`. */ -int __arg_max(void) { - if (IsWindows()) return 32767; - if (IsLinux()) return 128 * 1024; - if (IsNetbsd()) return 256 * 1024; - if (IsFreebsd()) return 512 * 1024; - if (IsOpenbsd()) return 512 * 1024; - if (IsXnu()) return 1024 * 1024; - return ARG_MAX; +int __get_arg_max(void) { + if (IsLinux()) { + // You might think that just returning a constant 128KiB (ARG_MAX) + // would make sense, as this guy did: + // + // https://lkml.org/lkml/2017/11/15/813... + // + // I suspect a 128kB sysconf(_SC_ARG_MAX) is the sanest bet, simply + // because of that "conservative is better than aggressive". + // + // Especially since _technically_ we're still limiting things to that + // 128kB due to the single-string limit. + // + // Linus + // + // In practice that caused us trouble with toybox tests for xargs + // edge cases. The tests assume that they can at least reach the + // kernel's "minimum maximum" of 128KiB, but if we report 128KiB for + // _SC_ARG_MAX and xargs starts subtracting the environment space + // and so on from that, then xargs will think it's run out of space + // when given 128KiB of data, which should always work. See this + // thread for more: + // + // http://lists.landley.net/pipermail/toybox-landley.net/2019-November/011229.html + // + // So let's resign ourselves to tracking what the kernel actually + // does. Right now (2019, Linux 5.3) that amounts to: + uint64_t stacksz; + stacksz = __get_rlimit(RLIMIT_STACK); + return MAX(MIN(stacksz / 4, 3 * (8 * 1024 * 1024) / 4), _ARG_MAX); + } else if (IsBsd()) { + return __get_sysctl(CTL_KERN, KERN_ARGMAX); + } else { + return _ARG_MAX; + } } diff --git a/libc/runtime/getmaxfd.c b/libc/runtime/getavphyspages.c similarity index 81% rename from libc/runtime/getmaxfd.c rename to libc/runtime/getavphyspages.c index 14f63eee4..d55407037 100644 --- a/libc/runtime/getmaxfd.c +++ b/libc/runtime/getavphyspages.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,22 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/syscall-sysv.internal.h" -#include "libc/dce.h" +#include "libc/calls/struct/sysinfo.h" #include "libc/runtime/runtime.h" -#include "libc/sysv/consts/rlimit.h" -#define F_MAXFD 11 - -/** - * Returns maximum number of open files. - */ -long _GetMaxFd(void) { - int rc; - if (IsNetbsd()) { - if ((rc = __sys_fcntl(0, F_MAXFD, 0)) != -1) { - return rc; - } - } - return _GetResourceLimit(RLIMIT_NOFILE); +long __get_avphys_pages(void) { + struct sysinfo si; + if (sysinfo(&si) == -1) return -1; + return (((int64_t)si.freeram + si.bufferram) * si.mem_unit) / FRAMESIZE; } diff --git a/libc/runtime/getphyspages.c b/libc/runtime/getphyspages.c new file mode 100644 index 000000000..5212ee7e3 --- /dev/null +++ b/libc/runtime/getphyspages.c @@ -0,0 +1,26 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/sysinfo.h" +#include "libc/runtime/runtime.h" + +long __get_phys_pages(void) { + struct sysinfo si; + if (sysinfo(&si) == -1) return -1; + return ((int64_t)si.totalram * si.mem_unit) / FRAMESIZE; +} diff --git a/libc/runtime/getresourcelimit.c b/libc/runtime/getresourcelimit.c index e678149f0..3b670585a 100644 --- a/libc/runtime/getresourcelimit.c +++ b/libc/runtime/getresourcelimit.c @@ -21,9 +21,9 @@ #include "libc/macros.internal.h" #include "libc/sysv/consts/rlim.h" -long _GetResourceLimit(int resource) { +long __get_rlimit(int resource) { struct rlimit rl; - getrlimit(resource, &rl); + if (getrlimit(resource, &rl) == -1) return -1; if (rl.rlim_cur == RLIM_INFINITY) return -1; return MIN(rl.rlim_cur, LONG_MAX); } diff --git a/libc/calls/nanos.c b/libc/runtime/getsysctl.c similarity index 83% rename from libc/calls/nanos.c rename to libc/runtime/getsysctl.c index 14728f272..6c5fd7ecd 100644 --- a/libc/calls/nanos.c +++ b/libc/runtime/getsysctl.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -17,18 +17,15 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/struct/timespec.h" -#include "libc/time/time.h" +#include "libc/runtime/runtime.h" -/** - * Returns nanoseconds since UNIX epoch. - */ -int128_t _nanos(int timer) { - int128_t nanos; - struct timespec ts; - clock_gettime(timer, &ts); - nanos = ts.tv_sec; - nanos *= 1000000000; - nanos += ts.tv_nsec; - return nanos; +long __get_sysctl(int x, int y) { + int value; + int mib[2] = {x, y}; + size_t len = sizeof(value); + if (sys_sysctl(mib, 2, &value, &len, 0, 0) != -1) { + return value; + } else { + return -1; + } } diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index e619bcb0e..cebe1fb5e 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -129,9 +129,14 @@ bool IsCygwin(void); const char *GetCpuidOs(void); const char *GetCpuidEmulator(void); void GetCpuidBrand(char[13], uint32_t); -long _GetResourceLimit(int); +long __get_rlimit(int); +int __set_rlimit(int, int64_t); const char *__describe_os(void); -int __arg_max(void); +long __get_sysctl(int, int); +int __get_arg_max(void) pureconst; +int __get_cpu_count(void) pureconst; +long __get_avphys_pages(void) pureconst; +long __get_phys_pages(void) pureconst; #endif /* _COSMO_SOURCE */ COSMOPOLITAN_C_END_ diff --git a/libc/runtime/sysconf.c b/libc/runtime/sysconf.c index eff1f8b9f..0231d1f12 100644 --- a/libc/runtime/sysconf.c +++ b/libc/runtime/sysconf.c @@ -17,10 +17,21 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/sysconf.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/rlimit.h" +#include "libc/calls/struct/sysinfo.h" +#include "libc/calls/struct/sysinfo.internal.h" +#include "libc/dce.h" +#include "libc/limits.h" +#include "libc/macros.internal.h" #include "libc/runtime/clktck.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/sysconf.h" +#include "libc/sysv/consts/_posix.h" #include "libc/sysv/consts/limits.h" #include "libc/sysv/consts/rlimit.h" +#include "libc/sysv/errfuns.h" +#include "libc/thread/thread.h" /** * Returns configuration value about system. @@ -28,30 +39,58 @@ * The following parameters are supported: * * - `_SC_CLK_TCK` returns number of clock ticks per second - * - `_SC_ARG_MAX` currently always returns 32768 due to Windows + * - `_SC_ARG_MAX` will perform expensive rlimit calculations * - `_SC_PAGESIZE` currently always returns 65536 due to Windows - * - `_SC_NPROCESSORS_ONLN` returns number of CPUs in the system - * - `_SC_OPEN_MAX` returns maximum number of open files + * - `_SC_AVPHYS_PAGES` returns average physical memory pages + * - `_SC_PHYS_PAGES` returns physical memory pages available + * - `_SC_NPROCESSORS_ONLN` returns number of effective CPUs * - `_SC_CHILD_MAX` returns maximum number of processes + * - `_SC_OPEN_MAX` returns maximum number of open files * + * @return value on success, or -1 w/ errno + * @raise EINVAL if `name` isn't valid */ long sysconf(int name) { int n; switch (name) { - case _SC_ARG_MAX: - return _ARG_MAX; - case _SC_CHILD_MAX: - return _GetResourceLimit(RLIMIT_NPROC); case _SC_CLK_TCK: return CLK_TCK; - case _SC_OPEN_MAX: - return _GetMaxFd(); case _SC_PAGESIZE: return FRAMESIZE; + case _SC_ARG_MAX: + return __get_arg_max(); + case _SC_CHILD_MAX: + return __get_rlimit(RLIMIT_NPROC); + case _SC_OPEN_MAX: + return __get_rlimit(RLIMIT_NOFILE); + case _SC_NPROCESSORS_CONF: case _SC_NPROCESSORS_ONLN: - n = _getcpucount(); - return n > 0 ? n : -1; + return __get_cpu_count(); + case _SC_PHYS_PAGES: + return __get_phys_pages(); + case _SC_AVPHYS_PAGES: + return __get_avphys_pages(); + case _SC_THREADS: + return _POSIX_THREADS; + case _SC_THREAD_DESTRUCTOR_ITERATIONS: + return PTHREAD_DESTRUCTOR_ITERATIONS; + case _SC_THREAD_KEYS_MAX: + return PTHREAD_KEYS_MAX; + case _SC_THREAD_STACK_MIN: + return PTHREAD_STACK_MIN; + case _SC_THREAD_THREADS_MAX: + return LONG_MAX; + case _SC_LINE_MAX: + return _POSIX2_LINE_MAX; + case _SC_MONOTONIC_CLOCK: + return _POSIX_MONOTONIC_CLOCK; + case _SC_HOST_NAME_MAX: + return _POSIX_HOST_NAME_MAX; + case _SC_SPAWN: + return _POSIX_SPAWN; + case _SC_SYMLOOP_MAX: + return _POSIX_SYMLOOP_MAX; default: - return -1; + return einval(); } } diff --git a/libc/stdio/appendz.c b/libc/stdio/appendz.c index a71a6142f..8caca7051 100644 --- a/libc/stdio/appendz.c +++ b/libc/stdio/appendz.c @@ -37,12 +37,10 @@ struct appendz appendz(char *p) { unassert(z.n >= W * 2 && !(z.n & (W - 1))); z.i = *(size_t *)(p + z.n - W); if (!IsTiny() && W == 8) { - /* - * This check should fail if an append*() function was passed a - * pointer that was allocated manually by malloc(). Append ptrs - * can be free()'d safely, but they need to be allocated by the - * append library, because we write a special value to the end. - */ + // This check should fail if an append*() function was passed a + // pointer that was allocated manually by malloc(). Append ptrs + // can be free()'d safely, but they need to be allocated by the + // append library, because we write a special value to the end. unassert((z.i >> 48) == APPEND_COOKIE); z.i &= 0x0000ffffffffffff; } diff --git a/libc/stdio/dirstream.c b/libc/stdio/dirstream.c index 9f3b7a274..9437dc81a 100644 --- a/libc/stdio/dirstream.c +++ b/libc/stdio/dirstream.c @@ -413,24 +413,6 @@ static struct dirent *readdir_zipos(DIR *dir) { return ent; } -static void *golden(void *a, const void *b, size_t n) { - size_t i; - char *volatile d = a; - const char *volatile s = b; - if (d > s) { - for (i = n; i--;) { - d[i] = s[i]; - asm volatile("" ::: "memory"); - } - } else { - for (i = 0; i < n; ++i) { - d[i] = s[i]; - asm volatile("" ::: "memory"); - } - } - return d; -} - static struct dirent *readdir_unix(DIR *dir) { if (dir->buf_pos >= dir->buf_end) { long basep = dir->tell; diff --git a/libc/stdio/puts.c b/libc/stdio/puts.c index cae291488..459332ba7 100644 --- a/libc/stdio/puts.c +++ b/libc/stdio/puts.c @@ -20,7 +20,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" -static inline int PutsImpl(const char *s, FILE *f) { +static inline int puts_unlocked(const char *s, FILE *f) { size_t n, r; if ((n = strlen(s))) { r = fwrite_unlocked(s, 1, n, f); @@ -45,7 +45,7 @@ int puts(const char *s) { int bytes; f = stdout; flockfile(f); - bytes = PutsImpl(s, f); + bytes = puts_unlocked(s, f); funlockfile(f); return bytes; } diff --git a/libc/thread/pthread_attr_init.c b/libc/thread/pthread_attr_init.c index 231d7db1d..dbd16ab09 100644 --- a/libc/thread/pthread_attr_init.c +++ b/libc/thread/pthread_attr_init.c @@ -38,7 +38,7 @@ errno_t pthread_attr_init(pthread_attr_t *attr) { *attr = (pthread_attr_t){ .__stacksize = GetStackSize(), - .__guardsize = getauxval(AT_PAGESZ), + .__guardsize = GetGuardSize(), }; return 0; } diff --git a/net/turfwar/turfwar.c b/net/turfwar/turfwar.c index 6a75c83a5..e81038e15 100644 --- a/net/turfwar/turfwar.c +++ b/net/turfwar/turfwar.c @@ -1916,7 +1916,7 @@ int main(int argc, char *argv[]) { // we don't have proper futexes on these platforms // we'll be somewhat less aggressive about workers if (IsXnu() || IsNetbsd()) { - g_workers = MIN(g_workers, _getcpucount()); + g_workers = MIN(g_workers, (unsigned)__get_cpu_count()); } // user interface diff --git a/test/libc/calls/sched_getaffinity_test.c b/test/libc/calls/sched_getaffinity_test.c index 3121048c4..6a6112ad0 100644 --- a/test/libc/calls/sched_getaffinity_test.c +++ b/test/libc/calls/sched_getaffinity_test.c @@ -51,7 +51,7 @@ TEST(sched_getaffinity, firstOnly) { } TEST(sched_getaffinity, secondOnly) { - if (_getcpucount() < 2) return; + if (__get_cpu_count() < 2) return; cpu_set_t x, y; CPU_ZERO(&x); CPU_SET(1, &x); diff --git a/test/libc/mem/critbit0_test.c b/test/libc/mem/critbit0_test.c index 23b79a569..f3222f645 100644 --- a/test/libc/mem/critbit0_test.c +++ b/test/libc/mem/critbit0_test.c @@ -17,11 +17,14 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/mem/critbit0.h" +#include "libc/fmt/itoa.h" #include "libc/intrin/bits.h" #include "libc/mem/critbit0.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" +#include "libc/stdio/rand.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" struct Bog { @@ -143,3 +146,26 @@ TEST(critbit0, manual_clear) { ASSERT_TRUE(critbit0_delete(&tree, "hi")); ASSERT_EQ(NULL, tree.root); } + +#define N 500 + +char words[N][16]; + +void GenerateWords(void) { + for (int i = 0; i < N; ++i) { + FormatInt32(words[i], rand()); + } +} + +void BuildTree(void) { + struct critbit0 tree = {0}; + for (int i = 0; i < N; ++i) { + critbit0_insert(&tree, words[i]); + } + critbit0_clear(&tree); +} + +BENCH(critbit0, bench) { + GenerateWords(); + EZBENCH2("critbit0", donothing, BuildTree()); +} diff --git a/test/libc/mem/malloc_test.c b/test/libc/mem/malloc_test.c index fc535f155..50ffe6c5c 100644 --- a/test/libc/mem/malloc_test.c +++ b/test/libc/mem/malloc_test.c @@ -214,7 +214,7 @@ void *Worker(void *arg) { } BENCH(malloc, torture) { - int i, n = _getcpucount() * 2; + int i, n = __get_cpu_count() * 2; pthread_t *t = _gc(malloc(sizeof(pthread_t) * n)); if (!n) return; printf("\nmalloc torture test w/ %d threads and %d iterations\n", n, diff --git a/test/libc/stdio/popen_test.c b/test/libc/stdio/popen_test.c index 541cf463f..c64c574e2 100644 --- a/test/libc/stdio/popen_test.c +++ b/test/libc/stdio/popen_test.c @@ -79,7 +79,7 @@ TEST(popen, semicolon) { TEST(popen, singleQuotes) { setenv("there", "a b c", true); - ASSERT_NE(NULL, (f = popen("echo -l 'hello $there' yo", "r"))); + ASSERT_NE(NULL, (f = popen("echo 'hello $there'; echo yo", "r"))); ASSERT_STREQ("hello $there\n", fgets(buf, sizeof(buf), f)); ASSERT_STREQ("yo\n", fgets(buf, sizeof(buf), f)); ASSERT_EQ(0, pclose(f)); @@ -88,7 +88,7 @@ TEST(popen, singleQuotes) { TEST(popen, doubleQuotes) { setenv("hello", "a b c", true); - ASSERT_NE(NULL, (f = popen("echo -l \"$hello there\"", "r"))); + ASSERT_NE(NULL, (f = popen("echo \"$hello there\"", "r"))); ASSERT_STREQ("a b c there\n", fgets(buf, sizeof(buf), f)); ASSERT_EQ(0, pclose(f)); CheckForFdLeaks(); @@ -96,7 +96,7 @@ TEST(popen, doubleQuotes) { TEST(popen, quoteless) { setenv("there", "a b c", true); - ASSERT_NE(NULL, (f = popen("echo -l hello a$there yo", "r"))); + ASSERT_NE(NULL, (f = popen("echo hello; echo a$there; echo yo", "r"))); ASSERT_STREQ("hello\n", fgets(buf, sizeof(buf), f)); ASSERT_STREQ("aa b c\n", fgets(buf, sizeof(buf), f)); // mixed feelings ASSERT_STREQ("yo\n", fgets(buf, sizeof(buf), f)); diff --git a/test/libc/stdio/system_test.c b/test/libc/stdio/system_test.c index e6bc87353..9c0b846b2 100644 --- a/test/libc/stdio/system_test.c +++ b/test/libc/stdio/system_test.c @@ -24,6 +24,7 @@ #include "libc/paths.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/str/str.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sig.h" #include "libc/testlib/ezbench.h" @@ -45,6 +46,22 @@ void SetUp(void) { } } +int pipefd[2]; +int stdoutBack; + +void CaptureStdout(void) { + ASSERT_NE(-1, (stdoutBack = dup(1))); + ASSERT_SYS(0, 0, pipe(pipefd)); + ASSERT_NE(-1, dup2(pipefd[1], 1)); +} + +void RestoreStdout(void) { + ASSERT_SYS(0, 1, dup2(stdoutBack, 1)); + ASSERT_SYS(0, 0, close(stdoutBack)); + ASSERT_SYS(0, 0, close(pipefd[1])); + ASSERT_SYS(0, 0, close(pipefd[0])); +} + TEST(system, haveShell) { ASSERT_TRUE(system(0)); } @@ -71,20 +88,14 @@ TEST(system, testStdoutRedirect_withSpacesInFilename) { } TEST(system, testStderrRedirect_toStdout) { - if (IsAsan()) return; // TODO(jart): fix me - int pipefd[2]; - int stdoutBack = dup(1); - ASSERT_NE(-1, stdoutBack); - ASSERT_EQ(0, pipe(pipefd)); - ASSERT_NE(-1, dup2(pipefd[1], 1)); + CaptureStdout(); int stderrBack = dup(2); ASSERT_NE(-1, stderrBack); char buf[5] = {0}; - ASSERT_NE(-1, dup2(1, 2)); bool success = false; if (WEXITSTATUS(system("echo aaa 2>&1")) == 0) { - success = read(pipefd[0], buf, sizeof(buf) - 1) == (sizeof(buf) - 1); + success = read(pipefd[0], buf, 4) == (4); } ASSERT_NE(-1, dup2(stderrBack, 2)); ASSERT_EQ(true, success); @@ -97,15 +108,12 @@ TEST(system, testStderrRedirect_toStdout) { ASSERT_NE(-1, dup2(1, 2)); success = false; if (WEXITSTATUS(system("./echo.com aaa 2>&1")) == 0) { - success = read(pipefd[0], buf, sizeof(buf) - 1) == (sizeof(buf) - 1); + success = read(pipefd[0], buf, 4) == (4); } ASSERT_NE(-1, dup2(stderrBack, 2)); ASSERT_EQ(true, success); ASSERT_STREQ("aaa\n", buf); - - ASSERT_NE(-1, dup2(stdoutBack, 1)); - ASSERT_EQ(0, close(pipefd[1])); - ASSERT_EQ(0, close(pipefd[0])); + RestoreStdout(); } TEST(system, and) { @@ -168,49 +176,43 @@ TEST(system, exitStatusPreservedAfterSemiColon) { ASSERT_EQ(1, WEXITSTATUS(system("false; "))); ASSERT_EQ(1, WEXITSTATUS(system("./false.com;"))); ASSERT_EQ(1, WEXITSTATUS(system("./false.com;"))); - int pipefd[2]; - int stdoutBack = dup(1); - ASSERT_NE(-1, stdoutBack); - ASSERT_EQ(0, pipe(pipefd)); - ASSERT_NE(-1, dup2(pipefd[1], 1)); + CaptureStdout(); ASSERT_EQ(0, WEXITSTATUS(system("false; echo $?"))); - char buf[3] = {0}; - ASSERT_EQ(2, read(pipefd[0], buf, 2)); + char buf[9] = {0}; + ASSERT_EQ(2, read(pipefd[0], buf, 8)); ASSERT_STREQ("1\n", buf); ASSERT_EQ(0, WEXITSTATUS(system("./false.com; echo $?"))); - buf[0] = 0; - buf[1] = 0; - ASSERT_EQ(2, read(pipefd[0], buf, 2)); + ASSERT_EQ(2, read(pipefd[0], buf, 8)); ASSERT_STREQ("1\n", buf); - ASSERT_NE(-1, dup2(stdoutBack, 1)); - ASSERT_EQ(0, close(pipefd[1])); - ASSERT_EQ(0, close(pipefd[0])); + ASSERT_EQ(0, WEXITSTATUS(system("echo -n hi"))); + EXPECT_EQ(2, read(pipefd[0], buf, 8)); + ASSERT_STREQ("hi", buf); + RestoreStdout(); +} + +TEST(system, globio) { + char buf[9] = {0}; + CaptureStdout(); + ASSERT_SYS(0, 0, touch("a", 0644)); + ASSERT_SYS(0, 0, touch("b", 0644)); + ASSERT_EQ(0, WEXITSTATUS(system("echo *"))); + EXPECT_EQ(4, read(pipefd[0], buf, 8)); + ASSERT_STREQ("a b\n", buf); + RestoreStdout(); } TEST(system, allowsLoneCloseCurlyBrace) { - int pipefd[2]; - int stdoutBack = dup(1); - ASSERT_NE(-1, stdoutBack); - ASSERT_EQ(0, pipe(pipefd)); - ASSERT_NE(-1, dup2(pipefd[1], 1)); + CaptureStdout(); char buf[6] = {0}; - ASSERT_EQ(0, WEXITSTATUS(system("echo \"aaa\"}"))); - ASSERT_EQ(sizeof(buf) - 1, read(pipefd[0], buf, sizeof(buf) - 1)); + ASSERT_EQ(5, read(pipefd[0], buf, 5)); ASSERT_STREQ("aaa}\n", buf); - buf[0] = 0; - buf[1] = 0; - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; + bzero(buf, 6); testlib_extract("/zip/echo.com", "echo.com", 0755); ASSERT_EQ(0, WEXITSTATUS(system("./echo.com \"aaa\"}"))); - ASSERT_EQ(sizeof(buf) - 1, read(pipefd[0], buf, sizeof(buf) - 1)); + ASSERT_EQ(5, read(pipefd[0], buf, 5)); ASSERT_STREQ("aaa}\n", buf); - - ASSERT_NE(-1, dup2(stdoutBack, 1)); - ASSERT_EQ(0, close(pipefd[1])); - ASSERT_EQ(0, close(pipefd[0])); + RestoreStdout(); } TEST(system, glob) { diff --git a/third_party/ggml/common.cc b/third_party/ggml/common.cc index 09a9cd5c4..2f8e1d04c 100644 --- a/third_party/ggml/common.cc +++ b/third_party/ggml/common.cc @@ -88,7 +88,7 @@ static bool append_file_to_prompt(const char *path, gpt_params & params) { } bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { - params.n_threads = std::min(20, std::max(1, _getcpucount() >> 1)); + params.n_threads = std::min(20., (unsigned)__get_cpu_count() * .75); bool invalid_param = false; std::string arg; diff --git a/third_party/ggml/common.h b/third_party/ggml/common.h index 8a150d2ad..78851bbeb 100644 --- a/third_party/ggml/common.h +++ b/third_party/ggml/common.h @@ -21,7 +21,7 @@ struct gpt_params { int32_t seed = -1; // RNG seed int32_t verbose = 0; // Logging verbosity - int32_t n_threads = std::max(1, _getcpucount() >> 1); + int32_t n_threads = std::max(20., (unsigned)__get_cpu_count() * .75); int32_t n_predict = -1; // new tokens to predict int32_t n_parts = -1; // amount of model parts (-1 = determine from model dimensions) int32_t n_ctx = 512; // context size diff --git a/third_party/ggml/quantize.cc b/third_party/ggml/quantize.cc index 838d0189f..9a0e70ddb 100644 --- a/third_party/ggml/quantize.cc +++ b/third_party/ggml/quantize.cc @@ -92,7 +92,7 @@ int main(int argc, char ** argv) { ftype = (enum llama_ftype)atoi(argv[3]); } - int nthread = argc > 4 ? atoi(argv[4]) : std::min(20, std::max(1, _getcpucount() >> 1)); + int nthread = argc > 4 ? atoi(argv[4]) : std::min(20, std::max(1, __get_cpu_count() >> 1)); const int64_t t_main_start_us = ggml_time_us(); diff --git a/third_party/lua/lunix.c b/third_party/lua/lunix.c index 1ff267441..d2687fa3c 100644 --- a/third_party/lua/lunix.c +++ b/third_party/lua/lunix.c @@ -3532,7 +3532,7 @@ int LuaUnix(lua_State *L) { LuaSetIntField(L, "RUSAGE_CHILDREN", RUSAGE_CHILDREN); LuaSetIntField(L, "RUSAGE_BOTH", RUSAGE_BOTH); - LuaSetIntField(L, "ARG_MAX", __arg_max()); + LuaSetIntField(L, "ARG_MAX", __get_arg_max()); LuaSetIntField(L, "BUFSIZ", BUFSIZ); LuaSetIntField(L, "CLK_TCK", CLK_TCK); LuaSetIntField(L, "NAME_MAX", _NAME_MAX); diff --git a/third_party/python/Modules/posixmodule.c b/third_party/python/Modules/posixmodule.c index e6b4a237c..51240832d 100644 --- a/third_party/python/Modules/posixmodule.c +++ b/third_party/python/Modules/posixmodule.c @@ -10509,7 +10509,7 @@ os_cpu_count_impl(PyObject *module) /*[clinic end generated code: output=5fc29463c3936a9c input=e7c8f4ba6dbbadd3]*/ { int ncpu; - ncpu = _getcpucount(); + ncpu = __get_cpu_count(); if (ncpu >= 1) return PyLong_FromLong(ncpu); else diff --git a/third_party/radpajama/common-gptneox.cc b/third_party/radpajama/common-gptneox.cc index 4a6b7ac02..6739678de 100644 --- a/third_party/radpajama/common-gptneox.cc +++ b/third_party/radpajama/common-gptneox.cc @@ -39,7 +39,7 @@ // clang-format off bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { - params.n_threads = std::min(20, std::max(1, (int)(_getcpucount() * 0.75))); + params.n_threads = std::min(20., (unsigned)__get_cpu_count() * 0.75); bool invalid_param = false; std::string arg; diff --git a/third_party/radpajama/common-gptneox.h b/third_party/radpajama/common-gptneox.h index 05e285617..f74a6283e 100644 --- a/third_party/radpajama/common-gptneox.h +++ b/third_party/radpajama/common-gptneox.h @@ -19,7 +19,7 @@ struct gpt_params { int32_t seed = -1; // RNG seed - int32_t n_threads = MIN(4, (int32_t) _getcpucount() * 0.75); + int32_t n_threads = MIN(20., (unsigned) __get_cpu_count() * 0.75); int32_t n_predict = 128; // new tokens to predict int32_t n_parts = -1; // amount of model parts (-1 = determine from model dimensions) int32_t n_ctx = 512; // context size diff --git a/tool/build/compile.c b/tool/build/compile.c index 82997fffa..9e91e2213 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -314,7 +314,7 @@ void PrintMakeCommand(void) { appends(&output, "make MODE="); appends(&output, mode); appends(&output, " -j"); - appendd(&output, buf, FormatUint64(buf, _getcpucount()) - buf); + appendd(&output, buf, FormatUint64(buf, __get_cpu_count()) - buf); appendw(&output, ' '); appends(&output, target); } diff --git a/tool/build/mkdeps.c b/tool/build/mkdeps.c index fd9e892ce..5f1c9067c 100644 --- a/tool/build/mkdeps.c +++ b/tool/build/mkdeps.c @@ -206,8 +206,8 @@ static void Crunch(void) { free(sources.p); sources.p = 0; sources.i = j; - if (!radix_sort_int64((const long *)sauces, sources.i) || - !radix_sort_int64((const long *)edges.p, edges.i)) { + if (radix_sort_int64((const long *)sauces, sources.i) == -1 || + radix_sort_int64((const long *)edges.p, edges.i) == -1) { DieOom(); } } diff --git a/tool/build/pledge.c b/tool/build/pledge.c index 7e67632e9..efebdc7ea 100644 --- a/tool/build/pledge.c +++ b/tool/build/pledge.c @@ -163,9 +163,9 @@ static void GetOpts(int argc, char *argv[]) { g_fszquota = 256 * 1000 * 1000; if (!sysinfo(&si)) { g_memquota = si.totalram; - g_proquota = _getcpucount() + si.procs; + g_proquota = __get_cpu_count() + si.procs; } else { - g_proquota = _getcpucount() * 100; + g_proquota = __get_cpu_count() * 100; g_memquota = 4L * 1024 * 1024 * 1024; } while ((opt = getopt(argc, argv, "hnqkNVT:p:u:g:c:C:D:P:M:F:O:v:")) != -1) { diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index 60561081e..5a57014ac 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -131,7 +131,7 @@ int LuaGetCpuCore(lua_State *L) { } int LuaGetCpuCount(lua_State *L) { - lua_pushinteger(L, _getcpucount()); + lua_pushinteger(L, __get_cpu_count()); return 1; }