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:
Justine Tunney 2022-04-12 05:20:17 -07:00
parent f68f1789bd
commit 046c7ebd4a
110 changed files with 1514 additions and 876 deletions

View file

@ -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();

View file

@ -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
View 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
View 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_ */

View 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;
}
}

View 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
View 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
View 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_ */

View 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_ */

View file

@ -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) */

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/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);
}

View 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);
}

View file

@ -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
View 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
View 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();
}

View file

@ -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: \

View file

@ -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().
*

View file

@ -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
View 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
View 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_ */

View 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
View 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
View 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
View 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
View 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_ */

View file

@ -18,4 +18,4 @@
*/
#include "libc/runtime/internal.h"
uint32_t __ntconsolemode[2];
uint32_t __ntconsolemode[3];

View file

@ -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
View 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
View 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_ */