mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-25 20:10:29 +00:00
Improve locks and signals
- Introduce fast spinlock API - Double rand64() perf w/ spinlock - Improve raise() on New Technology - Support gettid() across platforms - Implement SA_NODEFER on New Technology - Move the lock intrinsics into LIBC_INTRIN - Make SIGTRAP recoverable on New Technology - Block SIGCHLD in wait4() on New Technology - Add threading prototypes for XNU and FreeBSD - Rewrite abort() fixing its minor bugs on XNU/NT - Shave down a lot of the content in libc/bits/bits.h - Let signal handlers modify CPU registers on New Technology
This commit is contained in:
parent
f68f1789bd
commit
046c7ebd4a
110 changed files with 1514 additions and 876 deletions
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
|
@ -29,6 +28,7 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/asancodes.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
@ -842,7 +842,7 @@ void *__asan_morgue_add(void *p) {
|
|||
for (;;) {
|
||||
i = __asan_morgue.i;
|
||||
j = (i + 1) & (ARRAYLEN(__asan_morgue.p) - 1);
|
||||
if (cmpxchg(&__asan_morgue.i, i, j)) {
|
||||
if (_lockcmpxchg(&__asan_morgue.i, i, j)) {
|
||||
r = __asan_morgue.p[i];
|
||||
__asan_morgue.p[i] = p;
|
||||
return r;
|
||||
|
@ -855,7 +855,7 @@ static void __asan_morgue_flush(void) {
|
|||
void *p;
|
||||
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
||||
p = __asan_morgue.p[i];
|
||||
if (cmpxchg(__asan_morgue.p + i, p, 0)) {
|
||||
if (_lockcmpxchg(__asan_morgue.p + i, p, 0)) {
|
||||
if (weaken(dlfree)) {
|
||||
weaken(dlfree)(p);
|
||||
}
|
||||
|
@ -1206,7 +1206,7 @@ void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
|
|||
}
|
||||
|
||||
void __asan_report_load(uint8_t *addr, int size) {
|
||||
if (cmpxchg(&__asan_noreentry, false, true)) {
|
||||
if (_lockcmpxchg(&__asan_noreentry, false, true)) {
|
||||
if (!__vforked) {
|
||||
__asan_report_memory_fault(addr, size, "load")();
|
||||
__asan_unreachable();
|
||||
|
@ -1219,7 +1219,7 @@ void __asan_report_load(uint8_t *addr, int size) {
|
|||
}
|
||||
|
||||
void __asan_report_store(uint8_t *addr, int size) {
|
||||
if (cmpxchg(&__asan_noreentry, false, true)) {
|
||||
if (_lockcmpxchg(&__asan_noreentry, false, true)) {
|
||||
if (!__vforked) {
|
||||
__asan_report_memory_fault(addr, size, "store")();
|
||||
__asan_unreachable();
|
||||
|
@ -1364,7 +1364,7 @@ static textstartup void __asan_shadow_existing_mappings(void) {
|
|||
textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
static bool once;
|
||||
if (!cmpxchg(&once, false, true)) return;
|
||||
if (!_lockcmpxchg(&once, false, true)) return;
|
||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||
__write_str("error: asan binaries require windows10\r\n");
|
||||
__restorewintty();
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -29,17 +30,19 @@
|
|||
*/
|
||||
relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
||||
int line) {
|
||||
int rc;
|
||||
static bool noreentry;
|
||||
kprintf("%s:%d: assert(%s) failed%n", file, line, expr);
|
||||
if (cmpxchg(&noreentry, false, true)) {
|
||||
if (_lockcmpxchg(&noreentry, false, true)) {
|
||||
if (weaken(__die)) {
|
||||
weaken(__die)();
|
||||
} else {
|
||||
kprintf("can't backtrace b/c `__die` not linked%n");
|
||||
}
|
||||
__restorewintty();
|
||||
_Exit(23);
|
||||
rc = 23;
|
||||
} else {
|
||||
rc = 24;
|
||||
}
|
||||
__restorewintty();
|
||||
_Exit(24);
|
||||
_Exit(rc);
|
||||
}
|
||||
|
|
53
libc/intrin/atomic_load.c
Normal file
53
libc/intrin/atomic_load.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*-*- 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/intrin/atomic_load.h"
|
||||
|
||||
/**
|
||||
* Reads scalar from memory w/ one operation.
|
||||
*
|
||||
* This macro is intended to prevent things like compiler load tearing
|
||||
* optimizations.
|
||||
*
|
||||
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @return *(MEM)
|
||||
* @note defeats compiler load tearing optimizations
|
||||
* @note alignas(𝑘) is implied if compiler knows type
|
||||
* @note alignas(𝑘) only avoids multi-core / cross-page edge cases
|
||||
* @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1
|
||||
* @see atomic_store()
|
||||
*/
|
||||
intptr_t(atomic_load)(void *p, size_t n) {
|
||||
intptr_t x = 0;
|
||||
switch (n) {
|
||||
case 1:
|
||||
__builtin_memcpy(&x, p, 1);
|
||||
return x;
|
||||
case 2:
|
||||
__builtin_memcpy(&x, p, 2);
|
||||
return x;
|
||||
case 4:
|
||||
__builtin_memcpy(&x, p, 4);
|
||||
return x;
|
||||
case 8:
|
||||
__builtin_memcpy(&x, p, 8);
|
||||
return x;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
22
libc/intrin/atomic_load.h
Normal file
22
libc/intrin/atomic_load.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
intptr_t atomic_load(void *, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define atomic_load(MEM) \
|
||||
({ \
|
||||
autotype(MEM) Mem = (MEM); \
|
||||
typeof(*Mem) Reg; \
|
||||
asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \
|
||||
Reg; \
|
||||
})
|
||||
#else
|
||||
#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM)))
|
||||
#endif /* GNUC && !ANSI && x86 */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ */
|
54
libc/intrin/atomic_store.c
Normal file
54
libc/intrin/atomic_store.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*-*- 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/intrin/atomic_store.h"
|
||||
|
||||
/**
|
||||
* Saves scalar to memory w/ one operation.
|
||||
*
|
||||
* This is guaranteed to happen in either one or zero operations,
|
||||
* depending on whether or not it's possible for *(MEM) to be read
|
||||
* afterwards. This macro only forbids compiler from using >1 ops.
|
||||
*
|
||||
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr)
|
||||
* @return VAL
|
||||
* @note alignas(𝑘) on nexgen32e only needed for end of page gotcha
|
||||
* @note alignas(𝑘) is implied if compiler knows type
|
||||
* @note needed to defeat store tearing optimizations
|
||||
* @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1
|
||||
* @see atomic_load()
|
||||
*/
|
||||
intptr_t(atomic_store)(void *p, intptr_t x, size_t n) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
__builtin_memcpy(p, &x, 1);
|
||||
return x;
|
||||
case 2:
|
||||
__builtin_memcpy(p, &x, 2);
|
||||
return x;
|
||||
case 4:
|
||||
__builtin_memcpy(p, &x, 4);
|
||||
return x;
|
||||
case 8:
|
||||
__builtin_memcpy(p, &x, 8);
|
||||
return x;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
23
libc/intrin/atomic_store.h
Normal file
23
libc/intrin/atomic_store.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
intptr_t atomic_store(void *, intptr_t, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define atomic_store(MEM, VAL) \
|
||||
({ \
|
||||
autotype(VAL) Val = (VAL); \
|
||||
typeof(&Val) Mem = (MEM); \
|
||||
asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \
|
||||
Val; \
|
||||
})
|
||||
#else
|
||||
#define atomic_store(MEM, VAL) \
|
||||
atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL))))
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ */
|
47
libc/intrin/cmpxchg.c
Normal file
47
libc/intrin/cmpxchg.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*-*- 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/intrin/cmpxchg.h"
|
||||
|
||||
/**
|
||||
* Compares and exchanges.
|
||||
*
|
||||
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param size is automatically supplied by macro wrapper
|
||||
* @return true if value was exchanged, otherwise false
|
||||
* @see _lockcmpxchg()
|
||||
*/
|
||||
bool(_cmpxchg)(void *ifthing, intptr_t isequaltome, intptr_t replaceitwithme,
|
||||
size_t size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
return _cmpxchg((int8_t *)ifthing, (int8_t)isequaltome,
|
||||
(int8_t)replaceitwithme);
|
||||
case 2:
|
||||
return _cmpxchg((int16_t *)ifthing, (int16_t)isequaltome,
|
||||
(int16_t)replaceitwithme);
|
||||
case 4:
|
||||
return _cmpxchg((int32_t *)ifthing, (int32_t)isequaltome,
|
||||
(int32_t)replaceitwithme);
|
||||
case 8:
|
||||
return _cmpxchg((int64_t *)ifthing, (int64_t)isequaltome,
|
||||
(int64_t)replaceitwithme);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
29
libc/intrin/cmpxchg.h
Normal file
29
libc/intrin/cmpxchg.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_CMPXCHG_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_CMPXCHG_H_
|
||||
#include "libc/bits/asmflag.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
bool _cmpxchg(void *, intptr_t, intptr_t, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||
#define _cmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm volatile(ZFLAG_ASM("cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
#else
|
||||
#define _cmpxchg(MEM, CMP, VAL) \
|
||||
_cmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
|
||||
#endif /* GNUC && !ANSI && x86 */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_CMPXCHG_H_ */
|
46
libc/intrin/cmpxchg16b.internal.h
Normal file
46
libc/intrin/cmpxchg16b.internal.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
|
||||
#include "libc/bits/asmflag.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* Compares and exchanges 128-bit value, i.e.
|
||||
*
|
||||
* if (*IfThing == *IsEqualToMe) {
|
||||
* *IfThing = ReplaceItWithMe;
|
||||
* return true;
|
||||
* } else {
|
||||
* *IsEqualToMe = *IfThing;
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* Please note that Intel Architecture doesn't guarantee 16-byte memory
|
||||
* accesses to be atomic on their own. Therefore _lockcmpxchg16b should
|
||||
* be considered instead for both thread and asynchronous signal safety
|
||||
*
|
||||
* @param IfThing should point to aligned memory
|
||||
* @param IsEqualToMe should point to in/out local variable
|
||||
* @param ReplaceItWithMe might become the new memory value
|
||||
* @return true if *IfThing was changed
|
||||
*/
|
||||
static inline bool _cmpxchg16b(uint128_t *IfThing, uint128_t *IsEqualToMe,
|
||||
uint128_t ReplaceItWithMe) {
|
||||
bool DidIt;
|
||||
uint64_t ax, bx, cx, dx;
|
||||
ax = *IsEqualToMe;
|
||||
dx = *IsEqualToMe >> 64;
|
||||
bx = ReplaceItWithMe;
|
||||
cx = ReplaceItWithMe >> 64;
|
||||
asm volatile(ZFLAG_ASM("cmpxchg16b\t%1")
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(ax), "+d"(dx)
|
||||
: "b"(bx), "c"(cx));
|
||||
if (!DidIt) {
|
||||
*IsEqualToMe = ax | (uint128_t)dx << 64;
|
||||
}
|
||||
return DidIt;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_ */
|
|
@ -16,6 +16,8 @@ const char *DescribeNtFileFlagsAndAttributes(uint32_t);
|
|||
const char *DescribeNtFileShareFlags(uint32_t);
|
||||
const char *DescribeNtFileAccessFlags(uint32_t);
|
||||
const char *DescribeNtProcessAccessFlags(uint32_t);
|
||||
const char *DescribeNtConsoleModeInputFlags(uint32_t);
|
||||
const char *DescribeNtConsoleModeOutputFlags(uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
41
libc/intrin/describentconsolemodeinputflags.greg.c
Normal file
41
libc/intrin/describentconsolemodeinputflags.greg.c
Normal 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/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
|
||||
static const struct DescribeFlags kConsoleModeInputFlags[] = {
|
||||
{kNtEnableProcessedInput, "ProcessedInput"}, //
|
||||
{kNtEnableLineInput, "LineInput"}, //
|
||||
{kNtEnableEchoInput, "EchoInput"}, //
|
||||
{kNtEnableWindowInput, "WindowInput"}, //
|
||||
{kNtEnableMouseInput, "MouseInput"}, //
|
||||
{kNtEnableInsertMode, "InsertMode"}, //
|
||||
{kNtEnableQuickEditMode, "QuickEditMode"}, //
|
||||
{kNtEnableExtendedFlags, "ExtendedFlags"}, //
|
||||
{kNtEnableAutoPosition, "AutoPosition"}, //
|
||||
{kNtEnableVirtualTerminalInput, "VirtualTerminalInput"}, //
|
||||
};
|
||||
|
||||
const char *DescribeNtConsoleModeInputFlags(uint32_t x) {
|
||||
static char consolemodeinputflags[256];
|
||||
return DescribeFlags(consolemodeinputflags, sizeof(consolemodeinputflags),
|
||||
kConsoleModeInputFlags, ARRAYLEN(kConsoleModeInputFlags),
|
||||
"kNtEnable", x);
|
||||
}
|
36
libc/intrin/describentconsolemodeoutputflags.greg.c
Normal file
36
libc/intrin/describentconsolemodeoutputflags.greg.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*-*- 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/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
|
||||
static const struct DescribeFlags kConsoleModeOutputFlags[] = {
|
||||
{kNtEnableProcessedOutput, "EnableProcessedOutput"}, //
|
||||
{kNtEnableWrapAtEolOutput, "EnableWrapAtEolOutput"}, //
|
||||
{kNtEnableVirtualTerminalProcessing, "EnableVirtualTerminalProcessing"}, //
|
||||
{kNtDisableNewlineAutoReturn, "DisableNewlineAutoReturn"}, //
|
||||
{kNtEnableLvbGridWorldwide, "EnableLvbGridWorldwide"}, //
|
||||
};
|
||||
|
||||
const char *DescribeNtConsoleModeOutputFlags(uint32_t x) {
|
||||
static char consolemodeoutputflags[128];
|
||||
return DescribeFlags(consolemodeoutputflags, sizeof(consolemodeoutputflags),
|
||||
kConsoleModeOutputFlags,
|
||||
ARRAYLEN(kConsoleModeOutputFlags), "kNt", x);
|
||||
}
|
|
@ -21,20 +21,20 @@
|
|||
#include "libc/nt/enum/processaccess.h"
|
||||
|
||||
static const struct DescribeFlags kProcessAccessflags[] = {
|
||||
{kNtProcessAllAccess, "AllAccess"},
|
||||
{kNtProcessCreateProcess, "CreateProcess"},
|
||||
{kNtProcessCreateThread, "CreateThread"},
|
||||
{kNtProcessDupHandle, "DupHandle"},
|
||||
{kNtProcessQueryInformation, "QueryInformation"},
|
||||
{kNtProcessQueryLimitedInformation, "QueryLimitedInformation"},
|
||||
{kNtProcessSetInformation, "SetInformation"},
|
||||
{kNtProcessSetQuota, "SetQuota"},
|
||||
{kNtProcessSuspendResume, "SuspendResume"},
|
||||
{kNtProcessTerminate, "Terminate"},
|
||||
{kNtProcessVmOperation, "VmOperation"},
|
||||
{kNtProcessVmRead, "VmRead"},
|
||||
{kNtProcessVmWrite, "VmWrite"},
|
||||
{kNtProcessSynchronize, "Synchronize"},
|
||||
{kNtProcessAllAccess, "AllAccess"}, //
|
||||
{kNtProcessCreateProcess, "CreateProcess"}, //
|
||||
{kNtProcessCreateThread, "CreateThread"}, //
|
||||
{kNtProcessDupHandle, "DupHandle"}, //
|
||||
{kNtProcessQueryInformation, "QueryInformation"}, //
|
||||
{kNtProcessQueryLimitedInformation, "QueryLimitedInformation"}, //
|
||||
{kNtProcessSetInformation, "SetInformation"}, //
|
||||
{kNtProcessSetQuota, "SetQuota"}, //
|
||||
{kNtProcessSuspendResume, "SuspendResume"}, //
|
||||
{kNtProcessTerminate, "Terminate"}, //
|
||||
{kNtProcessVmOperation, "VmOperation"}, //
|
||||
{kNtProcessVmRead, "VmRead"}, //
|
||||
{kNtProcessVmWrite, "VmWrite"}, //
|
||||
{kNtProcessSynchronize, "Synchronize"}, //
|
||||
};
|
||||
|
||||
const char *DescribeNtProcessAccessFlags(uint32_t x) {
|
||||
|
|
37
libc/intrin/getpid.c
Normal file
37
libc/intrin/getpid.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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"
|
||||
|
||||
extern int __pid;
|
||||
|
||||
/**
|
||||
* Returns process id.
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int getpid(void) {
|
||||
int rc;
|
||||
if (!__vforked) {
|
||||
rc = __pid;
|
||||
} else {
|
||||
rc = sys_getpid().ax;
|
||||
}
|
||||
return rc;
|
||||
}
|
78
libc/intrin/gettid.c
Normal file
78
libc/intrin/gettid.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/dce.h"
|
||||
#include "libc/nt/thread.h"
|
||||
|
||||
/**
|
||||
* Returns current thread id.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int gettid(void) {
|
||||
int rc;
|
||||
int64_t wut;
|
||||
|
||||
if (IsLinux()) {
|
||||
asm("syscall"
|
||||
: "=a"(rc) // man says always succeeds
|
||||
: "0"(186) // __NR_gettid
|
||||
: "rcx", "r11", "memory");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (IsXnu()) {
|
||||
asm("syscall" // xnu/osfmk/kern/ipc_tt.c
|
||||
: "=a"(rc) // assume success
|
||||
: "0"(0x1000000 | 27) // Mach thread_self_trap()
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (IsOpenbsd()) {
|
||||
asm("syscall"
|
||||
: "=a"(rc) // man says always succeeds
|
||||
: "0"(299) // getthrid()
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (IsNetbsd()) {
|
||||
asm("syscall"
|
||||
: "=a"(rc) // man says always succeeds
|
||||
: "0"(311) // _lwp_self()
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (IsFreebsd()) {
|
||||
asm("syscall"
|
||||
: "=a"(rc), // only fails w/ EFAULT, which isn't possible
|
||||
"=m"(wut) // must be 64-bit
|
||||
: "0"(432), // thr_self()
|
||||
"D"(&wut) // but not actually 64-bit
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
return wut; // narrowing intentional
|
||||
}
|
||||
|
||||
if (IsWindows()) {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
return getpid();
|
||||
}
|
|
@ -26,6 +26,7 @@ LIBC_INTRIN_A_CHECKS = \
|
|||
LIBC_INTRIN_A_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32
|
||||
|
||||
|
@ -66,6 +67,7 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
|
|||
o/$(MODE)/libc/intrin/createfile.greg.o \
|
||||
o/$(MODE)/libc/intrin/createpipe.greg.o \
|
||||
o/$(MODE)/libc/intrin/closehandle.greg.o \
|
||||
o/$(MODE)/libc/intrin/openprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/createthread.greg.o \
|
||||
o/$(MODE)/libc/intrin/createprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/describeflags.greg.o \
|
||||
|
@ -75,9 +77,11 @@ o/$(MODE)/libc/intrin/flushviewoffile.greg.o \
|
|||
o/$(MODE)/libc/intrin/deviceiocontrol.greg.o \
|
||||
o/$(MODE)/libc/intrin/createdirectory.greg.o \
|
||||
o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \
|
||||
o/$(MODE)/libc/intrin/terminateprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/getfileattributes.greg.o \
|
||||
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
|
||||
o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \
|
||||
o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \
|
||||
o/$(MODE)/libc/intrin/kstarttsc.o \
|
||||
o/$(MODE)/libc/intrin/nomultics.o \
|
||||
o/$(MODE)/libc/intrin/ntconsolemode.o: \
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
|
@ -27,7 +26,10 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/divmod10.internal.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
|
@ -42,6 +44,7 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/time/clockstonanos.internal.h"
|
||||
|
||||
struct Timestamps {
|
||||
unsigned long long birth;
|
||||
|
@ -51,14 +54,7 @@ struct Timestamps {
|
|||
extern int __pid;
|
||||
extern bool __replmode;
|
||||
extern bool __nomultics;
|
||||
volatile unsigned long long __kbirth;
|
||||
|
||||
static inline uint64_t ClocksToNanos(uint64_t x, uint64_t y) {
|
||||
// approximation of round(x*.323018) which is usually
|
||||
// the ratio between inva rdtsc ticks and nanoseconds
|
||||
uint128_t difference = x - y;
|
||||
return (difference * 338709) >> 20;
|
||||
}
|
||||
unsigned long long __kbirth; // see fork-nt.c
|
||||
|
||||
privileged static struct Timestamps kenter(void) {
|
||||
struct Timestamps ts;
|
||||
|
@ -67,7 +63,7 @@ privileged static struct Timestamps kenter(void) {
|
|||
if (!ts.birth) {
|
||||
ts.birth = kStartTsc;
|
||||
if (!ts.birth) ts.birth = 1;
|
||||
cmpxchg(&__kbirth, 0, ts.birth);
|
||||
_lockcmpxchg(&__kbirth, 0, ts.birth);
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
@ -78,7 +74,9 @@ privileged static void kleave(struct Timestamps ts) {
|
|||
elapse = unsignedsubtract(finish, ts.start);
|
||||
adjust = ts.birth + elapse;
|
||||
if (!adjust) adjust = 1;
|
||||
cmpxchg(&__kbirth, ts.birth, adjust); /* ignore overlapping time intervals */
|
||||
if (__kbirth == ts.birth) {
|
||||
_lockcmpxchg(&__kbirth, ts.birth, adjust); // ignore overlapping intervals
|
||||
}
|
||||
}
|
||||
|
||||
privileged static inline char *kadvance(char *p, char *e, long n) {
|
||||
|
@ -732,6 +730,32 @@ privileged size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
|
|||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged snprintf() w/o timestamp feature.
|
||||
*
|
||||
* This provides a marginal performance boost, but it means %T can no
|
||||
* longer be used.
|
||||
*
|
||||
* snprintf(".") l: 25𝑐 8𝑛𝑠
|
||||
* kusnprintf(".") l: 22𝑐 7𝑛𝑠
|
||||
* ksnprintf(".") l: 54𝑐 17𝑛𝑠
|
||||
*
|
||||
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
|
||||
* @param n is number of bytes available in buffer
|
||||
* @return length of output excluding NUL, which may exceed `n`
|
||||
* @see kprintf() for documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
privileged size_t kusnprintf(char *b, size_t n, const char *fmt, ...) {
|
||||
size_t m;
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
m = kformat(b, n, fmt, v, (struct Timestamps){0});
|
||||
va_end(v);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged vsnprintf().
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
void kprintf(const char *, ...);
|
||||
size_t ksnprintf(char *, size_t, const char *, ...);
|
||||
size_t kusnprintf(char *, size_t, const char *, ...);
|
||||
void kvprintf(const char *, va_list);
|
||||
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
||||
bool kisdangerous(const void *);
|
||||
|
|
47
libc/intrin/lockcmpxchg.c
Normal file
47
libc/intrin/lockcmpxchg.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*-*- 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/intrin/lockcmpxchg.h"
|
||||
|
||||
/**
|
||||
* Compares and exchanges w/ lock prefix.
|
||||
*
|
||||
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param size is automatically supplied by macro wrapper
|
||||
* @return true if value was exchanged, otherwise false
|
||||
* @see cmpxchg() if only written by one thread
|
||||
*/
|
||||
bool(_lockcmpxchg)(void *ifthing, intptr_t isequaltome,
|
||||
intptr_t replaceitwithme, size_t size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
return _lockcmpxchg((int8_t *)ifthing, (int8_t)isequaltome,
|
||||
(int8_t)replaceitwithme);
|
||||
case 2:
|
||||
return _lockcmpxchg((int16_t *)ifthing, (int16_t)isequaltome,
|
||||
(int16_t)replaceitwithme);
|
||||
case 4:
|
||||
return _lockcmpxchg((int32_t *)ifthing, (int32_t)isequaltome,
|
||||
(int32_t)replaceitwithme);
|
||||
case 8:
|
||||
return _lockcmpxchg((int64_t *)ifthing, (int64_t)isequaltome,
|
||||
(int64_t)replaceitwithme);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
29
libc/intrin/lockcmpxchg.h
Normal file
29
libc/intrin/lockcmpxchg.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_LOCKCMPXCHG_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_LOCKCMPXCHG_H_
|
||||
#include "libc/bits/asmflag.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
bool _lockcmpxchg(void *, intptr_t, intptr_t, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||
#define _lockcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm volatile(ZFLAG_ASM("lock cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
#else
|
||||
#define _lockcmpxchg(MEM, CMP, VAL) \
|
||||
_lockcmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
|
||||
#endif /* GNUC && !ANSI && x86 */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_LOCKCMPXCHG_H_ */
|
46
libc/intrin/lockcmpxchg16b.h
Normal file
46
libc/intrin/lockcmpxchg16b.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_H_
|
||||
#include "libc/bits/asmflag.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||
/**
|
||||
* Compares and exchanges 128-bit value, i.e.
|
||||
*
|
||||
* if (*IfThing == *IsEqualToMe) {
|
||||
* *IfThing = ReplaceItWithMe;
|
||||
* return true;
|
||||
* } else {
|
||||
* *IsEqualToMe = *IfThing;
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* @param IfThing should point to aligned memory
|
||||
* @param IsEqualToMe should point to in/out local variable
|
||||
* @param ReplaceItWithMe might become the new memory value
|
||||
* @return true if *IfThing was changed
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
static inline bool _lockcmpxchg16b(uint128_t *IfThing, uint128_t *IsEqualToMe,
|
||||
uint128_t ReplaceItWithMe) {
|
||||
bool DidIt;
|
||||
uint64_t ax, bx, cx, dx;
|
||||
ax = *IsEqualToMe;
|
||||
dx = *IsEqualToMe >> 64;
|
||||
bx = ReplaceItWithMe;
|
||||
cx = ReplaceItWithMe >> 64;
|
||||
asm volatile(ZFLAG_ASM("lock cmpxchg16b\t%1")
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(ax), "+d"(dx)
|
||||
: "b"(bx), "c"(cx));
|
||||
if (!DidIt) {
|
||||
*IsEqualToMe = ax | (uint128_t)dx << 64;
|
||||
}
|
||||
return DidIt;
|
||||
}
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_H_ */
|
44
libc/intrin/lockxadd.c
Normal file
44
libc/intrin/lockxadd.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- 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/intrin/lockxadd.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Compares and exchanges w/ lock prefix.
|
||||
*
|
||||
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param size is automatically supplied by macro wrapper
|
||||
* @return value at location `*ifthing` *before* addition
|
||||
* @see InterlockedAdd() for a very similar API
|
||||
* @see xadd() if only written by one thread
|
||||
*/
|
||||
intptr_t(_lockxadd)(void *ifthing, intptr_t replaceitwithme, size_t size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
return _lockxadd((int8_t *)ifthing, (int8_t)replaceitwithme);
|
||||
case 2:
|
||||
return _lockxadd((int16_t *)ifthing, (int16_t)replaceitwithme);
|
||||
case 4:
|
||||
return _lockxadd((int32_t *)ifthing, (int32_t)replaceitwithme);
|
||||
case 8:
|
||||
return _lockxadd((int64_t *)ifthing, (int64_t)replaceitwithme);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
22
libc/intrin/lockxadd.h
Normal file
22
libc/intrin/lockxadd.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKXADD_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_LOCKXADD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
intptr_t _lockxadd(void *, intptr_t, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||
#define _lockxadd(PTR, VAL) \
|
||||
({ \
|
||||
typeof(*(PTR)) Res; \
|
||||
typeof(Res) Val = (VAL); \
|
||||
asm volatile("lock xadd\t%0,%1" : "=r"(Res), "+m"(*(PTR)) : "0"(Val)); \
|
||||
Res; /* contains *PTR before addition cf. InterlockedAdd() */ \
|
||||
})
|
||||
#else
|
||||
#define _lockxadd(MEM, VAL) _lockxadd(MEM, (intptr_t)(VAL), sizeof(*(MEM)))
|
||||
#endif /* GNUC && !ANSI && x86 */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKXADD_H_ */
|
42
libc/intrin/lockxchg.c
Normal file
42
libc/intrin/lockxchg.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*-*- 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/intrin/lockxchg.h"
|
||||
|
||||
/**
|
||||
* Compares and exchanges w/ lock prefix.
|
||||
*
|
||||
* @param memory is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param size is automatically supplied by macro wrapper
|
||||
* @return true if value was exchanged, otherwise false
|
||||
* @see xchg()
|
||||
*/
|
||||
intptr_t(lockxchg)(void *memory, void *localvar, size_t size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
return lockxchg((int8_t *)memory, (int8_t *)localvar);
|
||||
case 2:
|
||||
return lockxchg((int16_t *)memory, (int16_t *)localvar);
|
||||
case 4:
|
||||
return lockxchg((int32_t *)memory, (int32_t *)localvar);
|
||||
case 8:
|
||||
return lockxchg((int64_t *)memory, (int64_t *)localvar);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
29
libc/intrin/lockxchg.h
Normal file
29
libc/intrin/lockxchg.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_LOCKXCHG_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_LOCKXCHG_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
intptr_t lockxchg(void *, void *, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
/**
|
||||
* Exchanges *MEMORY into *LOCALVAR w/ one operation.
|
||||
*
|
||||
* @param MEMORY is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param LOCALVAR is uint𝑘_t[hasatleast 1]
|
||||
* @return LOCALVAR[0]
|
||||
* @see xchg()
|
||||
*/
|
||||
#define lockxchg(MEMORY, LOCALVAR) \
|
||||
({ \
|
||||
asm("xchg\t%0,%1" : "+%m"(*(MEMORY)), "+r"(*(LOCALVAR))); \
|
||||
*(LOCALVAR); \
|
||||
})
|
||||
#else
|
||||
#define lockxchg(MEM, VAR) \
|
||||
lockxchg(MEM, VAR, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAR))))
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_LOCKXCHG_H_ */
|
|
@ -18,4 +18,4 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/internal.h"
|
||||
|
||||
uint32_t __ntconsolemode[2];
|
||||
uint32_t __ntconsolemode[3];
|
||||
|
|
|
@ -23,7 +23,12 @@
|
|||
#include "libc/runtime/internal.h"
|
||||
|
||||
uint32_t __winmainpid;
|
||||
const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle};
|
||||
|
||||
const char kConsoleHandles[3] = {
|
||||
kNtStdInputHandle,
|
||||
kNtStdOutputHandle,
|
||||
kNtStdErrorHandle,
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts cmd.exe gui back the way it was.
|
||||
|
@ -31,7 +36,7 @@ const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle};
|
|||
noasan void __restorewintty(void) {
|
||||
int i;
|
||||
if (IsWindows() && GetCurrentProcessId() == __winmainpid) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
for (i = 0; i < 3; ++i) {
|
||||
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
||||
}
|
||||
__winmainpid = 0;
|
||||
|
|
50
libc/intrin/spinlock.c
Normal file
50
libc/intrin/spinlock.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
|
||||
/**
|
||||
* Acquires spinlock.
|
||||
*/
|
||||
void cthread_spinlock(cthread_spinlock_t *lock) {
|
||||
#if 0
|
||||
// TODO(jart): possibly reenable for !NDEBUG when we have TLS
|
||||
int me = gettid();
|
||||
if (lock->x && lock->owner == me) {
|
||||
assert(!"cosmo spinlock not intended to be reentrant");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
do
|
||||
while (lock->x) asm("pause");
|
||||
while (!_lockcmpxchg(&lock->x, false, true));
|
||||
#if 0
|
||||
lock->owner = me;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases spinlock.
|
||||
*/
|
||||
void cthread_spunlock(cthread_spinlock_t *lock) {
|
||||
lock->x = false;
|
||||
}
|
22
libc/intrin/spinlock.h
Normal file
22
libc/intrin/spinlock.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* "Place each synchronization variable alone,
|
||||
separated by 128 bytes or in a separate cache line."
|
||||
──Intel Optimization Manual §8.3.1 */
|
||||
struct cthread_spinlock_t {
|
||||
bool x;
|
||||
int owner;
|
||||
char __ignore[128 - 1 - 4];
|
||||
} forcealign(128);
|
||||
|
||||
typedef struct cthread_spinlock_t cthread_spinlock_t;
|
||||
|
||||
void cthread_spinlock(cthread_spinlock_t *) dontthrow;
|
||||
void cthread_spunlock(cthread_spinlock_t *) dontthrow;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue