Make improvements

- Document redbean's argon2 module
- Fix regressions in cthreads library
- Make testlib work better with threads
- Give the cthreads library lots of love
- Remove some of the stdio assembly code
- Implement getloadavg() across platforms
- Code size optimizations for errnos, etc.
- Only check for signals in main thread on Windows
- Make errnos for dup2 / dup3 consistent with posix

This change also fixes a bug in the argon2 module, where the NUL
terminator was being included in the hash encoded ascii string. This
shouldn't require any database migrations to folks who found this module
and productionized it, since the argon2 library treats it as a c string.
This commit is contained in:
Justine Tunney 2022-05-27 13:25:46 -07:00
parent cb67223051
commit de5de19004
234 changed files with 1728 additions and 1993 deletions

View file

@ -248,6 +248,7 @@ void sync(void);
int clone(int (*)(void *), void *, size_t, int, void *, int *, void *, size_t,
int *);
int futex(uint32_t *, int, int, const struct timespec *, uint32_t *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » formatting

View file

@ -54,7 +54,7 @@ int close(int fd) {
} else if (fd < 0) {
rc = einval();
} else {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
if (__isfdkind(fd, kFdZip)) {
rc = weaken(__zipos_close)(fd);
} else {
if (!IsWindows() && !IsMetal()) {
@ -62,16 +62,16 @@ int close(int fd) {
} else if (IsMetal()) {
rc = 0;
} else {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) {
if (__isfdkind(fd, kFdEpoll)) {
rc = weaken(sys_close_epoll_nt)(fd);
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) {
} else if (__isfdkind(fd, kFdSocket)) {
rc = weaken(sys_closesocket_nt)(g_fds.p + fd);
} else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdFile ||
g_fds.p[fd].kind == kFdConsole ||
g_fds.p[fd].kind == kFdProcess)) {
} else if (__isfdkind(fd, kFdFile) || //
__isfdkind(fd, kFdConsole) || //
__isfdkind(fd, kFdProcess)) { //
rc = sys_close_nt(g_fds.p + fd);
} else {
STRACE("close(%d) unknown kind: %d", fd, g_fds.p[fd].kind);
STRACE("close(%d) unknown kind", fd);
rc = ebadf();
}
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/mem/mem.h"
#include "libc/nt/files.h"
@ -37,7 +38,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t rc, proc, handle;
// validate the api usage
if (oldfd < 0) return einval();
if (oldfd < 0) return ebadf();
if (flags & ~O_CLOEXEC) return einval();
_spinlock(&__fds_lock);

View file

@ -17,26 +17,35 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Duplicates file descriptor/handle.
* Duplicates file descriptor.
*
* The `O_CLOEXEC` flag shall be cleared from the resulting file
* descriptor; see dup3() to preserve it.
*
* @param fd remains open afterwards
* @return some arbitrary new number for fd
* @raise EOPNOTSUPP if zipos file
* @raise EBADF if fd isn't open
* @asyncsignalsafe
* @vforksafe
*/
int dup(int fd) {
int fd2;
if (!IsWindows()) {
fd2 = sys_dup(fd);
int rc;
if (__isfdkind(fd, kFdZip)) {
rc = eopnotsupp();
} else if (!IsWindows()) {
rc = sys_dup(fd);
} else {
fd2 = sys_dup_nt(fd, -1, 0, -1);
rc = sys_dup_nt(fd, -1, 0, -1);
}
STRACE("%s(%d) → %d% m", "dup", fd, fd2);
return fd2;
STRACE("%s(%d) → %d% m", "dup", fd, rc);
return rc;
}

View file

@ -17,27 +17,47 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Duplicates file descriptor, granting it specific number.
*
* The `O_CLOEXEC` flag shall be cleared from the resulting file
* descriptor; see dup3() to preserve it.
*
* Unlike dup3(), the dup2() function permits oldfd and newfd to be the
* same, in which case the only thing this function does is test if
* oldfd is open.
*
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op
* @return new file descriptor, or -1 w/ errno
* @raise EBADF is oldfd isn't open
* @raise EBADF is newfd negative or too big
* @raise EINTR if a signal handler was called
* @asyncsignalsafe
* @vforksafe
*/
int dup2(int oldfd, int newfd) {
int rc;
if (oldfd == newfd) {
rc = newfd;
if (__isfdkind(oldfd, kFdZip)) {
rc = eopnotsupp();
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, 0);
rc = sys_dup2(oldfd, newfd);
} else if (newfd < 0) {
rc = ebadf();
} else if (oldfd == newfd) {
if (__isfdopen(oldfd)) {
rc = newfd;
} else {
rc = ebadf();
}
} else {
rc = sys_dup_nt(oldfd, newfd, 0, -1);
}

View file

@ -19,11 +19,18 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#define F_DUP2FD 10
#define F_DUP2FD_CLOEXEC 18
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
static bool once, demodernize;
int olderr, fd;
static bool once;
static bool demodernize;
int olderr, how, fd;
if (!once) {
olderr = errno;
fd = __sys_dup3(oldfd, newfd, flags);
@ -39,5 +46,12 @@ int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
} else if (!demodernize) {
return __sys_dup3(oldfd, newfd, flags);
}
return __fixupnewfd(sys_dup2(oldfd, newfd), flags);
if (oldfd == newfd) return einval();
if (flags & ~O_CLOEXEC) return einval();
if (IsFreebsd()) {
how = flags & O_CLOEXEC ? F_DUP2FD_CLOEXEC : F_DUP2FD;
return __sys_fcntl(oldfd, how, newfd);
} else {
return __fixupnewfd(sys_dup2(oldfd, newfd), flags);
}
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
@ -33,13 +34,26 @@
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op
* @param flags can have O_CLOEXEC
* @param flags may have O_CLOEXEC which is needed to preserve the
* close-on-execve() state after file descriptor duplication
* @return newfd on success, or -1 w/ errno
* @raise EINVAL if flags has unsupported bits
* @raise EINVAL if newfd equals oldfd
* @raise EBADF is oldfd isn't open
* @raise EBADF is newfd negative or too big
* @raise EINTR if a signal handler was called
* @see dup(), dup2()
*/
int dup3(int oldfd, int newfd, int flags) {
int rc;
if (!IsWindows()) {
if (__isfdkind(oldfd, kFdZip)) {
rc = eopnotsupp();
} else if (oldfd == newfd) {
rc = einval();
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, flags);
} else if (newfd < 0) {
rc = ebadf();
} else {
rc = sys_dup_nt(oldfd, newfd, flags, -1);
}

View file

@ -17,6 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
_Alignas(64) int __sig_lock;
unsigned __sighandrvas[NSIG];
unsigned __sighandflags[NSIG];
_Alignas(64) int __sig_lock_obj;

98
libc/calls/getcpucount.c Normal file
View file

@ -0,0 +1,98 @@
/*-*- 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
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/assert.h"
#include "libc/bits/popcnt.h"
#include "libc/calls/calls.h"
#include "libc/calls/weirdtypes.h"
#include "libc/dce.h"
#include "libc/macros.internal.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
#define HW_NCPU 3
#define HW_NCPUONLINE_OPENBSD 25
#define HW_NCPUONLINE_NETBSD 16
#define ALL_PROCESSOR_GROUPS 0xffff
static unsigned GetCpuCountLinux(void) {
uint64_t s[16];
unsigned i, c, n;
if (!sched_getaffinity(0, sizeof(s), s)) {
for (c = i = 0; i < ARRAYLEN(s); ++i) {
c += popcnt(s[i]);
}
return c;
} else {
return 0;
}
}
static unsigned GetCpuCountBsd(void) {
size_t n;
int c, cmd[2];
n = sizeof(c);
cmd[0] = CTL_HW;
if (IsOpenbsd()) {
cmd[1] = HW_NCPUONLINE_OPENBSD;
} else if (IsNetbsd()) {
cmd[1] = HW_NCPUONLINE_NETBSD;
} else {
cmd[1] = HW_NCPU;
}
if (!sysctl(cmd, 2, &c, &n, 0, 0)) {
return c;
} else {
return 0;
}
}
static textwindows unsigned GetCpuCountWindows(void) {
struct NtSystemInfo si;
uint32_t (*f)(uint16_t);
if ((f = GetProcAddress(GetModuleHandle("KERNEL32"),
"GetMaximumProcessorCount"))) {
return f(ALL_PROCESSOR_GROUPS);
} else {
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}
}
/**
* Returns number of CPUs in system.
*
* On Intel systems with HyperThreading this will return the number of
* cores multiplied by two.
*
* @return cpu count or 0 if it couldn't be determined
*/
unsigned GetCpuCount(void) {
if (!IsWindows()) {
if (!IsBsd()) {
return GetCpuCountLinux();
} else {
return GetCpuCountBsd();
}
} else {
return GetCpuCountWindows();
}
}

View file

@ -0,0 +1,71 @@
/*-*- 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/calls.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
#include "libc/runtime/sysconf.h"
#define FT(x) (x.dwLowDateTime | (uint64_t)x.dwHighDateTime << 32)
static int cpus;
static double load;
_Alignas(64) static int lock;
static struct NtFileTime idle1, kern1, user1;
textwindows int sys_getloadavg_nt(double *a, int n) {
int i, rc;
uint64_t elapsed, used;
struct NtFileTime idle, kern, user;
_spinlock(&lock);
if (GetSystemTimes(&idle, &kern, &user)) {
elapsed = (FT(kern) - FT(kern1)) + (FT(user) - FT(user1));
if (elapsed) {
used = elapsed - (FT(idle) - FT(idle1));
load = (double)used / elapsed * cpus;
load = MIN(MAX(load, 0), cpus * 2);
idle1 = idle, kern1 = kern, user1 = user;
}
for (i = 0; i < n; ++i) {
a[i] = load;
}
rc = n;
} else {
rc = __winerr();
}
_spunlock(&lock);
return rc;
}
static textstartup void sys_getloadavg_nt_init(void) {
double a[3];
if (IsWindows()) {
load = 1;
cpus = GetCpuCount() / 2;
cpus = MAX(1, cpus);
GetSystemTimes(&idle1, &kern1, &user1);
}
}
const void *const sys_getloadavg_nt_ctor[] initarray = {
sys_getloadavg_nt_init,
};

View file

@ -17,24 +17,60 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
#define CTL_VM 2
#define VM_LOADAVG 2
struct loadavg {
uint32_t ldavg[3];
int64_t fscale;
};
/**
* Returns system load average.
* @note work in progress
*
* @param a should be array of 3 doubles
* @param n should be 3
* @return number of items placed in `a` or -1 w/ errno
* @raise ENOSYS on metal
*/
int getloadavg(double *a, int n) {
/* cat /proc/loadavg */
int i;
struct sysinfo si;
if (!n) return 0;
if (n < 0) return einval();
if (sysinfo(&si) == -1) return -1;
int i, rc;
if (n > 3) n = 3;
for (i = 0; i < n; i++) {
a[i] = 1. / 65536 * si.loads[i];
if (!n) {
rc = 0;
} else if (n < 0) {
rc = einval();
} else if (IsWindows()) {
return sys_getloadavg_nt(a, n);
} else if (IsLinux()) {
struct sysinfo si;
if ((rc = sysinfo(&si)) != -1) {
for (i = 0; i < n; i++) {
a[i] = 1. / 65536 * si.loads[i];
}
rc = n;
}
} else if (IsFreebsd() || IsNetbsd() || IsOpenbsd() || IsXnu()) {
size_t size;
struct loadavg loadinfo;
int mib[2] = {CTL_VM, VM_LOADAVG};
size = sizeof(loadinfo);
if ((rc = sysctl(mib, 2, &loadinfo, &size, 0, 0)) != -1) {
for (i = 0; i < n; i++) {
a[i] = (double)loadinfo.ldavg[i] / loadinfo.fscale;
}
rc = n;
}
} else {
rc = enosys();
}
return n;
STRACE("getloadavg(%p, %d) → %d% m", a, n, rc);
return rc;
}

View file

@ -49,9 +49,9 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
!GetProcessIoCounters(me, &iocount)) {
return __winerr();
}
_spinlock(&__sig_lock);
__sig_lock();
nsignals = __sig_count;
_spunlock(&__sig_lock);
__sig_unlock();
*usage = (struct rusage){
.ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)),
.ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)),

View file

@ -29,35 +29,13 @@
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/nexgen32e/threaded.h"
_Alignas(64) static int rlock;
// return 0 on success, or tid of other owner
static privileged inline int AcquireInterruptPollLock(void) {
// any thread can poll for interrupts
// but it's wasteful to have every single thread doing it
int me, owner = 0;
if (__threaded) {
me = gettid();
if (!_lockcmpxchgp(&rlock, &owner, me) && owner == me) {
owner = 0;
}
}
return owner;
}
static textwindows inline void ReleaseInterruptPollLock(void) {
int zero = 0;
__atomic_store(&rlock, &zero, __ATOMIC_RELAXED);
}
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
bool res;
if (__time_critical) return false;
if (AcquireInterruptPollLock()) return false;
if (__threaded && __threaded != gettid()) return false;
if (weaken(_check_sigalrm)) weaken(_check_sigalrm)();
if (weaken(_check_sigchld)) weaken(_check_sigchld)();
if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd);
res = weaken(__sig_check) && weaken(__sig_check)(restartable);
ReleaseInterruptPollLock();
return res;
}

View file

@ -1,97 +0,0 @@
/*-*- 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/loadavg.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/pdh.h"
#include "libc/nt/enum/securityimpersonationlevel.h"
#include "libc/nt/enum/wt.h"
#include "libc/nt/errors.h"
#include "libc/nt/events.h"
#include "libc/nt/files.h"
#include "libc/nt/pdh.h"
#include "libc/nt/privilege.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/luid.h"
#include "libc/nt/struct/pdhfmtcountervalue.h"
#include "libc/nt/struct/tokenprivileges.h"
#include "libc/nt/synchronization.h"
#include "libc/str/str.h"
/**
* @fileoverview sysinfo() on the new technology
* @kudos Giampaolo Rodola for teaching how to do load average
*/
#define LOAD_SAMPLING_INTERVAL 1 // in seconds
// https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23
#define LOAD1F .9200444146293232478931553241
#define LOAD5F .9834714538216174894737477501
#define LOAD15F .9944598480048967508795473394
double __ntloadavg[3];
static void LoadavgNtPoll(int64_t hCounter, bool32 timedOut) {
struct NtPdhFmtCountervalue c;
if (!PdhGetFormattedCounterValue(hCounter, kNtPdhFmtDouble, 0, &c)) {
__ntloadavg[0] = __ntloadavg[0] * LOAD1F + c.doubleValue * (1 - LOAD1F);
__ntloadavg[1] = __ntloadavg[1] * LOAD5F + c.doubleValue * (1 - LOAD5F);
__ntloadavg[2] = __ntloadavg[2] * LOAD15F + c.doubleValue * (1 - LOAD15F);
} else {
STRACE("PdhGetFormattedCounterValue(%ld) failed", hCounter);
}
}
static textstartup void LoadavgNtInit(void) {
int64_t hQuery, hCounter, hEvent, hWaiter;
if (!IsWindows()) return;
STRACE("LoadavgNtInit()");
if (PdhOpenQuery(0, 0, &hQuery)) {
STRACE("PdhOpenQuery failed");
return;
}
if (PdhAddEnglishCounter(hQuery, u"\\System\\Processor Queue Length", 0,
&hCounter)) {
STRACE("PdhAddEnglishCounter() failed");
return;
}
if (!(hEvent = CreateEvent(0, 0, 0, u"LoadUpdateEvent"))) {
STRACE("CreateEvent() failed");
return;
}
if (PdhCollectQueryDataEx(hQuery, LOAD_SAMPLING_INTERVAL, hEvent)) {
STRACE("PdhCollectQueryDataEx() failed");
return;
}
if (!RegisterWaitForSingleObject(
&hWaiter, hEvent, (void *)NT2SYSV(LoadavgNtPoll),
(void *)(intptr_t)hCounter, -1, kNtWtExecutedefault)) {
STRACE("RegisterWaitForSingleObject() failed");
return;
}
LoadavgNtPoll(hCounter, 0);
}
const void *const LoadavgNtCtor[] initarray = {
LoadavgNtInit,
};

View file

@ -1,10 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_LOADAVG_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_LOADAVG_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern double __ntloadavg[3];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_LOADAVG_INTERNAL_H_ */

View file

@ -38,7 +38,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
int i;
uint64_t a, b;
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
_spinlock(&__sig_lock);
__sig_lock();
if (old) {
*old = __sig.mask;
}
@ -54,7 +54,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
}
__sig.mask.__bits[0] &= ~(SIGKILL | SIGSTOP);
}
_spunlock(&__sig_lock);
__sig_unlock();
return 0;
} else {
return einval();

View file

@ -26,6 +26,8 @@ struct Signals {
extern struct Signals __sig; // TODO(jart): Need TLS
extern long __sig_count;
void __sig_lock(void) hidden;
void __sig_unlock(void) hidden;
bool __sig_check(bool) hidden;
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
int __sig_add(int, int) hidden;

View file

@ -66,7 +66,7 @@ static textwindows void __sig_free(struct Signal *mem) {
static textwindows struct Signal *__sig_remove(void) {
struct Signal *prev, *res;
if (__sig.queue) {
_spinlock(&__sig_lock);
__sig_lock();
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
if (!sigismember(&__sig.mask, res->sig)) {
if (res == __sig.queue) {
@ -80,7 +80,7 @@ static textwindows struct Signal *__sig_remove(void) {
STRACE("%G is masked", res->sig);
}
}
_spunlock(&__sig_lock);
__sig_unlock();
} else {
res = 0;
}
@ -99,7 +99,7 @@ static privileged bool __sig_deliver(bool restartable, int sig, int si_code,
STRACE("delivering %G", sig);
// enter the signal
_spinlock(&__sig_lock);
__sig_lock();
rva = __sighandrvas[sig];
flags = __sighandflags[sig];
if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
@ -110,7 +110,7 @@ static privileged bool __sig_deliver(bool restartable, int sig, int si_code,
// signal handler. in that case you must use SA_NODEFER.
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
}
_spunlock(&__sig_lock);
__sig_unlock();
// setup the somewhat expensive information args
// only if they're requested by the user in sigaction()
@ -196,9 +196,9 @@ privileged bool __sig_handle(bool restartable, int sig, int si_code,
textwindows int __sig_raise(int sig, int si_code) {
int rc;
int candeliver;
_spinlock(&__sig_lock);
__sig_lock();
candeliver = !sigismember(&__sig.mask, sig);
_spunlock(&__sig_lock);
__sig_unlock();
switch (candeliver) {
case 1:
__sig_handle(false, sig, si_code, 0);
@ -213,26 +213,31 @@ textwindows int __sig_raise(int sig, int si_code) {
/**
* Enqueues generic signal for delivery on New Technology.
* @return 0 if enqueued, otherwise -1 w/ errno
* @return 0 on success, otherwise -1 w/ errno
* @threadsafe
*/
textwindows int __sig_add(int sig, int si_code) {
int rc;
struct Signal *mem;
if (1 <= sig && sig <= NSIG) {
STRACE("enqueuing %G", sig);
_spinlock(&__sig_lock);
++__sig_count;
if ((mem = __sig_alloc())) {
mem->sig = sig;
mem->si_code = si_code;
mem->next = __sig.queue;
__sig.queue = mem;
__sig_lock();
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
STRACE("ignoring %G", sig);
rc = 0;
} else {
rc = enomem();
STRACE("enqueuing %G", sig);
++__sig_count;
if ((mem = __sig_alloc())) {
mem->sig = sig;
mem->si_code = si_code;
mem->next = __sig.queue;
__sig.queue = mem;
rc = 0;
} else {
rc = enomem();
}
}
_spunlock(&__sig_lock);
__sig_unlock();
} else {
rc = einval();
}

View file

@ -21,6 +21,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h"
@ -448,9 +449,9 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
if (sig == SIGKILL || sig == SIGSTOP) {
rc = einval();
} else {
_spinlock(&__sig_lock);
__sig_lock();
rc = __sigaction(sig, act, oldact);
_spunlock(&__sig_lock);
__sig_unlock();
}
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig,
DescribeSigaction(buf[0], sizeof(buf[0]), 0, act),

30
libc/calls/siglock.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/spinlock.h"
void __sig_lock(void) {
_spinlock(&__sig_lock_obj);
}
void __sig_unlock(void) {
_spunlock(&__sig_lock_obj);
}

View file

@ -5,7 +5,7 @@ COSMOPOLITAN_C_START_
hidden extern int __vforked;
hidden extern int __fds_lock;
hidden extern int __sig_lock;
hidden extern int __sig_lock_obj;
hidden extern bool __time_critical;
hidden extern unsigned __sighandrvas[NSIG];
hidden extern unsigned __sighandflags[NSIG];

View file

@ -18,6 +18,7 @@ int sys_fdatasync_nt(int) hidden;
int sys_flock_nt(int, int) hidden;
int sys_fork_nt(void) hidden;
int sys_ftruncate_nt(int64_t, uint64_t) hidden;
int sys_getloadavg_nt(double *, int) hidden;
int sys_getppid_nt(void) hidden;
int sys_getpriority_nt(int) hidden;
int sys_getsetpriority_nt(int, int, int, int (*)(int));

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/loadavg.internal.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/accounting.h"
@ -33,9 +32,6 @@ textwindows int sys_sysinfo_nt(struct sysinfo *info) {
info->totalram = memstat.ullTotalPhys;
info->freeram = memstat.ullAvailPhys;
info->procs = sysinfo.dwNumberOfProcessors;
info->loads[0] = __ntloadavg[0] * 65536;
info->loads[1] = __ntloadavg[1] * 65536;
info->loads[2] = __ntloadavg[2] * 65536;
info->mem_unit = 1;
return 0;
} else {