Make some systemic improvements

- add vdso dump utility
- tests now log stack usage
- rename g_ftrace to __ftrace
- make internal spinlocks go faster
- add conformant c11 atomics library
- function tracing now logs stack usage
- make function call tracing thread safe
- add -X unsecure (no ssl) mode to redbean
- munmap() has more consistent behavior now
- pacify fsync() calls on python unit tests
- make --strace flag work better in redbean
- start minimizing and documenting compiler flags
This commit is contained in:
Justine Tunney 2022-05-18 16:41:29 -07:00
parent c6bbca55e9
commit 9208c83f7a
141 changed files with 1948 additions and 1411 deletions

View file

@ -65,31 +65,39 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/calls/sigenter-freebsd.o \
o/$(MODE)/libc/calls/sigenter-netbsd.o \
o/$(MODE)/libc/calls/sigenter-openbsd.o \
# we can't use asan because:
# ucontext_t memory is owned by xnu kernel
o/$(MODE)/libc/calls/sigenter-xnu.o: \
OVERRIDE_COPTS += \
-mno-fentry \
-fno-stack-protector \
-fno-sanitize=all
-ffreestanding \
-fno-sanitize=address
o/$(MODE)/libc/calls/sys_mprotect.greg.o \
o/$(MODE)/libc/calls/vdsofunc.greg.o \
o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o \
o/$(MODE)/libc/calls/mapstack.greg.o \
o/$(MODE)/libc/calls/execve-nt.greg.o \
o/$(MODE)/libc/calls/getcwd.greg.o \
o/$(MODE)/libc/calls/getcwd-xnu.greg.o \
o/$(MODE)/libc/calls/getprogramexecutablename.greg.o \
o/$(MODE)/libc/calls/raise.o: \
# we can't use asan because:
# vdso memory is owned by linux kernel
o/$(MODE)/libc/calls/vdsofunc.greg.o: \
OVERRIDE_COPTS += \
-ffreestanding \
$(NO_MAGIC)
-fno-sanitize=address
o/$(MODE)/libc/calls/termios2linux.o \
o/$(MODE)/libc/calls/termios2host.o \
# we can't use asan because:
# asan guard pages haven't been allocated yet
o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o: \
OVERRIDE_COPTS += \
-ffreestanding \
-fno-sanitize=address
# we can't use asan because:
# ntspawn allocates 128kb of heap memory via win32
o/$(MODE)/libc/calls/ntspawn.o \
o/$(MODE)/libc/calls/mkntcmdline.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_COPTS += \
-ffreestanding \
-fno-sanitize=address
# we always want -O3 because:
# it makes the code size smaller too
o/$(MODE)/libc/calls/sigenter-freebsd.o \
o/$(MODE)/libc/calls/sigenter-netbsd.o \
o/$(MODE)/libc/calls/sigenter-openbsd.o \
@ -98,7 +106,36 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \
OVERRIDE_COPTS += \
-O3
# TODO(jart): make va_arg optimize well in default mode
# we must disable static stack safety because:
# these functions use alloca(n)
o/$(MODE)/libc/calls/execl.o \
o/$(MODE)/libc/calls/execle.o \
o/$(MODE)/libc/calls/execlp.o \
o/$(MODE)/libc/calls/execve-sysv.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
# we must disable static stack safety because:
# PATH_MAX*sizeof(char16_t)*2 exceeds 4096 byte frame limit
o/$(MODE)/libc/calls/copyfile.o \
o/$(MODE)/libc/calls/symlinkat-nt.o \
o/$(MODE)/libc/calls/readlinkat-nt.o \
o/$(MODE)/libc/calls/linkat-nt.o \
o/$(MODE)/libc/calls/renameat-nt.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
# we must segregate codegen because:
# file contains multiple independently linkable apis
o/$(MODE)/libc/calls/ioctl-siocgifconf.o \
o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \
OVERRIDE_COPTS += \
-ffunction-sections \
-fdata-sections
# we always want -Os because:
# va_arg codegen is very bloated in default mode
o//libc/calls/open.o \
o//libc/calls/openat.o \
o//libc/calls/prctl.o \
@ -120,27 +157,6 @@ o//libc/calls/fcntl.o: \
OVERRIDE_CFLAGS += \
-Os
# must use alloca() or path_max*2*2
o/$(MODE)/libc/calls/execl.o \
o/$(MODE)/libc/calls/execle.o \
o/$(MODE)/libc/calls/execlp.o \
o/$(MODE)/libc/calls/copyfile.o \
o/$(MODE)/libc/calls/execve-nt.greg.o \
o/$(MODE)/libc/calls/linkat-nt.o \
o/$(MODE)/libc/calls/renameat-nt.o \
o/$(MODE)/libc/calls/execve-sysv.o \
o/$(MODE)/libc/calls/symlinkat-nt.o \
o/$(MODE)/libc/calls/readlinkat-nt.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/libc/calls/ioctl-siocgifconf.o \
o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \
OVERRIDE_COPTS += \
-ffunction-sections \
-fdata-sections
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))

View file

@ -21,7 +21,6 @@
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -42,12 +41,7 @@ textwindows int sys_close_nt(struct Fd *fd) {
// if this file descriptor is wrapped in a named pipe worker thread
// then we need to close our copy of the worker thread handle. it's
// also required that whatever install a worker use malloc, so free
if (fd->worker) {
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
fd->worker = 0;
} else {
if (!CloseHandle(fd->handle)) ok = false;
}
if (!CloseHandle(fd->handle)) ok = false;
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
if (!CloseHandle(fd->extra)) ok = false;
}

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
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
@ -16,19 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/ntdll.h"
#include "libc/nt/synchronization.h"
#include "libc/calls/struct/sigaltstack.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
textwindows int sys_sched_yield_nt(void) {
// A value of zero, together with the bAlertable parameter set to
// FALSE, causes the thread to relinquish the remainder of its time
// slice to any other thread that is ready to run, if there are no
// pending user APCs on the calling thread. If there are no other
// threads ready to run and no user APCs are queued, the function
// returns immediately, and the thread continues execution.
// ──Quoth MSDN
SleepEx(0, false);
return 0;
const char *DescribeSigaltstk(char *buf, size_t bufsize, int rc,
const struct sigaltstack *ss) {
if (rc == -1) return "n/a";
if (!ss) return "NULL";
if ((!IsAsan() && kisdangerous(ss)) ||
(IsAsan() && !__asan_is_valid(ss, sizeof(*ss)))) {
ksnprintf(buf, sizeof(buf), "%p", ss);
} else {
ksnprintf(buf, bufsize, "{.ss_sp=%p, .ss_flags=%#lx, .ss_size=%'zu}",
ss->ss_sp, ss->ss_flags, ss->ss_size);
}
return buf;
}

View file

@ -25,7 +25,6 @@
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -67,16 +66,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
g_fds.p[newfd].kind = kFdReserved;
}
// if this file descriptor is wrapped in a named pipe worker thread
// then we should clone the original authentic handle rather than the
// stdin worker's named pipe. we won't clone the worker, since that
// can always be recreated again on demand.
if (g_fds.p[oldfd].worker) {
handle = g_fds.p[oldfd].worker->reader;
} else {
handle = g_fds.p[oldfd].handle;
}
handle = g_fds.p[oldfd].handle;
proc = GetCurrentProcess();
if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true,
kNtDuplicateSameAccess)) {
@ -90,9 +80,6 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
} else {
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
}
if (g_fds.p[oldfd].worker) {
g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker);
}
rc = newfd;
} else {
__releasefd(newfd);

View file

@ -20,21 +20,28 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
/**
* Blocks until kernel flushes non-metadata buffers for fd to disk.
*
* @return 0 on success, or -1 w/ errno
* @see fsync(), sync_file_range()
* @see sync(), fsync(), sync_file_range()
* @see __nosync to secretly disable
* @asyncsignalsafe
*/
int fdatasync(int fd) {
int rc;
if (!IsWindows()) {
rc = sys_fdatasync(fd);
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fdatasync(fd);
} else {
rc = sys_fdatasync_nt(fd);
}
STRACE("fdatasync(%d) → %d% m", fd, rc);
} else {
rc = sys_fdatasync_nt(fd);
rc = 0;
STRACE("fdatasync(%d) → disabled% m", fd);
}
STRACE("%s(%d) → %d% m", "fdatasync", fd, rc);
return rc;
}

View file

@ -20,21 +20,28 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/runtime/runtime.h"
/**
* Blocks until kernel flushes buffers for fd to disk.
*
* @return 0 on success, or -1 w/ errno
* @see fdatasync(), sync_file_range()
* @see __nosync to secretly disable
* @asyncsignalsafe
*/
int fsync(int fd) {
int rc;
if (!IsWindows()) {
rc = sys_fsync(fd);
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
rc = sys_fsync(fd);
} else {
rc = sys_fdatasync_nt(fd);
}
STRACE("fysnc(%d) → %d% m", fd, rc);
} else {
rc = sys_fdatasync_nt(fd);
rc = 0;
STRACE("fsync(%d) → disabled% m", fd);
}
STRACE("%s(%d) → %d% m", "fsync", fd, rc);
return rc;
}

View file

@ -62,7 +62,6 @@ struct Fd {
unsigned mode;
int64_t handle;
int64_t extra;
struct NtStdinWorker *worker;
bool zombie;
};
@ -90,9 +89,12 @@ void __releasefd(int) hidden;
void __releasefd_unlocked(int) hidden;
int __ensurefds(int) hidden;
int __ensurefds_unlocked(int) hidden;
int64_t __getfdhandleactual(int) hidden;
void __printfds(void) hidden;
forceinline int64_t __getfdhandleactual(int fd) {
return g_fds.p[fd].handle;
}
forceinline bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
}

View file

@ -31,7 +31,7 @@
} \
} while (0)
static noasan bool NeedsQuotes(const char *s) {
static bool NeedsQuotes(const char *s) {
if (!*s) return true;
do {
if (*s == ' ' || *s == '\t') {
@ -54,8 +54,8 @@ static noasan bool NeedsQuotes(const char *s) {
* @return freshly allocated lpCommandLine or NULL w/ errno
* @see libc/runtime/dosargv.c
*/
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX / 2],
const char *prog, char *const argv[]) {
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
char *const argv[]) {
char *arg;
uint64_t w;
wint_t x, y;

View file

@ -31,14 +31,14 @@
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
static noasan int CompareStrings(const char *l, const char *r) {
static int CompareStrings(const char *l, const char *r) {
int a, b;
size_t i = 0;
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
return a - b;
}
static noasan void InsertString(char **a, size_t i, char *s) {
static void InsertString(char **a, size_t i, char *s) {
size_t j;
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
a[j] = a[j - 1];
@ -57,8 +57,8 @@ static noasan void InsertString(char **a, size_t i, char *s) {
* @return 0 on success, or -1 w/ errno
* @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767)
*/
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX / 2],
char *const envp[], const char *extravar) {
textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
const char *extravar) {
bool v;
char *t;
axdx_t rc;

View file

@ -16,13 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/calls/calls.h"
int64_t __getfdhandleactual(int fd) {
if (g_fds.p[fd].worker) {
return g_fds.p[fd].worker->reader;
} else {
return g_fds.p[fd].handle;
}
}
/**
* Tunes sync system call availability.
*
* If this value is set to 0x5453455454534146, then the system calls
* sync(), fsync(), and fdatasync() system calls will do nothing and
* return success. This is intended to be used for things like making
* things like Python unit tests go faster because fsync is extremely
* slow and using tmpfs requires root privileges.
*/
uint64_t __nosync;

View file

@ -38,7 +38,6 @@
#include "libc/nt/synchronization.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sig.h"

View file

@ -54,7 +54,6 @@ void __printfds(void) {
if (g_fds.p[i].mode) kprintf(" mode=%#o", g_fds.p[i].mode);
if (g_fds.p[i].handle) kprintf(" handle=%ld", g_fds.p[i].handle);
if (g_fds.p[i].extra) kprintf(" extra=%ld", g_fds.p[i].extra);
if (g_fds.p[i].worker) kprintf(" worker=%p", g_fds.p[i].worker);
kprintf("\n");
}
_spunlock(&__fds_lock);

View file

@ -16,12 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -50,6 +52,7 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
(bytes = __zipos_notat(dirfd, path)) == -1) {
STRACE("TOOD: zipos support for readlinkat");
} else if (!IsWindows()) {
assert(bufsiz);
bytes = sys_readlinkat(dirfd, path, buf, bufsiz);
} else {
bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz);

View file

@ -30,6 +30,7 @@
#include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
@ -81,7 +82,9 @@ char *realpath(const char *filename, char *resolved)
ssize_t rc;
int e, up, check_dir=0;
size_t k, p, q, l, l0, cnt=0, nup=0;
char output[PATH_MAX], stack[PATH_MAX], *z;
char output[PATH_MAX], stack[PATH_MAX+1], *z;
/* STRACE("realpath(%#s, %#s)", filename, resolved); */
if (!filename) {
einval();

View file

@ -1,33 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/internal.h"
#include "libc/dce.h"
/**
* Asks kernel to deschedule thread momentarily.
*/
int sched_yield(void) {
/* TODO(jart): Add get_sched_yield() so we can STRACE() */
if (!IsWindows()) {
return sys_sched_yield();
} else {
return sys_sched_yield_nt();
}
}

View file

@ -22,10 +22,11 @@
#include "libc/calls/struct/sigaltstack.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
const struct sigaltstack *linux) {
static void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
const struct sigaltstack *linux) {
void *sp;
int flags;
size_t size;
@ -37,8 +38,8 @@ static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
bsd->ss_size = size;
}
static noasan void sigaltstack2linux(struct sigaltstack *linux,
const struct sigaltstack_bsd *bsd) {
static void sigaltstack2linux(struct sigaltstack *linux,
const struct sigaltstack_bsd *bsd) {
void *sp;
int flags;
size_t size;
@ -69,10 +70,11 @@ static noasan void sigaltstack2linux(struct sigaltstack *linux,
* @param old if non-null will receive current signal alt stack
* @return 0 on success, or -1 w/ errno
*/
noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
int rc;
void *b;
const void *a;
char buf[2][128];
struct sigaltstack_bsd bsd;
if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) ||
(neu && (__asan_check(neu, sizeof(*neu)).kind ||
@ -106,6 +108,8 @@ noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
} else {
rc = enosys();
}
STRACE("sigaltstack() → %d% m", rc);
STRACE("sigaltstack(%s, [%s]) → %d% m",
DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, neu),
DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, old), rc);
return rc;
}

View file

@ -4,6 +4,7 @@
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/runtime/runtime.h"
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
@ -50,8 +51,6 @@ COSMOPOLITAN_C_START_
#define NTTRACE(FMT, ...) (void)0
#endif
extern int __strace;
void __stracef(const char *, ...);
COSMOPOLITAN_C_END_

View file

@ -18,15 +18,22 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
/**
* Flushes file system changes to disk by any means necessary.
* @see __nosync to secretly disable
*/
void sync(void) {
if (!IsWindows()) {
sys_sync();
if (__nosync != 0x5453455454534146) {
if (!IsWindows()) {
sys_sync();
} else {
sys_sync_nt();
}
STRACE("sync()% m");
} else {
sys_sync_nt();
STRACE("sync() → disabled% m");
}
}

View file

@ -68,66 +68,5 @@ typedef __UINT_FAST64_TYPE__ uint_fast64_t;
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
#define UINT_FAST16_MIN (-UINT_FAST16_MAX - 1)
#define atomic_bool _Atomic(_Bool)
#define atomic_bool32 atomic_int_fast32_t
#define atomic_char _Atomic(char)
#define atomic_schar _Atomic(signed char)
#define atomic_uchar _Atomic(unsigned char)
#define atomic_short _Atomic(short)
#define atomic_ushort _Atomic(unsigned short)
#define atomic_int _Atomic(int)
#define atomic_uint _Atomic(unsigned int)
#define atomic_long _Atomic(long)
#define atomic_ulong _Atomic(unsigned long)
#define atomic_llong _Atomic(long long)
#define atomic_ullong _Atomic(unsigned long long)
#define atomic_char16_t _Atomic(char16_t)
#define atomic_char32_t _Atomic(char32_t)
#define atomic_wchar_t _Atomic(wchar_t)
#define atomic_int_least8_t _Atomic(int_least8_t)
#define atomic_uint_least8_t _Atomic(uint_least8_t)
#define atomic_int_least16_t _Atomic(int_least16_t)
#define atomic_uint_least16_t _Atomic(uint_least16_t)
#define atomic_int_least32_t _Atomic(int_least32_t)
#define atomic_uint_least32_t _Atomic(uint_least32_t)
#define atomic_int_least64_t _Atomic(int_least64_t)
#define atomic_uint_least64_t _Atomic(uint_least64_t)
#define atomic_int_fast8_t _Atomic(int_fast8_t)
#define atomic_uint_fast8_t _Atomic(uint_fast8_t)
#define atomic_int_fast16_t _Atomic(int_fast16_t)
#define atomic_uint_fast16_t _Atomic(uint_fast16_t)
#define atomic_int_fast32_t _Atomic(int_fast32_t)
#define atomic_uint_fast32_t _Atomic(uint_fast32_t)
#define atomic_int_fast64_t _Atomic(int_fast64_t)
#define atomic_uint_fast64_t _Atomic(uint_fast64_t)
#define atomic_intptr_t _Atomic(intptr_t)
#define atomic_uintptr_t _Atomic(uintptr_t)
#define atomic_size_t _Atomic(size_t)
#define atomic_ptrdiff_t _Atomic(ptrdiff_t)
#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
#else
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
#endif
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_WEIRDTYPES_H_ */