Make improvements

- Clean up sigaction() code
- Add a port scanner example
- Introduce a ParseCidr() API
- Clean up our futex abstraction code
- Fix a harmless integer overflow in ParseIp()
- Use kernel semaphores on NetBSD to make threads much faster
This commit is contained in:
Justine Tunney 2022-11-07 02:22:09 -08:00
parent 539bddce8c
commit c995838e5c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
107 changed files with 1085 additions and 492 deletions

127
examples/portscan.c Normal file
View file

@ -0,0 +1,127 @@
#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/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/timeval.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "net/http/ip.h"
/**
* @fileoverview fast local network port scanner, e.g.
*
* make -j8 o//examples/portscan.com
* o//examples/portscan.com 10.10.10.0/24 22
*/
const char *FormatIp(char buf[16], uint32_t ip) {
snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip);
return buf;
}
#define FormatIp(x) FormatIp(alloca(16), x)
int main(int argc, char *argv[]) {
int port;
struct Cidr in;
uint32_t netmask;
const char *status;
struct timeval timeout;
uint32_t network_address;
uint32_t last_host_address;
uint32_t first_host_address;
if (argc != 3) {
PrintUsage:
fprintf(stderr,
"usage: %s IP/CIDR PORT\n"
"example: %s 192.168.0.0/24 22\n",
argv[0], argv[0]);
return 1;
}
in = ParseCidr(argv[1], -1);
if (in.addr == -1) {
fprintf(stderr, "error: bad ip/cidr\n");
goto PrintUsage;
}
port = atoi(argv[2]);
if (!(1 <= port && port <= 65535)) {
fprintf(stderr, "error: bad port\n");
goto PrintUsage;
}
if (in.cidr > 30) {
fprintf(stderr, "error: maximum supported cidr is 30\n");
goto PrintUsage;
}
if (in.cidr < 22) {
fprintf(stderr, "error: minimum cidr support right now is 22\n");
goto PrintUsage;
}
netmask = -1u << (32 - in.cidr);
network_address = in.addr & netmask;
first_host_address = network_address + 1;
last_host_address = (network_address | ~netmask) - 1;
assert(last_host_address > first_host_address);
assert(last_host_address - first_host_address < 1024);
fprintf(stderr, "scanning %s through %s\n", FormatIp(first_host_address),
FormatIp(last_host_address));
timeout = timeval_frommillis(100);
for (int64_t ip = first_host_address; ip <= last_host_address; ++ip) {
if (!fork()) {
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(3, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
setsockopt(3, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
if (!connect(3,
(struct sockaddr *)&(struct sockaddr_in){
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(ip),
.sin_port = htons(port),
},
sizeof(struct sockaddr_in))) {
status = "open";
} else if (errno == ECONNREFUSED) {
status = "closed";
} else if (errno != EINPROGRESS) {
status = _strerrno(errno);
} else {
status = 0;
}
if (status) {
printf("%-15s %s\n", FormatIp(ip), status);
}
_Exit(0);
}
}
for (;;) {
if (wait(0) == -1 && errno == ECHILD) {
break;
}
}
}

View file

@ -184,7 +184,10 @@ o/$(MODE)/libc/calls/timespec_tomicros.o \
o/$(MODE)/libc/calls/timespec_totimeval.o \
o/$(MODE)/libc/calls/timespec_fromnanos.o \
o/$(MODE)/libc/calls/timespec_frommillis.o \
o/$(MODE)/libc/calls/timespec_frommicros.o: private \
o/$(MODE)/libc/calls/timespec_frommicros.o \
o/$(MODE)/libc/calls/timeval_tomillis.o \
o/$(MODE)/libc/calls/timeval_frommillis.o \
o/$(MODE)/libc/calls/timeval_frommicros.o: private \
OVERRIDE_CFLAGS += \
-O2

View file

@ -22,11 +22,6 @@
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction-linux.internal.h"
#include "libc/calls/struct/sigaction-netbsd.h"
#include "libc/calls/struct/sigaction-openbsd.internal.h"
#include "libc/calls/struct/sigaction-xnu.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigaction.internal.h"
#include "libc/calls/struct/siginfo.internal.h"
@ -46,6 +41,7 @@
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
@ -58,110 +54,111 @@ STATIC_YOINK("strsignal"); // for kprintf()
#define SA_RESTORER 0x04000000
#ifndef SWITCHEROO
#define SWITCHEROO(S1, S2, A, B, C, D) \
do { \
autotype((S2).A) a = (typeof((S2).A))(S1).A; \
autotype((S2).B) b = (typeof((S2).B))(S1).B; \
autotype((S2).C) c = (typeof((S2).C))(S1).C; \
typeof((S2).D) d; \
bzero(&d, sizeof(d)); \
memcpy(&d, &((S1).D), MIN(sizeof(d), sizeof((S1).D))); \
(S2).A = a; \
(S2).B = b; \
(S2).C = c; \
bzero(&((S2).D), sizeof((S2).D)); \
memcpy(&((S2).D), &d, MIN(sizeof(d), sizeof((S2).D))); \
} while (0);
#endif
union metasigaction {
struct sigaction cosmo;
struct sigaction_linux linux;
struct sigaction_freebsd freebsd;
struct sigaction_openbsd openbsd;
struct sigaction_netbsd netbsd;
struct sigaction_xnu_in xnu_in;
struct sigaction_xnu_out xnu_out;
};
void __sigenter_xnu(int, struct siginfo *, void *) hidden;
void __sigenter_linux(int, struct siginfo *, void *) hidden;
void __sigenter_netbsd(int, struct siginfo *, void *) hidden;
void __sigenter_freebsd(int, struct siginfo *, void *) hidden;
void __sigenter_openbsd(int, struct siginfo *, void *) hidden;
static void sigaction_cosmo2native(union metasigaction *sa) {
void *handler;
uint64_t flags;
void *restorer;
uint32_t mask[4];
if (!sa) return;
switch (__hostos) {
case _HOSTLINUX:
SWITCHEROO(sa->cosmo, sa->linux, sa_handler, sa_flags, sa_restorer,
sa_mask);
break;
case _HOSTXNU:
SWITCHEROO(sa->cosmo, sa->xnu_in, sa_handler, sa_flags, sa_restorer,
sa_mask);
break;
case _HOSTFREEBSD:
SWITCHEROO(sa->cosmo, sa->freebsd, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
case _HOSTOPENBSD:
SWITCHEROO(sa->cosmo, sa->openbsd, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
case _HOSTNETBSD:
SWITCHEROO(sa->cosmo, sa->netbsd, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
default:
break;
flags = sa->cosmo.sa_flags;
handler = sa->cosmo.sa_handler;
restorer = sa->cosmo.sa_restorer;
mask[0] = sa->cosmo.sa_mask.__bits[0];
mask[1] = sa->cosmo.sa_mask.__bits[0] >> 32;
mask[2] = sa->cosmo.sa_mask.__bits[1];
mask[3] = sa->cosmo.sa_mask.__bits[1] >> 32;
if (IsLinux()) {
sa->linux.sa_flags = flags;
sa->linux.sa_handler = handler;
sa->linux.sa_restorer = restorer;
sa->linux.sa_mask[0] = mask[0];
sa->linux.sa_mask[1] = mask[1];
} else if (IsXnu()) {
sa->xnu_in.sa_flags = flags;
sa->xnu_in.sa_handler = handler;
sa->xnu_in.sa_restorer = restorer;
sa->xnu_in.sa_mask[0] = mask[0];
} else if (IsFreebsd()) {
sa->freebsd.sa_flags = flags;
sa->freebsd.sa_handler = handler;
sa->freebsd.sa_mask[0] = mask[0];
sa->freebsd.sa_mask[1] = mask[1];
sa->freebsd.sa_mask[2] = mask[2];
sa->freebsd.sa_mask[3] = mask[3];
} else if (IsOpenbsd()) {
sa->openbsd.sa_flags = flags;
sa->openbsd.sa_handler = handler;
sa->openbsd.sa_mask[0] = mask[0];
} else if (IsNetbsd()) {
sa->netbsd.sa_flags = flags;
sa->netbsd.sa_handler = handler;
sa->netbsd.sa_mask[0] = mask[0];
sa->netbsd.sa_mask[1] = mask[1];
sa->netbsd.sa_mask[2] = mask[2];
sa->netbsd.sa_mask[3] = mask[3];
}
}
static void sigaction_native2cosmo(union metasigaction *sa) {
void *handler;
uint64_t flags;
void *restorer = 0;
uint32_t mask[4] = {0};
if (!sa) return;
switch (__hostos) {
case _HOSTLINUX:
SWITCHEROO(sa->linux, sa->cosmo, sa_handler, sa_flags, sa_restorer,
sa_mask);
break;
case _HOSTXNU:
SWITCHEROO(sa->xnu_out, sa->cosmo, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
case _HOSTFREEBSD:
SWITCHEROO(sa->freebsd, sa->cosmo, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
case _HOSTOPENBSD:
SWITCHEROO(sa->openbsd, sa->cosmo, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
case _HOSTNETBSD:
SWITCHEROO(sa->netbsd, sa->cosmo, sa_handler, sa_flags, sa_flags,
sa_mask);
break;
default:
break;
if (IsLinux()) {
flags = sa->linux.sa_flags;
handler = sa->linux.sa_handler;
restorer = sa->linux.sa_restorer;
mask[0] = sa->linux.sa_mask[0];
mask[1] = sa->linux.sa_mask[1];
} else if (IsXnu()) {
flags = sa->xnu_out.sa_flags;
handler = sa->xnu_out.sa_handler;
mask[0] = sa->xnu_out.sa_mask[0];
} else if (IsFreebsd()) {
flags = sa->freebsd.sa_flags;
handler = sa->freebsd.sa_handler;
mask[0] = sa->freebsd.sa_mask[0];
mask[1] = sa->freebsd.sa_mask[1];
mask[2] = sa->freebsd.sa_mask[2];
mask[3] = sa->freebsd.sa_mask[3];
} else if (IsOpenbsd()) {
flags = sa->openbsd.sa_flags;
handler = sa->openbsd.sa_handler;
mask[0] = sa->openbsd.sa_mask[0];
} else if (IsNetbsd()) {
flags = sa->netbsd.sa_flags;
handler = sa->netbsd.sa_handler;
mask[0] = sa->netbsd.sa_mask[0];
mask[1] = sa->netbsd.sa_mask[1];
mask[2] = sa->netbsd.sa_mask[2];
mask[3] = sa->netbsd.sa_mask[3];
} else {
return;
}
sa->cosmo.sa_flags = flags;
sa->cosmo.sa_handler = handler;
sa->cosmo.sa_restorer = restorer;
sa->cosmo.sa_mask.__bits[0] = mask[0] | (uint64_t)mask[1] << 32;
sa->cosmo.sa_mask.__bits[1] = mask[2] | (uint64_t)mask[3] << 32;
}
static int __sigaction(int sig, const struct sigaction *act,
struct sigaction *oldact) {
_Static_assert((sizeof(struct sigaction) > sizeof(struct sigaction_linux) &&
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_in) &&
sizeof(struct sigaction) > sizeof(struct sigaction_xnu_out) &&
sizeof(struct sigaction) > sizeof(struct sigaction_freebsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_openbsd) &&
sizeof(struct sigaction) > sizeof(struct sigaction_netbsd)),
"sigaction cosmo abi needs tuning");
_Static_assert(
(sizeof(struct sigaction) >= sizeof(struct sigaction_linux) &&
sizeof(struct sigaction) >= sizeof(struct sigaction_xnu_in) &&
sizeof(struct sigaction) >= sizeof(struct sigaction_xnu_out) &&
sizeof(struct sigaction) >= sizeof(struct sigaction_freebsd) &&
sizeof(struct sigaction) >= sizeof(struct sigaction_openbsd) &&
sizeof(struct sigaction) >= sizeof(struct sigaction_netbsd)),
"sigaction cosmo abi needs tuning");
int64_t arg4, arg5;
int rc, rva, oldrva;
sigaction_f sigenter;
struct sigaction *ap, copy;
if (IsMetal()) return enosys(); /* TODO: Signals on Metal */
if (!(0 < sig && sig < NSIG)) return einval();
if (!(1 <= sig && sig <= _NSIG)) return einval();
if (sig == SIGKILL || sig == SIGSTOP) return einval();
if (IsAsan() && ((act && !__asan_is_valid(act, sizeof(*act))) ||
(oldact && !__asan_is_valid(oldact, sizeof(*oldact))))) {
@ -184,18 +181,23 @@ static int __sigaction(int sig, const struct sigaction *act,
if (act) {
memcpy(&copy, act, sizeof(copy));
ap = &copy;
if (IsXnu()) {
if (IsLinux()) {
if (!(ap->sa_flags & SA_RESTORER)) {
ap->sa_flags |= SA_RESTORER;
ap->sa_restorer = &__restore_rt;
}
if (IsWsl1()) {
sigenter = __sigenter_wsl;
} else {
sigenter = ap->sa_sigaction;
}
} else if (IsXnu()) {
ap->sa_restorer = (void *)&__sigenter_xnu;
sigenter = __sigenter_xnu;
// mitigate Rosetta signal handling strangeness
// https://github.com/jart/cosmopolitan/issues/455
ap->sa_flags |= SA_SIGINFO;
} else if (IsLinux()) {
if (!(ap->sa_flags & SA_RESTORER)) {
ap->sa_flags |= SA_RESTORER;
ap->sa_restorer = &__restore_rt;
}
sigenter = __sigenter_linux;
} else if (IsNetbsd()) {
sigenter = __sigenter_netbsd;
} else if (IsFreebsd()) {

View file

@ -20,7 +20,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-freebsd.internal.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
@ -51,7 +50,7 @@ privileged void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
g.uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
g.uc.uc_stack.ss_size = ctx->uc_stack.ss_size;
g.uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags;
__repmovsb(&g.uc.uc_sigmask, &ctx->uc_sigmask,
__repmovsb(&g.uc.uc_sigmask, ctx->uc_sigmask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
g.uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8;
g.uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9;
@ -82,7 +81,7 @@ privileged void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
ctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
ctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
ctx->uc_flags = g.uc.uc_flags;
__repmovsb(&ctx->uc_sigmask, &g.uc.uc_sigmask,
__repmovsb(ctx->uc_sigmask, &g.uc.uc_sigmask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
ctx->uc_mcontext.mc_rdi = g.uc.uc_mcontext.rdi;
ctx->uc_mcontext.mc_rsi = g.uc.uc_mcontext.rsi;

View file

@ -28,8 +28,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
privileged void __sigenter_linux(int sig, struct siginfo *info,
ucontext_t *ctx) {
privileged void __sigenter_wsl(int sig, struct siginfo *info, ucontext_t *ctx) {
int i, rva, flags;
rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) {

View file

@ -20,7 +20,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo-netbsd.internal.h"

View file

@ -20,7 +20,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo-meta.internal.h"
#include "libc/calls/struct/siginfo-openbsd.internal.h"

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigset_freebsd {
uint32_t sig[4];
};
struct sigaction_freebsd {
intptr_t sa_handler;
uint32_t sa_flags;
struct sigset_freebsd sa_mask;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_ */

View file

@ -1,17 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigset_linux {
uint32_t sig[2];
};
struct sigaction_linux {
intptr_t sa_handler;
uint64_t sa_flags;
void (*sa_restorer)(void);
struct sigset_linux sa_mask;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_ */

View file

@ -1,18 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_NETBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_NETBSD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sigset_netbsd {
uint32_t sig[4];
};
struct sigaction_netbsd {
intptr_t sa_handler;
struct sigset_netbsd sa_mask;
uint32_t sa_flags;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_NETBSD_H_ */

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct sigset_openbsd {
uint32_t sig[1];
};
struct sigaction_openbsd {
intptr_t sa_handler;
struct sigset_openbsd sa_mask;
int32_t sa_flags;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_ */

View file

@ -1,27 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct __darwin_ucontext;
struct __darwin_siginfo;
struct sigset_xnu {
uint32_t sig[1];
};
struct sigaction_xnu_in {
intptr_t sa_handler;
void (*sa_restorer)(void *, int, int, const struct __darwin_siginfo *,
const struct __darwin_ucontext *);
struct sigset_xnu sa_mask;
int32_t sa_flags;
};
struct sigaction_xnu_out {
intptr_t sa_handler;
struct sigset_xnu sa_mask;
int32_t sa_flags;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_ */

View file

@ -20,7 +20,6 @@ struct sigaction { /* cosmo abi */
uint64_t sa_flags;
void (*sa_restorer)(void);
struct sigset sa_mask;
int64_t __pad;
};
sighandler_t signal(int, sighandler_t);

View file

@ -1,10 +1,65 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_INTERNAL_H_
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/mem/alloca.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sigaction_linux {
void *sa_handler;
uint64_t sa_flags;
void *sa_restorer;
uint32_t sa_mask[2];
};
struct sigaction_freebsd {
void *sa_handler;
uint32_t sa_flags;
uint32_t sa_mask[4];
};
struct sigaction_openbsd {
void *sa_handler;
uint32_t sa_mask[1];
uint32_t sa_flags;
};
struct sigaction_netbsd {
void *sa_handler;
uint32_t sa_mask[4];
uint32_t sa_flags;
};
struct sigaction_xnu_in {
void *sa_handler;
void *sa_restorer;
uint32_t sa_mask[1];
uint32_t sa_flags;
};
struct sigaction_xnu_out {
void *sa_handler;
uint32_t sa_mask[1];
uint32_t sa_flags;
};
union metasigaction {
struct sigaction cosmo;
struct sigaction_linux linux;
struct sigaction_freebsd freebsd;
struct sigaction_openbsd openbsd;
struct sigaction_netbsd netbsd;
struct sigaction_xnu_in xnu_in;
struct sigaction_xnu_out xnu_out;
};
void __sigenter_xnu(int, struct siginfo *, void *) hidden;
void __sigenter_wsl(int, struct siginfo *, void *) hidden;
void __sigenter_netbsd(int, struct siginfo *, void *) hidden;
void __sigenter_freebsd(int, struct siginfo *, void *) hidden;
void __sigenter_openbsd(int, struct siginfo *, void *) hidden;
const char *DescribeSigaction(char[256], int, const struct sigaction *);
#define DescribeSigaction(rc, sa) DescribeSigaction(alloca(256), rc, sa)

View file

@ -1,7 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_INTERNAL_H_
#include "libc/calls/struct/sigaction-xnu.internal.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/mem/alloca.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)

View file

@ -14,12 +14,13 @@ int sys_clock_gettime_nt(int, struct timespec *) hidden;
int sys_clock_gettime_xnu(int, struct timespec *) hidden;
int sys_clock_nanosleep(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_nt(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_xnu(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_openbsd(int, int, const struct timespec *, struct timespec *) hidden;
int sys_clock_nanosleep_xnu(int, int, const struct timespec *, struct timespec *) hidden;
int sys_futimens(int, const struct timespec[2]) hidden;
int sys_nanosleep(const struct timespec *, struct timespec *) hidden;
int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden;
int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden;
int sys_sem_timedwait(int64_t, const struct timespec *) hidden;
int sys_utimensat(int, const char *, const struct timespec[2], int) hidden;
int sys_utimensat_nt(int, const char *, const struct timespec[2], int) hidden;
int sys_utimensat_xnu(int, const char *, const struct timespec[2], int) hidden;

View file

@ -17,6 +17,8 @@ int lutimes(const char *, const struct timeval[2]);
int utimes(const char *, const struct timeval[2]);
int timeval_cmp(struct timeval, struct timeval) pureconst;
struct timeval timeval_frommicros(int64_t) pureconst;
struct timeval timeval_frommillis(int64_t) pureconst;
struct timeval timeval_add(struct timeval, struct timeval) pureconst;
struct timeval timeval_sub(struct timeval, struct timeval) pureconst;
struct timeval timespec_totimeval(struct timespec) pureconst;

View file

@ -1,6 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_FREEBSD_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_FREEBSD_INTERNAL_H_
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -52,7 +51,7 @@ struct mcontext_freebsd {
};
struct ucontext_freebsd {
struct sigset_freebsd uc_sigmask;
uint32_t uc_sigmask[4];
struct mcontext_freebsd uc_mcontext;
struct ucontext_freebsd *uc_link;
struct stack_freebsd uc_stack;

View file

@ -83,6 +83,15 @@ i32 sys_pivot_root(const char *, const char *) hidden;
i32 sys_pledge(const char *, const char *) hidden;
i32 sys_posix_openpt(i32) hidden;
i32 sys_renameat(i32, const char *, i32, const char *) hidden;
i32 sys_sem_close(i64) hidden;
i32 sys_sem_destroy(i64) hidden;
i32 sys_sem_getvalue(i64, u32 *) hidden;
i32 sys_sem_init(u32, i64 *) hidden;
i32 sys_sem_open(const char *, int, u32, i64 *) hidden;
i32 sys_sem_post(i64) hidden;
i32 sys_sem_trywait(i64) hidden;
i32 sys_sem_unlink(const char *) hidden;
i32 sys_sem_wait(i64) hidden;
i32 sys_setfsgid(i32) hidden;
i32 sys_setfsuid(i32) hidden;
i32 sys_setgid(i32) hidden;

View file

@ -22,8 +22,9 @@
/**
* Converts timespec to scalar.
*
* This function will detect overflow in which case `INT64_MAX` or
* `INT64_MIN` may be returned. The `errno` variable isn't changed.
. * This returns the absolute number of nanoseconds in a timespec. If
* overflow happens, then `INT64_MAX` or `INT64_MIN` is returned. The
* `errno` variable isn't changed.
*
* @return 64-bit integer holding nanoseconds since epoch
*/

View file

@ -0,0 +1,29 @@
/*-*- 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"
/**
* Converts timeval interval from microseconds.
*/
struct timeval timeval_frommicros(int64_t x) {
struct timeval tv;
tv.tv_sec = x / 1000000;
tv.tv_usec = x % 1000000;
return tv;
}

View file

@ -0,0 +1,29 @@
/*-*- 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"
/**
* Converts timeval interval from milliseconds.
*/
struct timeval timeval_frommillis(int64_t x) {
struct timeval tv;
tv.tv_sec = x / 1000;
tv.tv_usec = x % 1000 * 1000;
return tv;
}

View file

@ -0,0 +1,41 @@
/*-*- 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"
#include "libc/limits.h"
/**
* Converts timeval to scalar.
*
* This returns the absolute number of microseconds in a timeval. If
* overflow happens, then `INT64_MAX` or `INT64_MIN` is returned. The
* `errno` variable isn't changed.
*
* @return 64-bit integer holding microseconds since epoch
*/
int64_t timeval_tomicros(struct timeval x) {
int64_t ns;
if (!__builtin_mul_overflow(x.tv_sec, 1000000ul, &ns) &&
!__builtin_add_overflow(ns, x.tv_usec, &ns)) {
return ns;
} else if (x.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
}
}

View file

@ -0,0 +1,56 @@
/*-*- 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"
#include "libc/limits.h"
/**
* Reduces `ts` from 1e-6 to 1e-3 granularity w/ ceil rounding.
*
* This function returns the absolute number of milliseconds in a
* timeval. Ceiling rounding is used. For example, if `ts` is one
* nanosecond, then one millisecond will be returned. Ceil rounding is
* needed by many interfaces, e.g. setitimer(), because the zero
* timestamp has a valial meaning.
*
* This function also detects overflow in which case `INT64_MAX` or
* `INT64_MIN` may be returned. The `errno` variable isn't changed.
*
* @return 64-bit scalar milliseconds since epoch
*/
int64_t timeval_tomillis(struct timeval ts) {
int64_t ms;
// reduce precision from micros to millis
if (ts.tv_usec <= 999000) {
ts.tv_usec = (ts.tv_usec + 999) / 1000;
} else {
ts.tv_usec = 0;
if (ts.tv_sec < INT64_MAX) {
ts.tv_sec += 1;
}
}
// convert to scalar result
if (!__builtin_mul_overflow(ts.tv_sec, 1000ul, &ms) &&
!__builtin_add_overflow(ms, ts.tv_usec, &ms)) {
return ms;
} else if (ts.tv_sec < 0) {
return INT64_MIN;
} else {
return INT64_MAX;
}
}

View file

@ -608,10 +608,10 @@ typedef struct {
#endif
#endif
#define notpossible \
do { \
asm("ud2\n\tnop"); \
unreachable; \
#define notpossible \
do { \
asm("nop\n\tud2\n\tnop"); \
unreachable; \
} while (0)
#define donothing \

View file

@ -21,6 +21,7 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/str/str.h"
const char *(DescribeTimespec)(char buf[45], int rc,
const struct timespec *ts) {
@ -30,7 +31,11 @@ const char *(DescribeTimespec)(char buf[45], int rc,
(IsAsan() && !__asan_is_valid(ts, sizeof(*ts)))) {
ksnprintf(buf, 45, "%p", ts);
} else {
ksnprintf(buf, 45, "{%ld, %ld}", ts->tv_sec, ts->tv_nsec);
if (!memcmp(ts, &timespec_max, sizeof(*ts))) {
strcpy(buf, "timespec_max");
} else {
ksnprintf(buf, 45, "{%ld, %ld}", ts->tv_sec, ts->tv_nsec);
}
}
return buf;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/likely.h"
#include "libc/thread/tls.h"
/**
@ -36,9 +37,9 @@
*/
int gettid(void) {
int tid;
if (__tls_enabled && !__vforked) {
tid = atomic_load_explicit(&__get_tls()->tib_tid, memory_order_relaxed);
if (tid > 0) {
if (VERY_LIKELY(__tls_enabled && !__vforked)) {
tid = atomic_load_explicit(&__get_tls()->tib_tid, memory_order_acquire);
if (VERY_LIKELY(tid > 0)) {
return tid;
}
}

0
libc/intrin/intrin.h Executable file
View file

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_close,0x0fafff190210dfff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_destroy,0x0fffff198fffffff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_getvalue,0x0fefff197fffffff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_init,0x0f7fff194fffffff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_open,0x0f8fff195210cfff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_post,0x0fbfff1912111fff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_timedwait,0x900fff9b9fffffff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_trywait,0x0fdfff1932110fff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_unlink,0x0f9fff196210efff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_wait,0x8fcfff992290ffff,globl

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_sem_wait_nocancel,0xfffffffff21a4fff,globl

View file

@ -2094,44 +2094,44 @@ syscon nr __NR_ktrace 0xfff 0xfff 0x002d 0x002d 0x02d 0xfff
# unilateral undocumented errnos
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon junkerr ECHRNG 44 0 0 0 0 0
syscon junkerr EL2NSYNC 45 0 0 0 0 0
syscon junkerr EL3HLT 46 0 0 0 0 0
syscon junkerr EL3RST 47 0 0 0 0 0
syscon junkerr ELNRNG 48 0 0 0 0 0
syscon junkerr EUNATCH 49 0 0 0 0 0
syscon junkerr ENOCSI 50 0 0 0 0 0
syscon junkerr EL2HLT 51 0 0 0 0 0
syscon junkerr EBADE 52 0 0 0 0 0
syscon junkerr EBADR 53 0 0 0 0 0
syscon junkerr EXFULL 54 0 0 0 0 0
syscon junkerr ENOANO 55 0 0 0 0 0
syscon junkerr EBADRQC 56 0 0 0 0 0
syscon junkerr EBADSLT 57 0 0 0 0 0
syscon junkerr ENOPKG 65 0 0 0 0 0
syscon junkerr EADV 68 0 0 0 0 0
syscon junkerr ESRMNT 69 0 0 0 0 0
syscon junkerr ECOMM 70 0 0 0 0 0
syscon junkerr EDOTDOT 73 0 0 0 0 0
syscon junkerr ENOTUNIQ 76 0 0 0 0 0
syscon junkerr EREMCHG 78 0 0 0 0 0
syscon junkerr ELIBACC 79 0 0 0 0 0
syscon junkerr ELIBBAD 80 0 0 0 0 0
syscon junkerr ELIBSCN 81 0 0 0 0 0
syscon junkerr ELIBMAX 82 0 0 0 0 0
syscon junkerr ELIBEXEC 83 0 0 0 0 0
syscon junkerr ESTRPIPE 86 0 0 0 0 0
syscon junkerr EUCLEAN 117 0 0 0 0 0
syscon junkerr ENOTNAM 118 0 0 0 0 0
syscon junkerr ENAVAIL 119 0 0 0 0 0
syscon junkerr EISNAM 120 0 0 0 0 0
syscon junkerr EREMOTEIO 121 0 0 0 0 0
syscon junkerr ENOKEY 126 0 0 0 0 0
syscon junkerr EKEYEXPIRED 127 0 0 0 0 0
syscon junkerr EKEYREVOKED 128 0 0 0 0 0
syscon junkerr EKEYREJECTED 129 0 0 0 0 0
syscon junkerr ERFKILL 132 0 0 0 0 0
syscon junkerr EHWPOISON 133 0 0 0 0 0
syscon junkerr ECHRNG 44 -1 -1 -1 -1 -1
syscon junkerr EL2NSYNC 45 -1 -1 -1 -1 -1
syscon junkerr EL3HLT 46 -1 -1 -1 -1 -1
syscon junkerr EL3RST 47 -1 -1 -1 -1 -1
syscon junkerr ELNRNG 48 -1 -1 -1 -1 -1
syscon junkerr EUNATCH 49 -1 -1 -1 -1 -1
syscon junkerr ENOCSI 50 -1 -1 -1 -1 -1
syscon junkerr EL2HLT 51 -1 -1 -1 -1 -1
syscon junkerr EBADE 52 -1 -1 -1 -1 -1
syscon junkerr EBADR 53 -1 -1 -1 -1 -1
syscon junkerr EXFULL 54 -1 -1 -1 -1 -1
syscon junkerr ENOANO 55 -1 -1 -1 -1 -1
syscon junkerr EBADRQC 56 -1 -1 -1 -1 -1
syscon junkerr EBADSLT 57 -1 -1 -1 -1 -1
syscon junkerr ENOPKG 65 -1 -1 -1 -1 -1
syscon junkerr EADV 68 -1 -1 -1 -1 -1
syscon junkerr ESRMNT 69 -1 -1 -1 -1 -1
syscon junkerr ECOMM 70 -1 -1 -1 -1 -1
syscon junkerr EDOTDOT 73 -1 -1 -1 -1 -1
syscon junkerr ENOTUNIQ 76 -1 -1 -1 -1 -1
syscon junkerr EREMCHG 78 -1 -1 -1 -1 -1
syscon junkerr ELIBACC 79 -1 -1 -1 -1 -1
syscon junkerr ELIBBAD 80 -1 -1 -1 -1 -1
syscon junkerr ELIBSCN 81 -1 -1 -1 -1 -1
syscon junkerr ELIBMAX 82 -1 -1 -1 -1 -1
syscon junkerr ELIBEXEC 83 -1 -1 -1 -1 -1
syscon junkerr ESTRPIPE 86 -1 -1 -1 -1 -1
syscon junkerr EUCLEAN 117 -1 -1 -1 -1 -1
syscon junkerr ENOTNAM 118 -1 -1 -1 -1 -1
syscon junkerr ENAVAIL 119 -1 -1 -1 -1 -1
syscon junkerr EISNAM 120 -1 -1 -1 -1 -1
syscon junkerr EREMOTEIO 121 -1 -1 -1 -1 -1
syscon junkerr ENOKEY 126 -1 -1 -1 -1 -1
syscon junkerr EKEYEXPIRED 127 -1 -1 -1 -1 -1
syscon junkerr EKEYREVOKED 128 -1 -1 -1 -1 -1
syscon junkerr EKEYREJECTED 129 -1 -1 -1 -1 -1
syscon junkerr ERFKILL 132 -1 -1 -1 -1 -1
syscon junkerr EHWPOISON 133 -1 -1 -1 -1 -1
# arpanet fork combating human-induced exhaustion of our ipv4 address space
#

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EADV,68,0,0,0,0,0
.syscon junkerr,EADV,68,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EBADE,52,0,0,0,0,0
.syscon junkerr,EBADE,52,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EBADR,53,0,0,0,0,0
.syscon junkerr,EBADR,53,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EBADRQC,56,0,0,0,0,0
.syscon junkerr,EBADRQC,56,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EBADSLT,57,0,0,0,0,0
.syscon junkerr,EBADSLT,57,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ECHRNG,44,0,0,0,0,0
.syscon junkerr,ECHRNG,44,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ECOMM,70,0,0,0,0,0
.syscon junkerr,ECOMM,70,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EDOTDOT,73,0,0,0,0,0
.syscon junkerr,EDOTDOT,73,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EHWPOISON,133,0,0,0,0,0
.syscon junkerr,EHWPOISON,133,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EISNAM,120,0,0,0,0,0
.syscon junkerr,EISNAM,120,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EKEYEXPIRED,127,0,0,0,0,0
.syscon junkerr,EKEYEXPIRED,127,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EKEYREJECTED,129,0,0,0,0,0
.syscon junkerr,EKEYREJECTED,129,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EKEYREVOKED,128,0,0,0,0,0
.syscon junkerr,EKEYREVOKED,128,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EL2HLT,51,0,0,0,0,0
.syscon junkerr,EL2HLT,51,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EL2NSYNC,45,0,0,0,0,0
.syscon junkerr,EL2NSYNC,45,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EL3HLT,46,0,0,0,0,0
.syscon junkerr,EL3HLT,46,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EL3RST,47,0,0,0,0,0
.syscon junkerr,EL3RST,47,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ELIBACC,79,0,0,0,0,0
.syscon junkerr,ELIBACC,79,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ELIBBAD,80,0,0,0,0,0
.syscon junkerr,ELIBBAD,80,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ELIBEXEC,83,0,0,0,0,0
.syscon junkerr,ELIBEXEC,83,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ELIBMAX,82,0,0,0,0,0
.syscon junkerr,ELIBMAX,82,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ELIBSCN,81,0,0,0,0,0
.syscon junkerr,ELIBSCN,81,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ELNRNG,48,0,0,0,0,0
.syscon junkerr,ELNRNG,48,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENAVAIL,119,0,0,0,0,0
.syscon junkerr,ENAVAIL,119,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENOANO,55,0,0,0,0,0
.syscon junkerr,ENOANO,55,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENOCSI,50,0,0,0,0,0
.syscon junkerr,ENOCSI,50,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENOKEY,126,0,0,0,0,0
.syscon junkerr,ENOKEY,126,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENOPKG,65,0,0,0,0,0
.syscon junkerr,ENOPKG,65,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENOTNAM,118,0,0,0,0,0
.syscon junkerr,ENOTNAM,118,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ENOTUNIQ,76,0,0,0,0,0
.syscon junkerr,ENOTUNIQ,76,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EREMCHG,78,0,0,0,0,0
.syscon junkerr,EREMCHG,78,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EREMOTEIO,121,0,0,0,0,0
.syscon junkerr,EREMOTEIO,121,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ERFKILL,132,0,0,0,0,0
.syscon junkerr,ERFKILL,132,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ESRMNT,69,0,0,0,0,0
.syscon junkerr,ESRMNT,69,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,ESTRPIPE,86,0,0,0,0,0
.syscon junkerr,ESTRPIPE,86,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EUCLEAN,117,0,0,0,0,0
.syscon junkerr,EUCLEAN,117,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EUNATCH,49,0,0,0,0,0
.syscon junkerr,EUNATCH,49,-1,-1,-1,-1,-1

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon junkerr,EXFULL,54,0,0,0,0,0
.syscon junkerr,EXFULL,54,-1,-1,-1,-1,-1

View file

@ -428,6 +428,18 @@ scall sys_issetugid 0xfff0fd0fd2147fff globl hidden
scall sys_minherit 0x1110fa0fa20fafff globl # no wrapper
scall sys_pathconf 0x0bf0bf0bf20bffff globl # no wrapper
scall sys_sysctl 0x0ca0ca0ca20cafff globl # no wrapper
#──────────────────XNU & FREEBSD & NETBSD────────────────────
scall sys_sem_init 0x0f7fff194fffffff globl
scall sys_sem_destroy 0x0fffff198fffffff globl
scall sys_sem_open 0x0f8fff195210cfff globl
scall sys_sem_close 0x0fafff190210dfff globl
scall sys_sem_unlink 0x0f9fff196210efff globl
scall sys_sem_post 0x0fbfff1912111fff globl
scall sys_sem_wait 0x8fcfff992290ffff globl
scall sys_sem_trywait 0x0fdfff1932110fff globl
scall sys_sem_timedwait 0x900fff9b9fffffff globl
scall sys_sem_wait_nocancel 0xfffffffff21a4fff globl # no wrapper
scall sys_sem_getvalue 0x0fefff197fffffff globl
#───────────────────────XNU & FREEBSD────────────────────────
scall sys_ntp_adjtime 0x0b0fff0b0220ffff globl # no wrapper
scall sys_ntp_gettime 0x1c0fff0f82210fff globl # no wrapper
@ -597,13 +609,6 @@ scall sys_bsdthread_register 0xfffffffff216efff globl hidden
#scall renameatx_np 0xfffffffff21e8fff globl
#scall searchfs 0xfffffffff20e1fff globl
#scall select_nocancel 0xfffffffff2197fff globl
#scall sem_close 0xfffffffff210dfff globl
#scall sem_open 0xfffffffff210cfff globl
#scall sem_post 0xfffffffff2111fff globl
#scall sem_trywait 0xfffffffff2110fff globl
#scall sem_unlink 0xfffffffff210efff globl
#scall sem_wait 0xfffffffff210ffff globl
#scall sem_wait_nocancel 0xfffffffff21a4fff globl
#scall sendmsg_nocancel 0xfffffffff2192fff globl
#scall sendmsg_x 0xfffffffff21e1fff globl
#scall sendto_nocancel 0xfffffffff219dfff globl
@ -711,16 +716,6 @@ scall getpagesize_freebsd 0xffffff040fffffff globl hidden
#scall kmq_timedreceive 0xffffff1cbfffffff globl
#scall kmq_timedsend 0xffffff1ccfffffff globl
#scall kmq_unlink 0xffffff1cefffffff globl
#scall ksem_close 0xffffff190fffffff globl
#scall ksem_destroy 0xffffff198fffffff globl
#scall ksem_getvalue 0xffffff197fffffff globl
#scall ksem_init 0xffffff194fffffff globl
#scall ksem_open 0xffffff195fffffff globl
#scall ksem_post 0xffffff191fffffff globl
#scall ksem_timedwait 0xffffff1b9fffffff globl
#scall ksem_trywait 0xffffff193fffffff globl
#scall ksem_unlink 0xffffff196fffffff globl
#scall ksem_wait 0xffffff192fffffff globl
#scall lchflags 0x130fff187fffffff globl
#scall lchmod 0x112fff112fffffff globl
#scall lgetfh 0xffffff0a0fffffff globl

View file

@ -51,10 +51,10 @@ int _pthread_cancel_sys(void) {
return ecanceled();
}
static void OnSigCancel(int sig, siginfo_t *si, void *ctx) {
static void OnSigThr(int sig, siginfo_t *si, void *ctx) {
ucontext_t *uc = ctx;
struct CosmoTib *tib = __get_tls();
struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread;
struct CosmoTib *t = __get_tls();
struct PosixThread *pt = (struct PosixThread *)t->tib_pthread;
if (pt && !(pt->flags & PT_NOCANCEL) &&
atomic_load_explicit(&pt->cancelled, memory_order_acquire)) {
sigaddset(&uc->uc_sigmask, sig);
@ -64,15 +64,14 @@ static void OnSigCancel(int sig, siginfo_t *si, void *ctx) {
} else if (pt->flags & PT_ASYNC) {
pthread_exit(PTHREAD_CANCELED);
} else {
__tkill(atomic_load_explicit(&tib->tib_tid, memory_order_relaxed), sig,
tib);
__tkill(atomic_load_explicit(&t->tib_tid, memory_order_relaxed), sig, t);
}
}
}
static void ListenForSigCancel(void) {
static void ListenForSigThr(void) {
struct sigaction sa;
sa.sa_sigaction = OnSigCancel;
sa.sa_sigaction = OnSigThr;
sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
memset(&sa.sa_mask, -1, sizeof(sa.sa_mask));
_npassert(!sigaction(SIGTHR, &sa, 0));
@ -262,7 +261,7 @@ errno_t pthread_cancel(pthread_t thread) {
int e, rc, tid;
static bool once;
struct PosixThread *pt;
if (!once) ListenForSigCancel(), once = true;
if (!once) ListenForSigThr(), once = true;
pt = (struct PosixThread *)thread;
switch (atomic_load_explicit(&pt->status, memory_order_acquire)) {
case kPosixThreadZombie:

View file

@ -35,13 +35,9 @@
* @param value is initial count of semaphore
* @return 0 on success, or -1 w/ errno
* @raise EINVAL if `value` exceeds `SEM_VALUE_MAX`
* @raise EPERM on OpenBSD if `pshared` is true
*/
int sem_init(sem_t *sem, int pshared, unsigned value) {
if (value > SEM_VALUE_MAX) return einval();
// OpenBSD MAP_ANONYMOUS|MAP_SHARED memory is kind of busted.
// The OpenBSD implementation of sem_init() also EPERMs here.
if (IsOpenbsd() && pshared) return eperm();
sem->sem_magic = SEM_MAGIC_UNNAMED;
atomic_store_explicit(&sem->sem_value, value, memory_order_relaxed);
sem->sem_pshared = !!pshared;

View file

@ -209,7 +209,7 @@ sem_t *sem_open(const char *name, int oflag, ...) {
sem = SEM_FAILED;
} else if (~oflag & O_EXCL) {
sem = s->sem;
atomic_fetch_add_explicit(&sem->sem_prefs, 1, memory_order_acquire);
atomic_fetch_add_explicit(&sem->sem_prefs, 1, memory_order_acq_rel);
++s->refs;
} else {
eexist();
@ -218,7 +218,7 @@ sem_t *sem_open(const char *name, int oflag, ...) {
} else if ((s = calloc(1, sizeof(struct Semaphore)))) {
if ((s->path = strdup(path))) {
if ((sem = sem_open_impl(path, oflag, mode, value)) != SEM_FAILED) {
atomic_fetch_add_explicit(&sem->sem_prefs, 1, memory_order_relaxed);
atomic_fetch_add_explicit(&sem->sem_prefs, 1, memory_order_acq_rel);
s->next = g_semaphores.list;
s->sem = sem;
s->refs = 1;
@ -260,7 +260,7 @@ int sem_close(sem_t *sem) {
sem_open_init();
sem_open_lock();
_npassert((s = sem_open_get(sem, &p)));
prefs = atomic_fetch_add_explicit(&sem->sem_prefs, -1, memory_order_release);
prefs = atomic_fetch_add_explicit(&sem->sem_prefs, -1, memory_order_acq_rel);
_npassert(s->refs > 0);
if ((unmap = !--s->refs)) {
_npassert(prefs > 0);

View file

@ -33,26 +33,6 @@ static void sem_delay(int n) {
for (i = 0; i != 1 << n; i++) donothing;
}
// TODO(jart): This should be abstracted by polyfill.
static struct timespec *sem_timeout(struct timespec *memory,
const struct timespec *abstime) {
struct timespec now;
if (!abstime) {
return 0;
} else if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
*memory = *abstime;
return memory;
} else {
now = timespec_real();
if (timespec_cmp(now, *abstime) > 0) {
*memory = (struct timespec){0};
} else {
*memory = timespec_sub(*abstime, now);
}
return memory;
}
}
static void sem_timedwait_cleanup(void *arg) {
sem_t *sem = arg;
_unassert(atomic_fetch_add_explicit(&sem->sem_waiters, -1,
@ -95,8 +75,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime) {
do {
if (!(v = atomic_load_explicit(&sem->sem_value, memory_order_relaxed))) {
rc = nsync_futex_wait_(&sem->sem_value, v, sem->sem_pshared,
sem_timeout(&ts, abstime));
rc = nsync_futex_wait_(&sem->sem_value, v, sem->sem_pshared, abstime);
if (rc == -EINTR || rc == -ECANCELED) {
errno = -rc;
rc = -1;

View file

@ -209,7 +209,6 @@ bool IsAcceptablePath(const char *, size_t);
bool IsAcceptableHost(const char *, size_t);
bool IsAcceptablePort(const char *, size_t);
bool IsReasonablePath(const char *, size_t);
int64_t ParseIp(const char *, size_t);
int ParseForwarded(const char *, size_t, uint32_t *, uint16_t *);
bool IsMimeType(const char *, size_t, const char *);
ssize_t Unchunk(struct HttpUnchunker *, char *, size_t, size_t *);

View file

@ -25,6 +25,13 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Cidr {
int64_t addr;
int cidr;
};
int64_t ParseIp(const char *, size_t);
struct Cidr ParseCidr(const char *, size_t);
bool IsDodIp(uint32_t);
bool IsArinIp(uint32_t);
bool IsRipeIp(uint32_t);

67
net/http/parsecidr.c Normal file
View file

@ -0,0 +1,67 @@
/*-*- 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/str/str.h"
#include "net/http/ip.h"
/**
* Parse IPv4 network address.
*
* For example, a router address might be `10.10.10.1/24` in which case
* the IP address word `0x0a0a0a01` would be returned, whose CIDR would
* be 24. That means your IP address is on a network with 24 bits which
* converts to a netmask `0xffffff00` by using `1u << (32 - res.cidr)`.
* You may specify the IP address portion as an integer. As an example,
* the value `168430081/1` would be the same as `10.10.10.1/1`
*
* @param n if -1 implies strlen
* @return ip is uint32 IPv4 address, or -1 on failure
* @return cidr is number of bits in network, on interval [1,32]; it
* defaults to 32; if the return ip is -1 then cidr is undefined
*/
struct Cidr ParseCidr(const char *s, size_t n) {
size_t i;
const char *p;
struct Cidr c;
if (n == -1) n = s ? strlen(s) : 0;
if ((p = strchr(s, '/'))) {
if ((c.addr = ParseIp(s, (i = p - s))) != -1) {
c.cidr = 0;
for (++i; i < n; ++i) {
if (isdigit(s[i])) {
c.cidr *= 10;
c.cidr += s[i] - '0';
if (c.cidr > 32) {
c.cidr = -1;
break;
}
} else {
c.cidr = -1;
break;
}
}
if (c.cidr <= 0) {
c.addr = -1;
}
}
} else {
c.addr = ParseIp(s, n);
c.cidr = 32;
}
return c;
}

View file

@ -17,27 +17,33 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "net/http/http.h"
#include "net/http/ip.h"
/**
* Parse IPv4 address.
* Parse IPv4 host address.
*
* @param n if -1 implies strlen
* @return -1 on failure, otherwise 32-bit host-order unsigned integer
* @see ParseCidr()
*/
int64_t ParseIp(const char *s, size_t n) {
int c, j;
size_t i;
uint32_t x;
int b, c, j;
unsigned b, x;
bool dotted = false;
if (n == -1) n = s ? strlen(s) : 0;
if (!n) return -1;
for (b = x = j = i = 0; i < n; ++i) {
c = s[i] & 255;
if (isdigit(c)) {
b *= 10;
b += c - '0';
if (__builtin_mul_overflow(b, 10, &b) || //
__builtin_add_overflow(b, c - '0', &b) || //
(b > 255 && dotted)) {
return -1;
}
} else if (c == '.') {
if (b > 255) return -1;
dotted = true;
x <<= 8;
x |= b;
b = 0;

View file

@ -28,6 +28,7 @@
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/sock.h"
#include "net/http/http.h"
#include "net/http/ip.h"
int main(int argc, char *argv[]) {

View file

@ -228,11 +228,13 @@ TEST(uc_sigmask, signalHandlerCanChangeSignalMaskOfTrappedThread) {
struct sigaction oldsa;
struct sigaction sa = {.sa_sigaction = OnSigMask, .sa_flags = SA_SIGINFO};
sigemptyset(&want);
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &want, 0));
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &want, &got));
ASSERT_FALSE(sigismember(&got, SIGUSR1));
ASSERT_SYS(0, 0, sigaction(SIGUSR1, &sa, &oldsa));
ASSERT_SYS(0, 0, raise(SIGUSR1));
ASSERT_TRUE(gotusr1);
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, 0, &got));
ASSERT_TRUE(sigismember(&got, SIGUSR1));
sigaddset(&want, SIGUSR1);
ASSERT_STREQ(DescribeSigset(0, &want), DescribeSigset(0, &got));
ASSERT_SYS(0, 0, sigaction(SIGUSR1, &oldsa, 0));

View file

@ -34,6 +34,7 @@ TEST_LIBC_INTRIN_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_THREAD \
LIBC_TESTLIB \
LIBC_TINYMATH \

View file

@ -22,7 +22,9 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
@ -39,6 +41,23 @@ FILE *f;
char buf[32];
char testlib_enable_tmp_setup_teardown;
void CheckForFdLeaks(void) {
int rc, i, l = 0, e = errno;
for (i = 3; i < 16; ++i) {
rc = fcntl(i, F_GETFL);
if (rc == -1) {
ASSERT_EQ(EBADF, errno);
errno = e;
} else {
kprintf("file descriptor %d leaked!\n", i);
++l;
}
}
if (l) {
__die();
}
}
TEST(popen, command) {
char foo[6];
testlib_extract("/zip/echo.com", "echo.com", 0755);
@ -46,6 +65,7 @@ TEST(popen, command) {
ASSERT_NE(NULL, fgets(foo, sizeof(foo), f));
ASSERT_STREQ("hello", foo);
ASSERT_EQ(0, pclose(f));
CheckForFdLeaks();
}
TEST(popen, semicolon) {
@ -53,6 +73,7 @@ TEST(popen, semicolon) {
ASSERT_STREQ("hello\n", fgets(buf, sizeof(buf), f));
ASSERT_STREQ("there\n", fgets(buf, sizeof(buf), f));
ASSERT_EQ(0, pclose(f));
CheckForFdLeaks();
}
TEST(popen, singleQuotes) {
@ -61,6 +82,7 @@ TEST(popen, singleQuotes) {
ASSERT_STREQ("hello $there\n", fgets(buf, sizeof(buf), f));
ASSERT_STREQ("yo\n", fgets(buf, sizeof(buf), f));
ASSERT_EQ(0, pclose(f));
CheckForFdLeaks();
}
TEST(popen, doubleQuotes) {
@ -68,6 +90,7 @@ TEST(popen, doubleQuotes) {
ASSERT_NE(NULL, (f = popen("echo -l \"$hello there\"", "r")));
ASSERT_STREQ("a b c there\n", fgets(buf, sizeof(buf), f));
ASSERT_EQ(0, pclose(f));
CheckForFdLeaks();
}
TEST(popen, quoteless) {
@ -77,6 +100,7 @@ TEST(popen, quoteless) {
ASSERT_STREQ("aa b c\n", fgets(buf, sizeof(buf), f)); // mixed feelings
ASSERT_STREQ("yo\n", fgets(buf, sizeof(buf), f));
ASSERT_EQ(0, pclose(f));
CheckForFdLeaks();
}
TEST(popen, pipe) {
@ -84,6 +108,7 @@ TEST(popen, pipe) {
ASSERT_NE(NULL, (f = popen("echo hello | toupper", "r")));
ASSERT_STREQ("HELLO\n", fgets(buf, sizeof(buf), f));
ASSERT_EQ(0, pclose(f));
CheckForFdLeaks();
}
sig_atomic_t gotsig;
@ -102,6 +127,7 @@ TEST(popen, complicated) {
ASSERT_EQ(0, pclose(f));
ASSERT_EQ(1, gotsig);
signal(SIGUSR1, SIG_DFL);
CheckForFdLeaks();
}
void *Worker(void *arg) {
@ -129,10 +155,10 @@ void *Worker(void *arg) {
}
TEST(popen, torture) {
int i, n = 8;
int i, n = 4;
pthread_t *t = _gc(malloc(sizeof(pthread_t) * n));
testlib_extract("/zip/echo.com", "echo.com", 0755);
for (i = 0; i < n; ++i) ASSERT_EQ(0, pthread_create(t + i, 0, Worker, 0));
for (i = 0; i < n; ++i) ASSERT_EQ(0, pthread_join(t[i], 0));
for (i = 3; i < 16; ++i) ASSERT_SYS(EBADF, -1, fcntl(i, F_GETFL));
CheckForFdLeaks();
}

View file

@ -170,12 +170,6 @@ TEST(sem_timedwait, threads) {
TEST(sem_timedwait, processes) {
int i, r, rc, n = 4, pshared = 1;
sem_t *sm = _mapshared(FRAMESIZE), *s[2] = {sm, sm + 1};
if (IsOpenbsd()) {
// TODO(jart): why?
ASSERT_SYS(EPERM, -1, sem_init(s[0], pshared, 0));
ASSERT_SYS(0, 0, munmap(sm, FRAMESIZE));
return;
}
ASSERT_SYS(0, 0, sem_init(s[0], pshared, 0));
ASSERT_SYS(0, 0, sem_init(s[1], pshared, 0));
for (i = 0; i < n; ++i) {

View file

@ -0,0 +1,59 @@
/*-*- 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/testlib/testlib.h"
#include "net/http/ip.h"
TEST(ParseCidr, test) {
struct Cidr in;
in = ParseCidr("10.10.10.1/24", -1);
EXPECT_EQ(0x0a0a0a01, in.addr);
EXPECT_EQ(24, in.cidr);
in = ParseCidr("168430081/1", -1);
EXPECT_EQ(0x0a0a0a01, in.addr);
EXPECT_EQ(1, in.cidr);
}
TEST(ParseCidr, noCidr_defaultsTo32) {
struct Cidr in;
in = ParseCidr("10.10.10.255", -1);
EXPECT_EQ(0x0a0a0aff, in.addr);
EXPECT_EQ(32, in.cidr);
}
TEST(ParseCidr, badIp_returnsNeg1) {
struct Cidr in;
in = ParseCidr("10.10.10.a", -1);
EXPECT_EQ(-1, in.addr);
in = ParseCidr("10.10.10.256", -1);
EXPECT_EQ(-1, in.addr);
in = ParseCidr("10.10.10.256/24", -1);
EXPECT_EQ(-1, in.addr);
}
TEST(ParseCidr, badCidr_returnsNeg1) {
struct Cidr in;
in = ParseCidr("10.10.10.1/", -1);
EXPECT_EQ(-1, in.addr);
in = ParseCidr("10.10.10.1/a", -1);
EXPECT_EQ(-1, in.addr);
in = ParseCidr("10.10.10.1/0", -1);
EXPECT_EQ(-1, in.addr);
in = ParseCidr("10.10.10.1/33", -1);
EXPECT_EQ(-1, in.addr);
}

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/testlib/testlib.h"
#include "net/http/http.h"
#include "net/http/ip.h"
TEST(ParseIp, test) {
EXPECT_EQ(-1, ParseIp("", -1));
@ -30,6 +30,8 @@ TEST(ParseIp, test) {
EXPECT_EQ(0x00000000, ParseIp("...", -1)); /* meh */
EXPECT_EQ(0x80000304, ParseIp("128.0.3.4", -1));
EXPECT_EQ(0x80000304, ParseIp("128..3.4", -1));
EXPECT_EQ(-1, ParseIp("4294967296", -1));
EXPECT_EQ(-1, ParseIp("255.255.255.256", -1));
EXPECT_EQ(-1, ParseIp("256.255.255.255", -1));
EXPECT_EQ(-1, ParseIp("hello", -1));
EXPECT_EQ(-1, ParseIp("hello\177", -1));

View file

@ -26,6 +26,7 @@
#include "libc/testlib/hyperion.h"
#include "libc/testlib/testlib.h"
#include "net/http/http.h"
#include "net/http/ip.h"
#include "net/http/url.h"
TEST(ParseUrl, testEmpty) {

View file

@ -2847,14 +2847,6 @@ static int LuaUnixMemoryWait(lua_State *L) {
} else {
ts.tv_sec = luaL_checkinteger(L, 4);
ts.tv_nsec = luaL_optinteger(L, 5, 0);
if (!FUTEX_TIMEOUT_IS_ABSOLUTE) {
now = timespec_real();
if (timespec_cmp(now, ts) > 0) {
ts = (struct timespec){0};
} else {
ts = timespec_sub(ts, now);
}
}
deadline = &ts;
}
BEGIN_CANCELLATION_POINT;

View file

@ -15,17 +15,18 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "libc/intrin/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/bits.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/s.h"
#include "net/http/http.h"
#include "net/http/ip.h"
#include "third_party/mbedtls/common.h"
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/oid.h"

View file

@ -28,7 +28,6 @@
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
@ -56,8 +55,8 @@ int sys_futex_cp (atomic_int *, int, int, const struct timespec *, int *, int);
static int FUTEX_WAIT_;
static int FUTEX_PRIVATE_FLAG_;
static bool FUTEX_IS_SUPPORTED;
bool FUTEX_TIMEOUT_IS_ABSOLUTE;
static bool futex_is_supported;
static bool futex_timeout_is_relative;
__attribute__((__constructor__)) static void nsync_futex_init_ (void) {
atomic_int x;
@ -65,20 +64,17 @@ __attribute__((__constructor__)) static void nsync_futex_init_ (void) {
FUTEX_WAIT_ = FUTEX_WAIT;
if (IsWindows ()) {
FUTEX_IS_SUPPORTED = true;
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
futex_is_supported = true;
return;
}
if (IsFreebsd ()) {
FUTEX_IS_SUPPORTED = true;
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
futex_is_supported = true;
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
return;
}
if (!(FUTEX_IS_SUPPORTED = IsLinux () || IsOpenbsd ())) {
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
if (!(futex_is_supported = IsLinux () || IsOpenbsd ())) {
return;
}
@ -98,20 +94,20 @@ __attribute__((__constructor__)) static void nsync_futex_init_ (void) {
1, 0, 0, FUTEX_BITSET_MATCH_ANY) == -EAGAIN) {
FUTEX_WAIT_ = FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME;
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
} else if (!IsTiny () && IsLinux () &&
_futex (&x, FUTEX_WAIT_BITSET, 1, 0, 0,
FUTEX_BITSET_MATCH_ANY) == -EAGAIN) {
FUTEX_WAIT_ = FUTEX_WAIT_BITSET;
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
FUTEX_TIMEOUT_IS_ABSOLUTE = true;
} else if (IsOpenbsd () ||
(!IsTiny () && IsLinux () &&
!_futex_wake (&x, FUTEX_WAKE_PRIVATE, 1))) {
FUTEX_WAIT_ = FUTEX_WAIT;
FUTEX_PRIVATE_FLAG_ = FUTEX_PRIVATE_FLAG;
futex_timeout_is_relative = true;
} else {
FUTEX_WAIT_ = FUTEX_WAIT;
futex_timeout_is_relative = true;
}
}
@ -123,10 +119,8 @@ static int nsync_futex_polyfill_ (atomic_int *w, int expect, struct timespec *ti
ts = timespec_real ();
if (!timeout) {
deadline = timespec_max;
} else if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
deadline = *timeout;
} else {
deadline = timespec_add (ts, *timeout);
deadline = *timeout;
}
nanos = 100;
@ -186,9 +180,29 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare, stru
return rc;
}
int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, struct timespec *timeout) {
static struct timespec *nsync_futex_timeout_ (struct timespec *memory,
const struct timespec *abstime) {
struct timespec now;
if (!abstime) {
return 0;
} else if (!futex_timeout_is_relative) {
*memory = *abstime;
return memory;
} else {
now = timespec_real ();
if (timespec_cmp (now, *abstime) > 0) {
*memory = (struct timespec){0};
} else {
*memory = timespec_sub (*abstime, now);
}
return memory;
}
}
int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, struct timespec *abstime) {
int e, rc, op, fop;
struct PosixThread *pt = 0;
struct timespec tsmem, *timeout;
if (atomic_load_explicit (w, memory_order_acquire) != expect) {
return -EAGAIN;
@ -199,12 +213,14 @@ int nsync_futex_wait_ (atomic_int *w, int expect, char pshare, struct timespec *
op |= FUTEX_PRIVATE_FLAG_;
}
timeout = nsync_futex_timeout_ (&tsmem, abstime);
LOCKTRACE ("futex(%t [%d], %s, %#x, %s) → ...",
w, atomic_load_explicit (w, memory_order_relaxed),
DescribeFutexOp (op), expect,
DescribeTimespec (0, timeout));
if (FUTEX_IS_SUPPORTED) {
if (futex_is_supported) {
e = errno;
if (IsWindows ()) {
// Windows 8 futexes don't support multiple processes :(
@ -270,7 +286,7 @@ int nsync_futex_wake_ (atomic_int *w, int count, char pshare) {
op |= FUTEX_PRIVATE_FLAG_;
}
if (FUTEX_IS_SUPPORTED) {
if (futex_is_supported) {
if (IsWindows ()) {
if (pshare) {
goto Polyfill;

View file

@ -5,8 +5,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool FUTEX_TIMEOUT_IS_ABSOLUTE;
int nsync_futex_wake_(_Atomic(int) *, int, char);
int nsync_futex_wait_(_Atomic(int) *, int, char, struct timespec *);

View file

@ -15,16 +15,9 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/weaken.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/atomic.h"
#include "third_party/nsync/atomic.internal.h"
#include "third_party/nsync/futex.internal.h"
#include "libc/dce.h"
#include "third_party/nsync/mu_semaphore.h"
#include "third_party/nsync/mu_semaphore.internal.h"
asm(".ident\t\"\\n\\n\
*NSYNC (Apache 2.0)\\n\
@ -32,108 +25,40 @@ Copyright 2016 Google, Inc.\\n\
https://github.com/google/nsync\"");
// clang-format off
#define ASSERT(x) _npassert(x)
/* Check that atomic operations on nsync_atomic_uint32_ can be applied to int. */
static const int assert_int_size = 1 /
(sizeof (assert_int_size) == sizeof (uint32_t) &&
sizeof (nsync_atomic_uint32_) == sizeof (uint32_t));
struct futex {
int i; /* lo half=count; hi half=waiter count */
};
static nsync_semaphore *sem_big_enough_for_futex = (nsync_semaphore *) (uintptr_t)(1 /
(sizeof (struct futex) <= sizeof (*sem_big_enough_for_futex)));
/* Initialize *s; the initial value is 0. */
void nsync_mu_semaphore_init (nsync_semaphore *s) {
struct futex *f = (struct futex *) s;
f->i = 0;
if (IsNetbsd ()) {
return nsync_mu_semaphore_init_sem (s);
} else {
return nsync_mu_semaphore_init_futex (s);
}
}
/* Wait until the count of *s exceeds 0, and decrement it. */
errno_t nsync_mu_semaphore_p (nsync_semaphore *s) {
struct futex *f = (struct futex *) s;
int i;
int result = 0;
do {
i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
if (i == 0) {
int futex_result = nsync_futex_wait_ (
(atomic_int *)&f->i, i, PTHREAD_PROCESS_PRIVATE, NULL);
ASSERT (futex_result == 0 ||
futex_result == -EINTR ||
futex_result == -EAGAIN ||
futex_result == -ECANCELED ||
futex_result == -EWOULDBLOCK);
if (futex_result == -ECANCELED) {
result = ECANCELED;
}
}
} while (result == 0 && (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i-1)));
return result;
if (IsNetbsd ()) {
return nsync_mu_semaphore_p_sem (s);
} else {
return nsync_mu_semaphore_p_futex (s);
}
}
/* Wait until one of:
the count of *s is non-zero, in which case decrement *s and return 0;
or abs_deadline expires, in which case return ETIMEDOUT. */
errno_t nsync_mu_semaphore_p_with_deadline (nsync_semaphore *s, nsync_time abs_deadline) {
struct futex *f = (struct futex *)s;
int i;
int result = 0;
do {
i = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
if (i == 0) {
int futex_result;
struct timespec ts_buf;
const struct timespec *ts = NULL;
if (nsync_time_cmp (abs_deadline, nsync_time_no_deadline) != 0) {
memset (&ts_buf, 0, sizeof (ts_buf));
if (FUTEX_TIMEOUT_IS_ABSOLUTE) {
ts_buf.tv_sec = NSYNC_TIME_SEC (abs_deadline);
ts_buf.tv_nsec = NSYNC_TIME_NSEC (abs_deadline);
} else {
nsync_time now;
now = nsync_time_now ();
if (nsync_time_cmp (now, abs_deadline) > 0) {
ts_buf.tv_sec = 0;
ts_buf.tv_nsec = 0;
} else {
nsync_time rel_deadline;
rel_deadline = nsync_time_sub (abs_deadline, now);
ts_buf.tv_sec = NSYNC_TIME_SEC (rel_deadline);
ts_buf.tv_nsec = NSYNC_TIME_NSEC (rel_deadline);
}
}
ts = &ts_buf;
}
futex_result = nsync_futex_wait_ ((atomic_int *)&f->i, i, PTHREAD_PROCESS_PRIVATE, ts);
ASSERT (futex_result == 0 ||
futex_result == -EINTR ||
futex_result == -EAGAIN ||
futex_result == -ECANCELED ||
futex_result == -ETIMEDOUT ||
futex_result == -EWOULDBLOCK);
/* Some systems don't wait as long as they are told. */
if (futex_result == -ETIMEDOUT &&
nsync_time_cmp (abs_deadline, nsync_time_now ()) <= 0) {
result = ETIMEDOUT;
}
if (futex_result == -ECANCELED) {
result = ECANCELED;
}
}
} while (result == 0 && (i == 0 || !ATM_CAS_ACQ ((nsync_atomic_uint32_ *) &f->i, i, i - 1)));
return (result);
if (IsNetbsd ()) {
return nsync_mu_semaphore_p_with_deadline_sem (s, abs_deadline);
} else {
return nsync_mu_semaphore_p_with_deadline_futex (s, abs_deadline);
}
}
/* Ensure that the count of *s is at least 1. */
void nsync_mu_semaphore_v (nsync_semaphore *s) {
struct futex *f = (struct futex *) s;
uint32_t old_value;
do {
old_value = ATM_LOAD ((nsync_atomic_uint32_ *) &f->i);
} while (!ATM_CAS_REL ((nsync_atomic_uint32_ *) &f->i, old_value, old_value+1));
ASSERT (nsync_futex_wake_ ((atomic_int *)&f->i, 1, PTHREAD_PROCESS_PRIVATE) >= 0);
if (IsNetbsd ()) {
return nsync_mu_semaphore_v_sem (s);
} else {
return nsync_mu_semaphore_v_futex (s);
}
}

Some files were not shown because too many files have changed in this diff Show more