From 75832f7379e853a0031fb59a86bd7850fc7968da Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 18 Aug 2022 15:43:03 -0700 Subject: [PATCH] Polyfill sysinfo() a ilttle bit on BSDs --- libc/calls/_timespec_totimeval.c | 23 ++++++++ libc/calls/_timeval_totimespec.c | 23 ++++++++ libc/calls/calls.mk | 1 + libc/calls/struct/timeval.h | 3 ++ libc/calls/struct/vmmeter-meta.internal.h | 0 libc/calls/sysinfo.c | 65 ++++++++++++++++++----- 6 files changed, 103 insertions(+), 12 deletions(-) create mode 100644 libc/calls/_timespec_totimeval.c create mode 100644 libc/calls/_timeval_totimespec.c create mode 100755 libc/calls/struct/vmmeter-meta.internal.h diff --git a/libc/calls/_timespec_totimeval.c b/libc/calls/_timespec_totimeval.c new file mode 100644 index 000000000..f530ce71e --- /dev/null +++ b/libc/calls/_timespec_totimeval.c @@ -0,0 +1,23 @@ +/*-*- 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 │ +│ │ +│ 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/timeval.h" + +struct timeval _timespec_totimeval(struct timespec ts) { + return (struct timeval){ts.tv_sec, ts.tv_nsec / 1000}; +} diff --git a/libc/calls/_timeval_totimespec.c b/libc/calls/_timeval_totimespec.c new file mode 100644 index 000000000..65a992bb4 --- /dev/null +++ b/libc/calls/_timeval_totimespec.c @@ -0,0 +1,23 @@ +/*-*- 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 │ +│ │ +│ 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/timeval.h" + +struct timespec _timeval_totimespec(struct timeval tv) { + return (struct timespec){tv.tv_sec, tv.tv_usec * 1000}; +} diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index bb343c738..c097156fb 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -185,6 +185,7 @@ o//libc/calls/getcwd-xnu.greg.o: private \ # division is expensive if not optimized o/$(MODE)/libc/calls/_timespec_tomillis.o \ o/$(MODE)/libc/calls/_timespec_tomicros.o \ +o/$(MODE)/libc/calls/_timespec_totimeval.o \ o/$(MODE)/libc/calls/_timespec_frommillis.o \ o/$(MODE)/libc/calls/_timespec_frommicros.o: private \ OVERRIDE_CFLAGS += \ diff --git a/libc/calls/struct/timeval.h b/libc/calls/struct/timeval.h index 633f05300..60390752e 100644 --- a/libc/calls/struct/timeval.h +++ b/libc/calls/struct/timeval.h @@ -1,5 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_H_ #define COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_H_ +#include "libc/calls/struct/timespec.h" #include "libc/time/struct/timezone.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -16,6 +17,8 @@ int lutimes(const char *, const struct timeval[2]); int utimes(const char *, const struct timeval[2]); struct timeval _timeval_add(struct timeval, struct timeval); +struct timeval _timespec_totimeval(struct timespec); +struct timespec _timeval_totimespec(struct timeval); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/calls/struct/vmmeter-meta.internal.h b/libc/calls/struct/vmmeter-meta.internal.h new file mode 100755 index 000000000..e69de29bb diff --git a/libc/calls/sysinfo.c b/libc/calls/sysinfo.c index e47b0a912..cd4f715d7 100644 --- a/libc/calls/sysinfo.c +++ b/libc/calls/sysinfo.c @@ -16,36 +16,77 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/struct/sysinfo.h" #include "libc/calls/struct/sysinfo.internal.h" +#include "libc/calls/struct/timespec.h" +#include "libc/calls/struct/timeval.h" +#include "libc/calls/struct/vmmeter-meta.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/macros.internal.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" +#define CTL_KERN 1 +#define CTL_HW 6 +#define KERN_BOOTTIME 21 +#define HW_PHYSMEM 5 + +static int64_t GetUptime(void) { + if (IsNetbsd()) return 0; // TODO(jart): Why? + struct timeval x; + size_t n = sizeof(x); + int mib[] = {CTL_KERN, KERN_BOOTTIME}; + if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return 0; + return _timespec_real().tv_sec - x.tv_sec; +} + +static int64_t GetPhysmem(void) { + uint64_t x; + size_t n = sizeof(x); + int mib[] = {CTL_HW, HW_PHYSMEM}; + if (sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return 0; + return x; +} + +static int sys_sysinfo_bsd(struct sysinfo *info) { + info->uptime = GetUptime(); + info->totalram = GetPhysmem(); + return 0; +} + /** * Returns amount of system ram, cores, etc. + * + * Only the `totalram` field is supported on all platforms right now. + * Support is best on Linux. Fields will be set to zero when they're not + * known. + * * @return 0 on success or -1 w/ errno - * @error ENOSYS, EFAULT + * @error EFAULT */ int sysinfo(struct sysinfo *info) { int rc; - if (IsAsan()) { - if (info && !__asan_is_valid(info, sizeof(*info))) { - return efault(); + struct sysinfo x = {0}; + if (IsAsan() && info && !__asan_is_valid(info, sizeof(*info))) { + rc = efault(); + } else if (!IsWindows()) { + if (IsLinux()) { + rc = sys_sysinfo(&x); + } else { + rc = sys_sysinfo_bsd(&x); } - } - bzero(info, sizeof(*info)); - if (!IsWindows()) { - rc = sys_sysinfo(info); } else { - rc = sys_sysinfo_nt(info); + rc = sys_sysinfo_nt(&x); } if (rc != -1) { - info->procs = MAX(1, info->procs); - info->mem_unit = MAX(1, info->mem_unit); - info->totalram = MAX((8 * 1024 * 1024) / info->mem_unit, info->totalram); + x.procs = MAX(1, x.procs); + x.mem_unit = MAX(1, x.mem_unit); + x.totalram = MAX((8 * 1024 * 1024) / x.mem_unit, x.totalram); + memcpy(info, &x, sizeof(x)); } + STRACE("sysinfo(%p) → %d% m", info, rc); return rc; }