mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +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
3
Makefile
3
Makefile
|
@ -107,6 +107,7 @@ include libc/fmt/fmt.mk #─┘
|
||||||
include libc/calls/calls.mk #─┐
|
include libc/calls/calls.mk #─┐
|
||||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||||
include libc/crt/crt.mk # │ You can issue system calls
|
include libc/crt/crt.mk # │ You can issue system calls
|
||||||
|
include libc/thread/thread.mk # │
|
||||||
include libc/rand/rand.mk # │
|
include libc/rand/rand.mk # │
|
||||||
include libc/unicode/unicode.mk # │
|
include libc/unicode/unicode.mk # │
|
||||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||||
|
@ -117,7 +118,6 @@ include libc/time/time.mk # │ You can finally call malloc()
|
||||||
include libc/alg/alg.mk # │
|
include libc/alg/alg.mk # │
|
||||||
include libc/stdio/stdio.mk # │
|
include libc/stdio/stdio.mk # │
|
||||||
include third_party/libcxx/libcxx.mk # │
|
include third_party/libcxx/libcxx.mk # │
|
||||||
include libc/thread/thread.mk # │
|
|
||||||
include net/net.mk # │
|
include net/net.mk # │
|
||||||
include libc/log/log.mk # │
|
include libc/log/log.mk # │
|
||||||
include third_party/bzip2/bzip2.mk # │
|
include third_party/bzip2/bzip2.mk # │
|
||||||
|
@ -282,7 +282,6 @@ COSMOPOLITAN_OBJECTS = \
|
||||||
LIBC_NT_PSAPI \
|
LIBC_NT_PSAPI \
|
||||||
LIBC_NT_POWERPROF \
|
LIBC_NT_POWERPROF \
|
||||||
LIBC_NT_PDH \
|
LIBC_NT_PDH \
|
||||||
LIBC_NT_KERNELBASE \
|
|
||||||
LIBC_NT_SHELL32 \
|
LIBC_NT_SHELL32 \
|
||||||
LIBC_NT_GDI32 \
|
LIBC_NT_GDI32 \
|
||||||
LIBC_NT_COMDLG32 \
|
LIBC_NT_COMDLG32 \
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nt/nt/process.h"
|
#include "libc/nt/nt/process.h"
|
||||||
|
|
34
libc/bits/asmflag.h
Normal file
34
libc/bits/asmflag.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constraints for virtual machine flags.
|
||||||
|
* @note we beseech clang devs for flag constraints
|
||||||
|
*/
|
||||||
|
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
|
||||||
|
#define CFLAG_CONSTRAINT "=@ccc"
|
||||||
|
#define CFLAG_ASM(OP) OP
|
||||||
|
#define ZFLAG_CONSTRAINT "=@ccz"
|
||||||
|
#define ZFLAG_ASM(OP) OP
|
||||||
|
#define OFLAG_CONSTRAINT "=@cco"
|
||||||
|
#define OFLAG_ASM(OP) OP
|
||||||
|
#define SFLAG_CONSTRAINT "=@ccs"
|
||||||
|
#define SFLAG_ASM(SP) SP
|
||||||
|
#define ABOVE_CONSTRAINT "=@cca" /* i.e. !ZF && !CF */
|
||||||
|
#define ABOVEFLAG_ASM(OP) OP
|
||||||
|
#else
|
||||||
|
#define CFLAG_CONSTRAINT "=q"
|
||||||
|
#define CFLAG_ASM(OP) OP "\n\tsetc\t%b0"
|
||||||
|
#define ZFLAG_CONSTRAINT "=q"
|
||||||
|
#define ZFLAG_ASM(OP) OP "\n\tsetz\t%b0"
|
||||||
|
#define OFLAG_CONSTRAINT "=q"
|
||||||
|
#define OFLAG_ASM(OP) OP "\n\tseto\t%b0"
|
||||||
|
#define SFLAG_CONSTRAINT "=q"
|
||||||
|
#define SFLAG_ASM(SP) OP "\n\tsets\t%b0"
|
||||||
|
#define ABOVE_CONSTRAINT "=@cca"
|
||||||
|
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_ */
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
||||||
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
@ -31,8 +32,8 @@ COSMOPOLITAN_C_START_
|
||||||
})
|
})
|
||||||
#define atomic_init(PTR, VAL) atomic_store(PTR, VAL)
|
#define atomic_init(PTR, VAL) atomic_store(PTR, VAL)
|
||||||
#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL))
|
#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL))
|
||||||
#define atomic_compare_exchange_strong(X, Y, Z) lockcmpxchg(X, Y, Z)
|
#define atomic_compare_exchange_strong(X, Y, Z) _lockcmpxchg(X, Y, Z)
|
||||||
#define atomic_compare_exchange_weak(X, Y, Z) lockcmpxchg(X, Y, Z)
|
#define atomic_compare_exchange_weak(X, Y, Z) _lockcmpxchg(X, Y, Z)
|
||||||
#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR)
|
#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR)
|
||||||
#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL)
|
#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL)
|
||||||
#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0)
|
#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0)
|
||||||
|
|
45
libc/bits/bitop.h
Normal file
45
libc/bits/bitop.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_BITS_BITOP_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_BITS_BITOP_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
|
||||||
|
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
|
||||||
|
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
|
||||||
|
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
|
||||||
|
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
|
||||||
|
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
|
#define __BitOp(OP, BIT, MEM) \
|
||||||
|
({ \
|
||||||
|
bool OldBit; \
|
||||||
|
if (__builtin_constant_p(BIT)) { \
|
||||||
|
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
|
||||||
|
: CFLAG_CONSTRAINT(OldBit), \
|
||||||
|
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
|
||||||
|
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
|
||||||
|
: "cc"); \
|
||||||
|
} else if (sizeof((MEM)[0]) == 2) { \
|
||||||
|
asm(CFLAG_ASM(OP "\t%w2,%1") \
|
||||||
|
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||||
|
: "r"(BIT) \
|
||||||
|
: "cc"); \
|
||||||
|
} else if (sizeof((MEM)[0]) == 4) { \
|
||||||
|
asm(CFLAG_ASM(OP "\t%k2,%1") \
|
||||||
|
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||||
|
: "r"(BIT) \
|
||||||
|
: "cc"); \
|
||||||
|
} else if (sizeof((MEM)[0]) == 8) { \
|
||||||
|
asm(CFLAG_ASM(OP "\t%q2,%1") \
|
||||||
|
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||||
|
: "r"(BIT) \
|
||||||
|
: "cc"); \
|
||||||
|
} \
|
||||||
|
OldBit; \
|
||||||
|
})
|
||||||
|
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_BITS_BITOP_H_ */
|
181
libc/bits/bits.h
181
libc/bits/bits.h
|
@ -21,11 +21,6 @@ unsigned long roundup2pow(unsigned long) libcesque pureconst;
|
||||||
unsigned long roundup2log(unsigned long) libcesque pureconst;
|
unsigned long roundup2log(unsigned long) libcesque pureconst;
|
||||||
unsigned long rounddown2pow(unsigned long) libcesque pureconst;
|
unsigned long rounddown2pow(unsigned long) libcesque pureconst;
|
||||||
unsigned long hamming(unsigned long, unsigned long) pureconst;
|
unsigned long hamming(unsigned long, unsigned long) pureconst;
|
||||||
intptr_t lockxchg(void *, void *, size_t);
|
|
||||||
bool cmpxchg(void *, intptr_t, intptr_t, size_t);
|
|
||||||
bool lockcmpxchg(void *, intptr_t, intptr_t, size_t);
|
|
||||||
intptr_t atomic_load(void *, size_t);
|
|
||||||
intptr_t atomic_store(void *, intptr_t, size_t);
|
|
||||||
unsigned bextra(const unsigned *, size_t, char);
|
unsigned bextra(const unsigned *, size_t, char);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
|
@ -136,84 +131,6 @@ unsigned bextra(const unsigned *, size_t, char);
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
|
|
||||||
/*
|
|
||||||
* Constraints for virtual machine flags.
|
|
||||||
* @note we beseech clang devs for flag constraints
|
|
||||||
*/
|
|
||||||
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
|
|
||||||
#define CFLAG_CONSTRAINT "=@ccc"
|
|
||||||
#define CFLAG_ASM(OP) OP
|
|
||||||
#define ZFLAG_CONSTRAINT "=@ccz"
|
|
||||||
#define ZFLAG_ASM(OP) OP
|
|
||||||
#define OFLAG_CONSTRAINT "=@cco"
|
|
||||||
#define OFLAG_ASM(OP) OP
|
|
||||||
#define SFLAG_CONSTRAINT "=@ccs"
|
|
||||||
#define SFLAG_ASM(SP) SP
|
|
||||||
#define ABOVE_CONSTRAINT "=@cca" /* i.e. !ZF && !CF */
|
|
||||||
#define ABOVEFLAG_ASM(OP) OP
|
|
||||||
#else
|
|
||||||
#define CFLAG_CONSTRAINT "=q"
|
|
||||||
#define CFLAG_ASM(OP) OP "\n\tsetc\t%b0"
|
|
||||||
#define ZFLAG_CONSTRAINT "=q"
|
|
||||||
#define ZFLAG_ASM(OP) OP "\n\tsetz\t%b0"
|
|
||||||
#define OFLAG_CONSTRAINT "=q"
|
|
||||||
#define OFLAG_ASM(OP) OP "\n\tseto\t%b0"
|
|
||||||
#define SFLAG_CONSTRAINT "=q"
|
|
||||||
#define SFLAG_ASM(SP) OP "\n\tsets\t%b0"
|
|
||||||
#define ABOVE_CONSTRAINT "=@cca"
|
|
||||||
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads scalar from memory w/ one operation.
|
|
||||||
*
|
|
||||||
* @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()
|
|
||||||
*/
|
|
||||||
#define atomic_load(MEM) \
|
|
||||||
({ \
|
|
||||||
autotype(MEM) Mem = (MEM); \
|
|
||||||
typeof(*Mem) Reg; \
|
|
||||||
asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \
|
|
||||||
Reg; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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()
|
|
||||||
*/
|
|
||||||
#define atomic_store(MEM, VAL) \
|
|
||||||
({ \
|
|
||||||
autotype(VAL) Val = (VAL); \
|
|
||||||
typeof(&Val) Mem = (MEM); \
|
|
||||||
asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \
|
|
||||||
Val; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
|
|
||||||
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
|
|
||||||
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
|
|
||||||
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
|
|
||||||
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
|
|
||||||
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
|
|
||||||
|
|
||||||
#define lockinc(MEM) __ArithmeticOp1("lock inc", MEM)
|
#define lockinc(MEM) __ArithmeticOp1("lock inc", MEM)
|
||||||
#define lockdec(MEM) __ArithmeticOp1("lock dec", MEM)
|
#define lockdec(MEM) __ArithmeticOp1("lock dec", MEM)
|
||||||
#define locknot(MEM) __ArithmeticOp1("lock not", MEM)
|
#define locknot(MEM) __ArithmeticOp1("lock not", MEM)
|
||||||
|
@ -225,66 +142,6 @@ unsigned bextra(const unsigned *, size_t, char);
|
||||||
#define lockandeq(MEM, VAL) __ArithmeticOp2("lock and", VAL, MEM)
|
#define lockandeq(MEM, VAL) __ArithmeticOp2("lock and", VAL, MEM)
|
||||||
#define lockoreq(MEM, VAL) __ArithmeticOp2("lock or", VAL, MEM)
|
#define lockoreq(MEM, VAL) __ArithmeticOp2("lock or", VAL, MEM)
|
||||||
|
|
||||||
/**
|
|
||||||
* 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); \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares and exchanges.
|
|
||||||
*
|
|
||||||
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
|
||||||
* @return true if value was exchanged, otherwise false
|
|
||||||
* @see lockcmpxchg()
|
|
||||||
*/
|
|
||||||
#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; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares and exchanges w/ one operation.
|
|
||||||
*
|
|
||||||
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
|
||||||
* @return true if value was exchanged, otherwise false
|
|
||||||
* @see lockcmpxchg()
|
|
||||||
*/
|
|
||||||
#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; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define IsAddressCanonicalForm(P) \
|
|
||||||
({ \
|
|
||||||
intptr_t p2 = (intptr_t)(P); \
|
|
||||||
(0xffff800000000000l <= p2 && p2 <= 0x00007fffffffffffl); \
|
|
||||||
})
|
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § bits » implementation details ─╬─│┼
|
│ cosmopolitan § bits » implementation details ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
@ -301,44 +158,6 @@ unsigned bextra(const unsigned *, size_t, char);
|
||||||
MEM; \
|
MEM; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define __BitOp(OP, BIT, MEM) \
|
|
||||||
({ \
|
|
||||||
bool OldBit; \
|
|
||||||
if (__builtin_constant_p(BIT)) { \
|
|
||||||
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
|
|
||||||
: CFLAG_CONSTRAINT(OldBit), \
|
|
||||||
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
|
|
||||||
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
|
|
||||||
: "cc"); \
|
|
||||||
} else if (sizeof((MEM)[0]) == 2) { \
|
|
||||||
asm(CFLAG_ASM(OP "\t%w2,%1") \
|
|
||||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
|
||||||
: "r"(BIT) \
|
|
||||||
: "cc"); \
|
|
||||||
} else if (sizeof((MEM)[0]) == 4) { \
|
|
||||||
asm(CFLAG_ASM(OP "\t%k2,%1") \
|
|
||||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
|
||||||
: "r"(BIT) \
|
|
||||||
: "cc"); \
|
|
||||||
} else if (sizeof((MEM)[0]) == 8) { \
|
|
||||||
asm(CFLAG_ASM(OP "\t%q2,%1") \
|
|
||||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
|
||||||
: "r"(BIT) \
|
|
||||||
: "cc"); \
|
|
||||||
} \
|
|
||||||
OldBit; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define cmpxchg(MEM, CMP, VAL) \
|
|
||||||
cmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
|
|
||||||
#define lockcmpxchg(MEM, CMP, VAL) \
|
|
||||||
lockcmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
|
|
||||||
#define lockxchg(MEM, VAR) \
|
|
||||||
lockxchg(MEM, VAR, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAR))))
|
|
||||||
#define atomic_store(MEM, VAL) \
|
|
||||||
atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL))))
|
|
||||||
#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM)))
|
|
||||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||||
/**
|
/**
|
||||||
* Computes `(a + b) / 2` assuming unsigned.
|
* Computes `(a + b) / 2` assuming unsigned.
|
||||||
|
*
|
||||||
|
* This implementation is the fastest on AMD Zen architecture.
|
||||||
*/
|
*/
|
||||||
#define _midpoint(a, b) \
|
#define _midpoint(a, b) \
|
||||||
({ \
|
({ \
|
||||||
|
@ -18,6 +21,12 @@
|
||||||
: "r"(b_)); \
|
: "r"(b_)); \
|
||||||
a_; \
|
a_; \
|
||||||
})
|
})
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* Computes `(a + b) / 2` assuming unsigned.
|
||||||
|
*/
|
||||||
|
#define _midpoint(a, b) (((a) & (b)) + ((a) ^ (b)) / 2)
|
||||||
|
#endif /* __GNUC__ && !__STRICT_ANSI__ && x86 */
|
||||||
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ */
|
#endif /* COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ */
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
@ -41,7 +41,7 @@ int atfork(void *fn, void *arg) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
i = g_atfork.i;
|
i = g_atfork.i;
|
||||||
if (i == ARRAYLEN(g_atfork.p)) return enomem();
|
if (i == ARRAYLEN(g_atfork.p)) return enomem();
|
||||||
if (cmpxchg(&g_atfork.i, i, i + 1)) {
|
if (_cmpxchg(&g_atfork.i, i, i + 1)) {
|
||||||
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,7 @@ int getdomainname(char *, size_t);
|
||||||
int gethostname(char *, size_t);
|
int gethostname(char *, size_t);
|
||||||
int getpgid(int);
|
int getpgid(int);
|
||||||
int getpid(void);
|
int getpid(void);
|
||||||
|
int gettid(void);
|
||||||
int getppid(void);
|
int getppid(void);
|
||||||
int getpriority(int, unsigned);
|
int getpriority(int, unsigned);
|
||||||
int getrlimit(int, struct rlimit *);
|
int getrlimit(int, struct rlimit *);
|
||||||
|
@ -227,7 +228,6 @@ uint32_t geteuid(void) nosideeffect;
|
||||||
uint32_t getgid(void) nosideeffect;
|
uint32_t getgid(void) nosideeffect;
|
||||||
uint32_t getpgrp(void) nosideeffect;
|
uint32_t getpgrp(void) nosideeffect;
|
||||||
uint32_t getsid(int) nosideeffect;
|
uint32_t getsid(int) nosideeffect;
|
||||||
uint32_t gettid(void) nosideeffect;
|
|
||||||
uint32_t getuid(void) nosideeffect;
|
uint32_t getuid(void) nosideeffect;
|
||||||
uint32_t umask(int32_t);
|
uint32_t umask(int32_t);
|
||||||
void rewinddir(DIR *);
|
void rewinddir(DIR *);
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
@ -40,7 +40,7 @@ int __ensurefds(int fd) {
|
||||||
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||||
memcpy(p2, p1, n1 * sizeof(*p1));
|
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||||
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
||||||
if (cmpxchg(&g_fds.p, p1, p2)) {
|
if (_cmpxchg(&g_fds.p, p1, p2)) {
|
||||||
g_fds.n = n2;
|
g_fds.n = n2;
|
||||||
if (weaken(free)) {
|
if (weaken(free)) {
|
||||||
if (p1 == g_fds.__init_p) {
|
if (p1 == g_fds.__init_p) {
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/flock.h"
|
#include "libc/calls/struct/flock.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/enum/accessmask.h"
|
#include "libc/nt/enum/accessmask.h"
|
||||||
#include "libc/nt/enum/fileflagandattributes.h"
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
|
@ -45,8 +45,8 @@ static textwindows int sys_fcntl_nt_reservefd(int start) {
|
||||||
if (fd >= g_fds.n) {
|
if (fd >= g_fds.n) {
|
||||||
if (__ensurefds(fd) == -1) return -1;
|
if (__ensurefds(fd) == -1) return -1;
|
||||||
}
|
}
|
||||||
cmpxchg(&g_fds.f, fd, fd + 1);
|
_cmpxchg(&g_fds.f, fd, fd + 1);
|
||||||
if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,5 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
|
||||||
|
cthread_spinlock_t __sig_lock;
|
||||||
unsigned __sighandrvas[NSIG];
|
unsigned __sighandrvas[NSIG];
|
||||||
unsigned __sighandflags[NSIG];
|
unsigned __sighandflags[NSIG];
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "libc/calls/struct/winsize.h"
|
#include "libc/calls/struct/winsize.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/struct/context.h"
|
#include "libc/nt/struct/context.h"
|
||||||
|
@ -72,6 +73,7 @@ extern const struct Fd kEmptyFd;
|
||||||
|
|
||||||
hidden extern int __vforked;
|
hidden extern int __vforked;
|
||||||
hidden extern bool __time_critical;
|
hidden extern bool __time_critical;
|
||||||
|
hidden extern cthread_spinlock_t __sig_lock;
|
||||||
hidden extern unsigned __sighandrvas[NSIG];
|
hidden extern unsigned __sighandrvas[NSIG];
|
||||||
hidden extern unsigned __sighandflags[NSIG];
|
hidden extern unsigned __sighandflags[NSIG];
|
||||||
hidden extern struct Fds g_fds;
|
hidden extern struct Fds g_fds;
|
||||||
|
@ -176,6 +178,7 @@ i32 sys_renameat(i32, const char *, i32, const char *) hidden;
|
||||||
i32 sys_sched_setaffinity(i32, u64, const void *) hidden;
|
i32 sys_sched_setaffinity(i32, u64, const void *) hidden;
|
||||||
i32 sys_sched_yield(void) hidden;
|
i32 sys_sched_yield(void) hidden;
|
||||||
i32 sys_setitimer(i32, const struct itimerval *, struct itimerval *) hidden;
|
i32 sys_setitimer(i32, const struct itimerval *, struct itimerval *) hidden;
|
||||||
|
i32 sys_setpgid(i32, i32) hidden;
|
||||||
i32 sys_setpriority(i32, u32, i32) hidden;
|
i32 sys_setpriority(i32, u32, i32) hidden;
|
||||||
i32 sys_setresgid(uint32_t, uint32_t, uint32_t) hidden;
|
i32 sys_setresgid(uint32_t, uint32_t, uint32_t) hidden;
|
||||||
i32 sys_setresuid(uint32_t, uint32_t, uint32_t) hidden;
|
i32 sys_setresuid(uint32_t, uint32_t, uint32_t) hidden;
|
||||||
|
@ -330,7 +333,8 @@ struct NtOverlapped *_offset2overlap(int64_t, struct NtOverlapped *) hidden;
|
||||||
unsigned __wincrash_nt(struct NtExceptionPointers *);
|
unsigned __wincrash_nt(struct NtExceptionPointers *);
|
||||||
void *GetProcAddressModule(const char *, const char *) hidden;
|
void *GetProcAddressModule(const char *, const char *) hidden;
|
||||||
void WinMainForked(void) hidden;
|
void WinMainForked(void) hidden;
|
||||||
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
|
void _ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
|
||||||
|
void _ntlinux2context(struct NtContext *, const ucontext_t *) hidden;
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § syscalls » metal ─╬─│┼
|
│ cosmopolitan § syscalls » metal ─╬─│┼
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
#include "libc/nt/iphlpapi.h"
|
#include "libc/nt/iphlpapi.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
@ -275,7 +275,7 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
|
||||||
if (!node) goto err;
|
if (!node) goto err;
|
||||||
if (!__hostInfo) {
|
if (!__hostInfo) {
|
||||||
__hostInfo = node;
|
__hostInfo = node;
|
||||||
if (cmpxchg(&once, false, true)) {
|
if (_cmpxchg(&once, false, true)) {
|
||||||
atexit(freeHostInfo);
|
atexit(freeHostInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/getconsolectrlevent.h"
|
#include "libc/calls/getconsolectrlevent.internal.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -30,34 +30,60 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows int sys_kill_nt(int pid, int sig) {
|
textwindows int sys_kill_nt(int pid, int sig) {
|
||||||
bool ok;
|
bool32 ok;
|
||||||
int64_t handle;
|
int64_t handle;
|
||||||
int event, ntpid;
|
int event, ntpid;
|
||||||
if (pid) {
|
|
||||||
pid = ABS(pid);
|
// is killing everything except init really worth supporting?
|
||||||
if ((event = GetConsoleCtrlEvent(sig)) != -1) {
|
if (pid == -1) return einval();
|
||||||
/* kill(pid, SIGINT|SIGQUIT) */
|
|
||||||
if (__isfdkind(pid, kFdProcess)) {
|
// XXX: NT doesn't really have process groups. For instance the
|
||||||
ntpid = GetProcessId(g_fds.p[pid].handle);
|
// CreateProcess() flag for starting a process group actually
|
||||||
} else if (!__isfdopen(pid)) {
|
// just does an "ignore ctrl-c" internally.
|
||||||
/* XXX: this is sloppy (see fork-nt.c) */
|
pid = ABS(pid);
|
||||||
ntpid = pid;
|
|
||||||
} else {
|
// If we're targeting current process group then just call raise().
|
||||||
return esrch();
|
if (!pid || pid == getpid()) {
|
||||||
}
|
|
||||||
ok = !!GenerateConsoleCtrlEvent(event, ntpid);
|
|
||||||
} else if (__isfdkind(pid, kFdProcess)) {
|
|
||||||
ok = !!TerminateProcess(g_fds.p[pid].handle, 128 + sig);
|
|
||||||
if (!ok && GetLastError() == kNtErrorAccessDenied) ok = true;
|
|
||||||
} else if ((handle = OpenProcess(kNtProcessTerminate, false, pid))) {
|
|
||||||
ok = !!TerminateProcess(handle, 128 + sig);
|
|
||||||
if (!ok && GetLastError() == kNtErrorAccessDenied) ok = true;
|
|
||||||
CloseHandle(handle);
|
|
||||||
} else {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
return ok ? 0 : __winerr();
|
|
||||||
} else {
|
|
||||||
return raise(sig);
|
return raise(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateConsoleCtrlEvent() will always signal groups and there's
|
||||||
|
// nothing we can do about it, unless we have a GUI GetMessage loop
|
||||||
|
// and alternatively create a centralized signal daemon like cygwin
|
||||||
|
if ((event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||||
|
// we're killing with SIGINT or SIGQUIT which are the only two
|
||||||
|
// signals we can really use, since TerminateProcess() makes
|
||||||
|
// everything else effectively a SIGKILL ;_;
|
||||||
|
if (__isfdkind(pid, kFdProcess)) {
|
||||||
|
ntpid = GetProcessId(g_fds.p[pid].handle);
|
||||||
|
} else if (!__isfdopen(pid)) {
|
||||||
|
ntpid = pid; // XXX: suboptimal
|
||||||
|
} else {
|
||||||
|
return esrch();
|
||||||
|
}
|
||||||
|
if (GenerateConsoleCtrlEvent(event, ntpid)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: Is this a cosmo pid that was returned by fork_nt?
|
||||||
|
if (__isfdkind(pid, kFdProcess)) {
|
||||||
|
ok = TerminateProcess(g_fds.p[pid].handle, 128 + sig);
|
||||||
|
if (!ok && GetLastError() == kNtErrorAccessDenied) ok = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: Is this a raw new technology pid? Because that's messy.
|
||||||
|
if ((handle = OpenProcess(kNtProcessTerminate, false, pid))) {
|
||||||
|
ok = TerminateProcess(handle, 128 + sig);
|
||||||
|
if (!ok && GetLastError() == kNtErrorAccessDenied) {
|
||||||
|
ok = true; // cargo culting other codebases here
|
||||||
|
}
|
||||||
|
CloseHandle(handle);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends signal to process.
|
* Sends signal to process.
|
||||||
|
@ -38,9 +40,12 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
int kill(int pid, int sig) {
|
int kill(int pid, int sig) {
|
||||||
|
int rc;
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return sys_kill(pid, sig, 1);
|
rc = sys_kill(pid, sig, 1);
|
||||||
} else {
|
} else {
|
||||||
return sys_kill_nt(pid, sig);
|
rc = sys_kill_nt(pid, sig);
|
||||||
}
|
}
|
||||||
|
STRACE("kill(%d, %s) → %d% m", pid, strsignal(sig), rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "libc/nt/struct/context.h"
|
#include "libc/nt/struct/context.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
textwindows void ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
||||||
if (!cr) return;
|
if (!cr) return;
|
||||||
ctx->uc_flags = cr->EFlags;
|
ctx->uc_flags = cr->EFlags;
|
||||||
ctx->uc_mcontext.gregs[REG_EFL] = cr->EFlags;
|
ctx->uc_mcontext.gregs[REG_EFL] = cr->EFlags;
|
||||||
|
@ -48,3 +48,30 @@ textwindows void ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
||||||
ctx->uc_mcontext.fpregs = &ctx->__fpustate;
|
ctx->uc_mcontext.fpregs = &ctx->__fpustate;
|
||||||
memcpy(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate));
|
memcpy(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) {
|
||||||
|
if (!cr) return;
|
||||||
|
cr->EFlags = ctx->uc_flags;
|
||||||
|
cr->EFlags = ctx->uc_mcontext.gregs[REG_EFL];
|
||||||
|
cr->Rax = ctx->uc_mcontext.rax;
|
||||||
|
cr->Rbx = ctx->uc_mcontext.rbx;
|
||||||
|
cr->Rcx = ctx->uc_mcontext.rcx;
|
||||||
|
cr->Rdx = ctx->uc_mcontext.rdx;
|
||||||
|
cr->Rdi = ctx->uc_mcontext.rdi;
|
||||||
|
cr->Rsi = ctx->uc_mcontext.rsi;
|
||||||
|
cr->Rbp = ctx->uc_mcontext.rbp;
|
||||||
|
cr->Rsp = ctx->uc_mcontext.rsp;
|
||||||
|
cr->Rip = ctx->uc_mcontext.rip;
|
||||||
|
cr->R8 = ctx->uc_mcontext.r8;
|
||||||
|
cr->R9 = ctx->uc_mcontext.r9;
|
||||||
|
cr->R10 = ctx->uc_mcontext.r10;
|
||||||
|
cr->R11 = ctx->uc_mcontext.r11;
|
||||||
|
cr->R12 = ctx->uc_mcontext.r12;
|
||||||
|
cr->R13 = ctx->uc_mcontext.r13;
|
||||||
|
cr->R14 = ctx->uc_mcontext.r14;
|
||||||
|
cr->R15 = ctx->uc_mcontext.r15;
|
||||||
|
cr->SegCs = ctx->uc_mcontext.cs;
|
||||||
|
cr->SegGs = ctx->uc_mcontext.gs;
|
||||||
|
cr->SegFs = ctx->uc_mcontext.fs;
|
||||||
|
memcpy(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate));
|
||||||
|
}
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/nexgen32e/nt2sysv.h"
|
||||||
#include "libc/nt/enum/ctrlevent.h"
|
#include "libc/nt/enum/ctrlevent.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) {
|
textwindows bool32 __onntconsoleevent(uint32_t dwCtrlType) {
|
||||||
|
STRACE("__onntconsoleevent(%u)", dwCtrlType);
|
||||||
switch (dwCtrlType) {
|
switch (dwCtrlType) {
|
||||||
case kNtCtrlCEvent:
|
case kNtCtrlCEvent:
|
||||||
__sig_add(SIGINT, SI_KERNEL);
|
__sig_add(SIGINT, SI_KERNEL);
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for any signal.
|
* Waits for signal.
|
||||||
*
|
*
|
||||||
* This suspends execution until an unmasked signal is delivered and its
|
* This suspends execution until an unmasked signal is delivered and its
|
||||||
* callback function has been called. The current signal mask is used.
|
* callback function has been called. The current signal mask is used.
|
||||||
|
|
|
@ -17,16 +17,25 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/getconsolectrlevent.h"
|
#include "libc/calls/getconsolectrlevent.internal.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
|
#include "libc/nt/process.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/synchronization.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
|
static textwindows inline bool HasWorkingConsole(void) {
|
||||||
|
return !!(__ntconsolemode[0] | __ntconsolemode[1] | __ntconsolemode[2]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends signal to this process.
|
* Sends signal to this process.
|
||||||
*
|
*
|
||||||
|
@ -36,7 +45,7 @@
|
||||||
*/
|
*/
|
||||||
int raise(int sig) {
|
int raise(int sig) {
|
||||||
int rc, event;
|
int rc, event;
|
||||||
STRACE("raise(%d) → [...]", sig);
|
STRACE("raise(%s) → [...]", strsignal(sig));
|
||||||
if (sig == SIGTRAP) {
|
if (sig == SIGTRAP) {
|
||||||
DebugBreak();
|
DebugBreak();
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -45,18 +54,27 @@ int raise(int sig) {
|
||||||
x = 1 / x;
|
x = 1 / x;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
|
// XXX: should be tkill() or tgkill() on linux
|
||||||
rc = sys_kill(getpid(), sig, 1);
|
rc = sys_kill(getpid(), sig, 1);
|
||||||
} else {
|
} else {
|
||||||
if ((event = GetConsoleCtrlEvent(sig)) != -1) {
|
if (HasWorkingConsole() && (event = GetConsoleCtrlEvent(sig)) != -1) {
|
||||||
|
// XXX: MSDN says "If this parameter is zero, the signal is
|
||||||
|
// generated in all processes that share the console of the
|
||||||
|
// calling process." which seems to imply multiple process
|
||||||
|
// groups potentially. We just shouldn't use this because it
|
||||||
|
// doesn't make any sense and it's so evil.
|
||||||
if (GenerateConsoleCtrlEvent(event, 0)) {
|
if (GenerateConsoleCtrlEvent(event, 0)) {
|
||||||
|
// XXX: we shouldn't need to sleep here ctrl-c is evil on nt
|
||||||
|
SleepEx(100, false);
|
||||||
|
__sig_check(false);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else {
|
} else {
|
||||||
rc = __winerr();
|
rc = __winerr();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = __sig_add(sig, SI_USER);
|
rc = __sig_raise(sig, SI_USER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STRACE("[...] raise → %d% m", rc);
|
STRACE("[...] raise(%s) → %d% m", strsignal(sig), rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,9 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
|
|
||||||
void __releasefd(int fd) {
|
void __releasefd(int fd) {
|
||||||
int x;
|
int x;
|
||||||
|
@ -26,6 +27,6 @@ void __releasefd(int fd) {
|
||||||
do {
|
do {
|
||||||
x = g_fds.f;
|
x = g_fds.f;
|
||||||
if (fd >= x) break;
|
if (fd >= x) break;
|
||||||
} while (!cmpxchg(&g_fds.f, x, fd));
|
} while (!_lockcmpxchg(&g_fds.f, x, fd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
@ -31,8 +31,8 @@ int __reservefd(void) {
|
||||||
if (fd >= g_fds.n) {
|
if (fd >= g_fds.n) {
|
||||||
if (__ensurefds(fd) == -1) return -1;
|
if (__ensurefds(fd) == -1) return -1;
|
||||||
}
|
}
|
||||||
cmpxchg(&g_fds.f, fd, fd + 1);
|
_cmpxchg(&g_fds.f, fd, fd + 1);
|
||||||
if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ textwindows int __sample_pids(int pids[hasatleast 64],
|
||||||
bool exploratory) {
|
bool exploratory) {
|
||||||
static uint64_t rando = 1;
|
static uint64_t rando = 1;
|
||||||
uint32_t i, j, base, count;
|
uint32_t i, j, base, count;
|
||||||
base = KnuthLinearCongruentialGenerator(&rando);
|
base = KnuthLinearCongruentialGenerator(&rando) >> 32;
|
||||||
for (count = i = 0; i < g_fds.n; ++i) {
|
for (count = i = 0; i < g_fds.n; ++i) {
|
||||||
j = (base + i) % g_fds.n;
|
j = (base + i) % g_fds.n;
|
||||||
if (g_fds.p[j].kind == kFdProcess && (!exploratory || !g_fds.p[j].zombie)) {
|
if (g_fds.p[j].kind == kFdProcess && (!exploratory || !g_fds.p[j].zombie)) {
|
||||||
|
|
58
libc/calls/setpgid.c
Normal file
58
libc/calls/setpgid.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/nt/console.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes process group for process.
|
||||||
|
*/
|
||||||
|
int setpgid(int pid, int pgid) {
|
||||||
|
int rc, me;
|
||||||
|
if (!IsWindows()) {
|
||||||
|
rc = sys_setpgid(pid, pgid);
|
||||||
|
} else {
|
||||||
|
me = getpid();
|
||||||
|
if (pid == me && pgid == me) {
|
||||||
|
/*
|
||||||
|
* "When a process is created with CREATE_NEW_PROCESS_GROUP
|
||||||
|
* specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE)
|
||||||
|
* is made on behalf of the new process; this means that the new
|
||||||
|
* process has CTRL+C disabled. This lets shells handle CTRL+C
|
||||||
|
* themselves, and selectively pass that signal on to
|
||||||
|
* sub-processes. CTRL+BREAK is not disabled, and may be used to
|
||||||
|
* interrupt the process/process group."
|
||||||
|
* ──Quoth MSDN § CreateProcessW()
|
||||||
|
*/
|
||||||
|
if (SetConsoleCtrlHandler(0, 1)) {
|
||||||
|
rc = 0;
|
||||||
|
} else {
|
||||||
|
rc = __winerr();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// irregular use cases not supported on windows
|
||||||
|
rc = einval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STRACE("setpgid(%d, %d) → %d% m", pid, pgid, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
212
libc/calls/sig.c
212
libc/calls/sig.c
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
|
@ -24,6 +23,9 @@
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/calls/typedef/sigaction_f.h"
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -37,18 +39,6 @@
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LOCK \
|
|
||||||
for (;;) \
|
|
||||||
if (lockcmpxchg(&__sig.lock, false, true)) { \
|
|
||||||
asm volatile("" ::: "memory")
|
|
||||||
|
|
||||||
#define UNLOCK \
|
|
||||||
asm volatile("" ::: "memory"); \
|
|
||||||
__sig.lock = false; \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
else sched_yield()
|
|
||||||
|
|
||||||
struct Signal {
|
struct Signal {
|
||||||
struct Signal *next;
|
struct Signal *next;
|
||||||
bool used;
|
bool used;
|
||||||
|
@ -57,7 +47,6 @@ struct Signal {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Signals {
|
struct Signals {
|
||||||
bool lock;
|
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
struct Signal *queue;
|
struct Signal *queue;
|
||||||
struct Signal mem[__SIG_QUEUE_LENGTH];
|
struct Signal mem[__SIG_QUEUE_LENGTH];
|
||||||
|
@ -67,15 +56,19 @@ struct Signals __sig; // TODO(jart): Need TLS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates piece of memory for storing pending signal.
|
* Allocates piece of memory for storing pending signal.
|
||||||
|
* @assume lock is held
|
||||||
*/
|
*/
|
||||||
static textwindows struct Signal *__sig_alloc(void) {
|
static textwindows struct Signal *__sig_alloc(void) {
|
||||||
int i;
|
int i;
|
||||||
|
struct Signal *res = 0;
|
||||||
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
||||||
if (!__sig.mem[i].used && lockcmpxchg(&__sig.mem[i].used, false, true)) {
|
if (!__sig.mem[i].used) {
|
||||||
return __sig.mem + i;
|
__sig.mem[i].used = true;
|
||||||
|
res = __sig.mem + i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,7 +85,7 @@ static textwindows void __sig_free(struct Signal *mem) {
|
||||||
static textwindows struct Signal *__sig_remove(void) {
|
static textwindows struct Signal *__sig_remove(void) {
|
||||||
struct Signal *prev, *res;
|
struct Signal *prev, *res;
|
||||||
if (__sig.queue) {
|
if (__sig.queue) {
|
||||||
LOCK;
|
cthread_spinlock(&__sig_lock);
|
||||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||||
if (!sigismember(&__sig.mask, res->sig)) {
|
if (!sigismember(&__sig.mask, res->sig)) {
|
||||||
if (res == __sig.queue) {
|
if (res == __sig.queue) {
|
||||||
|
@ -106,7 +99,7 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||||
STRACE("%s is masked", strsignal(res->sig));
|
STRACE("%s is masked", strsignal(res->sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UNLOCK;
|
cthread_spunlock(&__sig_lock);
|
||||||
} else {
|
} else {
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
|
@ -114,28 +107,60 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delivers signal.
|
* Delivers signal to callback.
|
||||||
* @note called from main thread
|
* @note called from main thread
|
||||||
* @return true if EINTR should be returned by caller
|
* @return true if EINTR should be returned by caller
|
||||||
*/
|
*/
|
||||||
static textwindows bool __sig_deliver(bool restartable, struct Signal *sig,
|
static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||||
unsigned rva) {
|
ucontext_t *ctx) {
|
||||||
unsigned flags;
|
unsigned rva, flags;
|
||||||
siginfo_t info;
|
siginfo_t info, *infop;
|
||||||
flags = __sighandflags[sig->sig];
|
STRACE("delivering %s", strsignal(sig));
|
||||||
// TODO(jart): polyfill prevention of re-entry
|
|
||||||
if (flags & SA_RESETHAND) {
|
// enter the signal
|
||||||
__sighandrvas[sig->sig] = (int32_t)(intptr_t)SIG_DFL;
|
cthread_spinlock(&__sig_lock);
|
||||||
|
rva = __sighandrvas[sig];
|
||||||
|
flags = __sighandflags[sig];
|
||||||
|
if (~flags & SA_NODEFER) {
|
||||||
|
// by default we try to avoid reentering a signal handler. for
|
||||||
|
// example, if a sigsegv handler segfaults, then we'd want the
|
||||||
|
// second signal to just kill the process. doing this means we
|
||||||
|
// track state. that's bad if you want to longjmp() out of the
|
||||||
|
// signal handler. in that case you must use SA_NODEFER.
|
||||||
|
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||||
}
|
}
|
||||||
STRACE("delivering %s", strsignal(sig->sig));
|
cthread_spunlock(&__sig_lock);
|
||||||
bzero(&info, sizeof(info));
|
|
||||||
info.si_signo = sig->sig;
|
// setup the somewhat expensive information args
|
||||||
info.si_code = sig->si_code;
|
// only if they're requested by the user in sigaction()
|
||||||
((sigaction_f)(_base + rva))(sig->sig, &info, 0);
|
if (flags & SA_SIGINFO) {
|
||||||
|
bzero(&info, sizeof(info));
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_code = si_code;
|
||||||
|
infop = &info;
|
||||||
|
} else {
|
||||||
|
infop = 0;
|
||||||
|
ctx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handover control to user
|
||||||
|
((sigaction_f)(_base + rva))(sig, infop, ctx);
|
||||||
|
|
||||||
|
// leave the signal
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
|
if (~flags & SA_NODEFER) {
|
||||||
|
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||||
|
}
|
||||||
|
if (flags & SA_RESETHAND) {
|
||||||
|
STRACE("resetting oneshot signal handler");
|
||||||
|
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||||
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
|
||||||
if (!restartable) {
|
if (!restartable) {
|
||||||
return true; // always send EINTR for wait4(), poll(), etc.
|
return true; // always send EINTR for wait4(), poll(), etc.
|
||||||
} else if (flags & SA_RESTART) {
|
} else if (flags & SA_RESTART) {
|
||||||
STRACE("restarting syscall on %s", strsignal(sig->sig));
|
STRACE("restarting syscall on %s", strsignal(sig));
|
||||||
return false; // resume syscall for read(), write(), etc.
|
return false; // resume syscall for read(), write(), etc.
|
||||||
} else {
|
} else {
|
||||||
return true; // default course is to raise EINTR
|
return true; // default course is to raise EINTR
|
||||||
|
@ -149,27 +174,86 @@ static textwindows bool __sig_isfatal(int sig) {
|
||||||
return sig != SIGCHLD;
|
return sig != SIGCHLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles signal.
|
||||||
|
*
|
||||||
|
* @param restartable can be used to suppress true return if SA_RESTART
|
||||||
|
* @return true if signal was delivered
|
||||||
|
*/
|
||||||
|
textwindows bool __sig_handle(bool restartable, int sig, int si_code,
|
||||||
|
ucontext_t *ctx) {
|
||||||
|
bool delivered;
|
||||||
|
switch (__sighandrvas[sig]) {
|
||||||
|
case (intptr_t)SIG_DFL:
|
||||||
|
if (__sig_isfatal(sig)) {
|
||||||
|
STRACE("terminating on %s", strsignal(sig));
|
||||||
|
__restorewintty();
|
||||||
|
_Exit(128 + sig);
|
||||||
|
}
|
||||||
|
// fallthrough
|
||||||
|
case (intptr_t)SIG_IGN:
|
||||||
|
STRACE("ignoring %s", strsignal(sig));
|
||||||
|
delivered = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
delivered = __sig_deliver(restartable, sig, si_code, ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return delivered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles signal immediately if not blocked.
|
||||||
|
*
|
||||||
|
* @param restartable is for functions like read() but not poll()
|
||||||
|
* @return true if EINTR should be returned by caller
|
||||||
|
* @return 1 if delivered, 0 if enqueued, otherwise -1 w/ errno
|
||||||
|
* @note called from main thread
|
||||||
|
* @threadsafe
|
||||||
|
*/
|
||||||
|
textwindows int __sig_raise(int sig, int si_code) {
|
||||||
|
int rc;
|
||||||
|
int candeliver;
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
|
candeliver = !sigismember(&__sig.mask, sig);
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
switch (candeliver) {
|
||||||
|
case 1:
|
||||||
|
__sig_handle(false, sig, si_code, 0);
|
||||||
|
return 0;
|
||||||
|
case 0:
|
||||||
|
STRACE("%s is masked", strsignal(sig));
|
||||||
|
return __sig_add(sig, si_code);
|
||||||
|
default:
|
||||||
|
return -1; // sigismember() validates `sig`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueues generic signal for delivery on New Technology.
|
* Enqueues generic signal for delivery on New Technology.
|
||||||
|
* @return 0 if enqueued, otherwise -1 w/ errno
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
textwindows int __sig_add(int sig, int si_code) {
|
textwindows int __sig_add(int sig, int si_code) {
|
||||||
|
int rc;
|
||||||
struct Signal *mem;
|
struct Signal *mem;
|
||||||
if (1 <= sig && sig <= NSIG) {
|
if (1 <= sig && sig <= NSIG) {
|
||||||
|
STRACE("enqueuing %s", strsignal(sig));
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
if ((mem = __sig_alloc())) {
|
if ((mem = __sig_alloc())) {
|
||||||
mem->sig = sig;
|
mem->sig = sig;
|
||||||
mem->si_code = si_code;
|
mem->si_code = si_code;
|
||||||
LOCK;
|
|
||||||
mem->next = __sig.queue;
|
mem->next = __sig.queue;
|
||||||
__sig.queue = mem;
|
__sig.queue = mem;
|
||||||
UNLOCK;
|
rc = 0;
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
return enomem();
|
rc = enomem();
|
||||||
}
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
} else {
|
} else {
|
||||||
return einval();
|
rc = einval();
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -186,21 +270,7 @@ textwindows bool __sig_check(bool restartable) {
|
||||||
struct Signal *sig;
|
struct Signal *sig;
|
||||||
delivered = false;
|
delivered = false;
|
||||||
while ((sig = __sig_remove())) {
|
while ((sig = __sig_remove())) {
|
||||||
switch ((rva = __sighandrvas[sig->sig])) {
|
delivered |= __sig_handle(restartable, sig->sig, sig->si_code, 0);
|
||||||
case (intptr_t)SIG_DFL:
|
|
||||||
if (__sig_isfatal(sig->sig)) {
|
|
||||||
STRACE("terminating on %s", strsignal(sig->sig));
|
|
||||||
__restorewintty();
|
|
||||||
_Exit(128 + sig->sig);
|
|
||||||
}
|
|
||||||
// fallthrough
|
|
||||||
case (intptr_t)SIG_IGN:
|
|
||||||
STRACE("ignoring %s", strsignal(sig->sig));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
delivered = __sig_deliver(restartable, sig, rva);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
__sig_free(sig);
|
__sig_free(sig);
|
||||||
}
|
}
|
||||||
return delivered;
|
return delivered;
|
||||||
|
@ -208,13 +278,31 @@ textwindows bool __sig_check(bool restartable) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes signal mask for main thread.
|
* Changes signal mask for main thread.
|
||||||
* @return old mask
|
* @return 0 on success, or -1 w/ errno
|
||||||
*/
|
*/
|
||||||
textwindows sigset_t __sig_mask(const sigset_t *neu) {
|
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
||||||
sigset_t old;
|
int i;
|
||||||
LOCK;
|
uint64_t a, b;
|
||||||
old = __sig.mask;
|
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
|
||||||
if (neu) __sig.mask = *neu;
|
cthread_spinlock(&__sig_lock);
|
||||||
UNLOCK;
|
if (old) {
|
||||||
return old;
|
*old = __sig.mask;
|
||||||
|
}
|
||||||
|
if (neu) {
|
||||||
|
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
|
||||||
|
if (how == SIG_BLOCK) {
|
||||||
|
__sig.mask.__bits[i] |= neu->__bits[i];
|
||||||
|
} else if (how == SIG_UNBLOCK) {
|
||||||
|
__sig.mask.__bits[i] &= ~neu->__bits[i];
|
||||||
|
} else {
|
||||||
|
__sig.mask.__bits[i] = neu->__bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__sig.mask.__bits[0] &= ~(SIGKILL | SIGSTOP);
|
||||||
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
|
#include "libc/calls/ucontext.h"
|
||||||
|
|
||||||
#define __SIG_QUEUE_LENGTH 8
|
#define __SIG_QUEUE_LENGTH 8
|
||||||
#define __SIG_POLLING_INTERVAL_MS 50
|
#define __SIG_POLLING_INTERVAL_MS 50
|
||||||
|
#define __SIG_LOGGING_INTERVAL_MS 1700
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
bool __sig_check(bool) hidden;
|
bool __sig_check(bool) hidden;
|
||||||
|
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
|
||||||
int __sig_add(int, int) hidden;
|
int __sig_add(int, int) hidden;
|
||||||
sigset_t __sig_mask(const sigset_t *) hidden;
|
int __sig_mask(int, const sigset_t *, sigset_t *) hidden;
|
||||||
|
int __sig_raise(int, int) hidden;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -212,6 +213,7 @@ static int __sigaction(int sig, const struct sigaction *act,
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
if (rc != -1 && !__vforked) {
|
if (rc != -1 && !__vforked) {
|
||||||
|
cthread_spinlock(&__sig_lock);
|
||||||
if (oldact) {
|
if (oldact) {
|
||||||
oldrva = __sighandrvas[sig];
|
oldrva = __sighandrvas[sig];
|
||||||
oldact->sa_sigaction = (sigaction_f)(
|
oldact->sa_sigaction = (sigaction_f)(
|
||||||
|
@ -221,6 +223,7 @@ static int __sigaction(int sig, const struct sigaction *act,
|
||||||
__sighandrvas[sig] = rva;
|
__sighandrvas[sig] = rva;
|
||||||
__sighandflags[sig] = act->sa_flags;
|
__sighandflags[sig] = act->sa_flags;
|
||||||
}
|
}
|
||||||
|
cthread_spunlock(&__sig_lock);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -233,6 +236,58 @@ static int __sigaction(int sig, const struct sigaction *act,
|
||||||
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
|
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
|
||||||
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
|
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
|
||||||
*
|
*
|
||||||
|
* Here's an example of the most professional way to handle signals.
|
||||||
|
* It's generally a best practice to have signal handlers do the fewest
|
||||||
|
* number of things possible. The trick is to have your signals work
|
||||||
|
* hand-in-glove with the EINTR errno returned by i/o.
|
||||||
|
*
|
||||||
|
* static volatile bool gotctrlc;
|
||||||
|
* void OnCtrlC(int sig) {
|
||||||
|
* gotctrlc = true;
|
||||||
|
* }
|
||||||
|
* int main() {
|
||||||
|
* size_t got;
|
||||||
|
* ssize_t rc;
|
||||||
|
* char buf[1];
|
||||||
|
* struct sigaction oldint;
|
||||||
|
* struct sigaction saint = {.sa_handler = GotCtrlC};
|
||||||
|
* if (sigaction(SIGINT, &saint, &oldint) == -1) {
|
||||||
|
* perror("sigaction");
|
||||||
|
* exit(1);
|
||||||
|
* }
|
||||||
|
* for (;;) {
|
||||||
|
* rc = read(0, buf, sizeof(buf));
|
||||||
|
* if (rc == -1) {
|
||||||
|
* if (errno == EINTR) {
|
||||||
|
* if (gotctrlc) {
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* } else {
|
||||||
|
* perror("read");
|
||||||
|
* exit(2);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* if (!(got = rc)) {
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* for (;;) {
|
||||||
|
* rc = write(1, buf, got);
|
||||||
|
* if (rc != -1) {
|
||||||
|
* assert(rc == 1);
|
||||||
|
* break;
|
||||||
|
* } else if (errno != EINTR) {
|
||||||
|
* perror("write");
|
||||||
|
* exit(3);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* sigaction(SIGINT, &oldint, 0);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Please note that you can't do the above if you use SA_RESTART. Since
|
||||||
|
* the purpose of SA_RESTART is to restart i/o operations whose docs say
|
||||||
|
* that they're @restartable and read() is one such function.
|
||||||
|
*
|
||||||
* @return 0 on success or -1 w/ errno
|
* @return 0 on success or -1 w/ errno
|
||||||
* @see xsigaction() for a much better api
|
* @see xsigaction() for a much better api
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
|
@ -241,7 +296,11 @@ static int __sigaction(int sig, const struct sigaction *act,
|
||||||
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||||
int rc;
|
int rc;
|
||||||
char buf[2][128];
|
char buf[2][128];
|
||||||
rc = __sigaction(sig, act, oldact);
|
if (sig == SIGKILL || sig == SIGSTOP) {
|
||||||
|
rc = einval();
|
||||||
|
} else {
|
||||||
|
rc = __sigaction(sig, act, oldact);
|
||||||
|
}
|
||||||
STRACE("sigaction(%s, %s, [%s]) → %d% m", strsignal(sig),
|
STRACE("sigaction(%s, %s, [%s]) → %d% m", strsignal(sig),
|
||||||
__strace_sigaction(buf[0], sizeof(buf[0]), 0, act),
|
__strace_sigaction(buf[0], sizeof(buf[0]), 0, act),
|
||||||
__strace_sigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
|
__strace_sigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
|
||||||
|
|
|
@ -20,104 +20,12 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
#include "libc/calls/struct/ucontext-freebsd.internal.h"
|
||||||
#include "libc/calls/typedef/sigaction_f.h"
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
union sigval_freebsd {
|
|
||||||
int32_t sival_int;
|
|
||||||
void *sival_ptr;
|
|
||||||
int32_t sigval_int;
|
|
||||||
void *sigval_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct siginfo_freebsd {
|
|
||||||
int32_t si_signo;
|
|
||||||
int32_t si_errno;
|
|
||||||
int32_t si_code;
|
|
||||||
int32_t si_pid;
|
|
||||||
uint32_t si_uid;
|
|
||||||
int32_t si_status;
|
|
||||||
void *si_addr;
|
|
||||||
union sigval_freebsd si_value;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
int32_t _trapno;
|
|
||||||
} _fault;
|
|
||||||
struct {
|
|
||||||
int32_t _timerid;
|
|
||||||
int32_t _overrun;
|
|
||||||
} _timer;
|
|
||||||
struct {
|
|
||||||
int32_t _mqd;
|
|
||||||
} _mesgq;
|
|
||||||
struct {
|
|
||||||
int64_t _band;
|
|
||||||
} _poll;
|
|
||||||
struct {
|
|
||||||
int64_t __spare1__;
|
|
||||||
int32_t __spare2__[7];
|
|
||||||
} __spare__;
|
|
||||||
} _reason;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct stack_freebsd {
|
|
||||||
void *ss_sp;
|
|
||||||
uint64_t ss_size;
|
|
||||||
int32_t ss_flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mcontext_freebsd {
|
|
||||||
int64_t mc_onstack;
|
|
||||||
int64_t mc_rdi;
|
|
||||||
int64_t mc_rsi;
|
|
||||||
int64_t mc_rdx;
|
|
||||||
int64_t mc_rcx;
|
|
||||||
int64_t mc_r8;
|
|
||||||
int64_t mc_r9;
|
|
||||||
int64_t mc_rax;
|
|
||||||
int64_t mc_rbx;
|
|
||||||
int64_t mc_rbp;
|
|
||||||
int64_t mc_r10;
|
|
||||||
int64_t mc_r11;
|
|
||||||
int64_t mc_r12;
|
|
||||||
int64_t mc_r13;
|
|
||||||
int64_t mc_r14;
|
|
||||||
int64_t mc_r15;
|
|
||||||
uint32_t mc_trapno;
|
|
||||||
uint16_t mc_fs;
|
|
||||||
uint16_t mc_gs;
|
|
||||||
int64_t mc_addr;
|
|
||||||
uint32_t mc_flags;
|
|
||||||
uint16_t mc_es;
|
|
||||||
uint16_t mc_ds;
|
|
||||||
int64_t mc_err;
|
|
||||||
int64_t mc_rip;
|
|
||||||
int64_t mc_cs;
|
|
||||||
int64_t mc_rflags;
|
|
||||||
int64_t mc_rsp;
|
|
||||||
int64_t mc_ss;
|
|
||||||
int64_t mc_len;
|
|
||||||
int64_t mc_fpformat;
|
|
||||||
int64_t mc_ownedfp;
|
|
||||||
int64_t mc_fpstate[64];
|
|
||||||
int64_t mc_fsbase;
|
|
||||||
int64_t mc_gsbase;
|
|
||||||
int64_t mc_xfpustate;
|
|
||||||
int64_t mc_xfpustate_len;
|
|
||||||
int64_t mc_spare[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ucontext_freebsd {
|
|
||||||
struct sigset_freebsd uc_sigmask;
|
|
||||||
struct mcontext_freebsd uc_mcontext;
|
|
||||||
struct ucontext_freebsd *uc_link;
|
|
||||||
struct stack_freebsd uc_stack;
|
|
||||||
int32_t uc_flags;
|
|
||||||
int32_t __spare__[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
|
void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
|
||||||
struct ucontext_freebsd *ctx) {
|
struct ucontext_freebsd *ctx) {
|
||||||
int rva;
|
int rva;
|
||||||
|
|
|
@ -21,12 +21,20 @@
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs kernel interrupt handler.
|
* Installs kernel interrupt handler, e.g.
|
||||||
*
|
*
|
||||||
|
* void GotCtrlC(int sig) { ... }
|
||||||
|
* CHECK_NE(SIG_ERR, signal(SIGINT, GotCtrlC));
|
||||||
|
*
|
||||||
|
* @return old signal handler on success or SIG_ERR w/ errno
|
||||||
|
* @note this function has BSD semantics, i.e. SA_RESTART
|
||||||
* @see sigaction() which has more features
|
* @see sigaction() which has more features
|
||||||
*/
|
*/
|
||||||
sighandler_t(signal)(int sig, sighandler_t func) {
|
sighandler_t(signal)(int sig, sighandler_t func) {
|
||||||
struct sigaction sa_old, sa = {.sa_handler = func, .sa_flags = SA_RESTART};
|
struct sigaction old, sa = {.sa_handler = func, .sa_flags = SA_RESTART};
|
||||||
if ((sigaction)(sig, &sa, &sa_old) == -1) return SIG_ERR;
|
if ((sigaction)(sig, &sa, &old) != -1) {
|
||||||
return sa_old.sa_handler;
|
return old.sa_handler;
|
||||||
|
} else {
|
||||||
|
return SIG_ERR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
||||||
char buf[2][41];
|
char buf[2][41];
|
||||||
int res, rc, arg1;
|
int res, rc, arg1;
|
||||||
const sigset_t *arg2;
|
const sigset_t *arg2;
|
||||||
|
STRACE("sigprocmask(%s, %s, [...]", DescribeHow(howbuf, how),
|
||||||
|
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set));
|
||||||
sigemptyset(&old);
|
sigemptyset(&old);
|
||||||
if (IsAsan() &&
|
if (IsAsan() &&
|
||||||
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
|
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
|
||||||
|
@ -86,14 +88,13 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
} else { // windows or metal
|
} else { // windows or metal
|
||||||
old = __sig_mask(opt_set);
|
rc = __sig_mask(how, opt_set, &old);
|
||||||
_check_interrupts(false, 0);
|
_check_interrupts(false, 0);
|
||||||
rc = 0;
|
|
||||||
}
|
}
|
||||||
if (rc != -1 && opt_out_oldset) {
|
if (rc != -1 && opt_out_oldset) {
|
||||||
*opt_out_oldset = old;
|
*opt_out_oldset = old;
|
||||||
}
|
}
|
||||||
STRACE("sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(howbuf, how),
|
STRACE("[...] sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(howbuf, how),
|
||||||
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set),
|
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set),
|
||||||
__strace_sigset(buf[1], sizeof(buf[1]), rc, opt_out_oldset), rc);
|
__strace_sigset(buf[1], sizeof(buf[1]), rc, opt_out_oldset), rc);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
|
@ -24,20 +25,23 @@
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/nt/synchronization.h"
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until SIG ∉ MASK is delivered to process.
|
* Blocks until SIG ∉ MASK is delivered to process.
|
||||||
*
|
*
|
||||||
* @param ignore is a bitset of signals to block temporarily
|
* @param ignore is a bitset of signals to block temporarily, which if
|
||||||
* @return -1 w/ EINTR or possibly EFAULT
|
* NULL is equivalent to passing an empty signal set
|
||||||
|
* @return -1 w/ EINTR (or possibly EFAULT)
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @norestart
|
* @norestart
|
||||||
*/
|
*/
|
||||||
int sigsuspend(const sigset_t *ignore) {
|
int sigsuspend(const sigset_t *ignore) {
|
||||||
int rc;
|
int rc;
|
||||||
char buf[41];
|
char buf[41];
|
||||||
|
long ms, totoms;
|
||||||
sigset_t save, mask, *arg;
|
sigset_t save, mask, *arg;
|
||||||
STRACE("sigsuspend(%s) → [...]",
|
STRACE("sigsuspend(%s) → [...]",
|
||||||
__strace_sigset(buf, sizeof(buf), 0, ignore));
|
__strace_sigset(buf, sizeof(buf), 0, ignore));
|
||||||
|
@ -62,15 +66,24 @@ int sigsuspend(const sigset_t *ignore) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
rc = sys_sigsuspend(arg, 8);
|
rc = sys_sigsuspend(arg, 8);
|
||||||
} else {
|
} else {
|
||||||
save = __sig_mask(arg);
|
__sig_mask(SIG_SETMASK, arg, &save);
|
||||||
|
ms = 0;
|
||||||
|
totoms = 0;
|
||||||
do {
|
do {
|
||||||
if (_check_interrupts(false, g_fds.p)) {
|
if (_check_interrupts(false, g_fds.p)) {
|
||||||
rc = eintr();
|
rc = eintr();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SleepEx(__SIG_POLLING_INTERVAL_MS, true);
|
SleepEx(__SIG_POLLING_INTERVAL_MS, true);
|
||||||
|
#ifdef SYSDEBUG
|
||||||
|
ms += __SIG_POLLING_INTERVAL_MS;
|
||||||
|
if (ms >= __SIG_LOGGING_INTERVAL_MS) {
|
||||||
|
totoms += ms, ms = 0;
|
||||||
|
STRACE("[...] sigsuspending for %'lums...", totoms);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} while (1);
|
} while (1);
|
||||||
__sig_mask(&save);
|
__sig_mask(SIG_SETMASK, &save, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO(jart): sigsuspend metal support
|
// TODO(jart): sigsuspend metal support
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/calls/typedef/sigaction_f.h"
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
#include "libc/calls/typedef/sighandler_t.h"
|
#include "libc/calls/typedef/sighandler_t.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
struct sigaction { /* cosmo abi */
|
struct sigaction { /* cosmo abi */
|
||||||
|
|
102
libc/calls/struct/ucontext-freebsd.internal.h
Normal file
102
libc/calls/struct/ucontext-freebsd.internal.h
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_FREEBSD_INTERNAL_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_FREEBSD_INTERNAL_H_
|
||||||
|
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
union sigval_freebsd {
|
||||||
|
int32_t sival_int;
|
||||||
|
void *sival_ptr;
|
||||||
|
int32_t sigval_int;
|
||||||
|
void *sigval_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct siginfo_freebsd {
|
||||||
|
int32_t si_signo;
|
||||||
|
int32_t si_errno;
|
||||||
|
int32_t si_code;
|
||||||
|
int32_t si_pid;
|
||||||
|
uint32_t si_uid;
|
||||||
|
int32_t si_status;
|
||||||
|
void *si_addr;
|
||||||
|
union sigval_freebsd si_value;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
int32_t _trapno;
|
||||||
|
} _fault;
|
||||||
|
struct {
|
||||||
|
int32_t _timerid;
|
||||||
|
int32_t _overrun;
|
||||||
|
} _timer;
|
||||||
|
struct {
|
||||||
|
int32_t _mqd;
|
||||||
|
} _mesgq;
|
||||||
|
struct {
|
||||||
|
int64_t _band;
|
||||||
|
} _poll;
|
||||||
|
struct {
|
||||||
|
int64_t __spare1__;
|
||||||
|
int32_t __spare2__[7];
|
||||||
|
} __spare__;
|
||||||
|
} _reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stack_freebsd {
|
||||||
|
void *ss_sp;
|
||||||
|
uint64_t ss_size;
|
||||||
|
int32_t ss_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mcontext_freebsd {
|
||||||
|
int64_t mc_onstack;
|
||||||
|
int64_t mc_rdi;
|
||||||
|
int64_t mc_rsi;
|
||||||
|
int64_t mc_rdx;
|
||||||
|
int64_t mc_rcx;
|
||||||
|
int64_t mc_r8;
|
||||||
|
int64_t mc_r9;
|
||||||
|
int64_t mc_rax;
|
||||||
|
int64_t mc_rbx;
|
||||||
|
int64_t mc_rbp;
|
||||||
|
int64_t mc_r10;
|
||||||
|
int64_t mc_r11;
|
||||||
|
int64_t mc_r12;
|
||||||
|
int64_t mc_r13;
|
||||||
|
int64_t mc_r14;
|
||||||
|
int64_t mc_r15;
|
||||||
|
uint32_t mc_trapno;
|
||||||
|
uint16_t mc_fs;
|
||||||
|
uint16_t mc_gs;
|
||||||
|
int64_t mc_addr;
|
||||||
|
uint32_t mc_flags;
|
||||||
|
uint16_t mc_es;
|
||||||
|
uint16_t mc_ds;
|
||||||
|
int64_t mc_err;
|
||||||
|
int64_t mc_rip;
|
||||||
|
int64_t mc_cs;
|
||||||
|
int64_t mc_rflags;
|
||||||
|
int64_t mc_rsp;
|
||||||
|
int64_t mc_ss;
|
||||||
|
int64_t mc_len;
|
||||||
|
int64_t mc_fpformat;
|
||||||
|
int64_t mc_ownedfp;
|
||||||
|
int64_t mc_fpstate[64];
|
||||||
|
int64_t mc_fsbase;
|
||||||
|
int64_t mc_gsbase;
|
||||||
|
int64_t mc_xfpustate;
|
||||||
|
int64_t mc_xfpustate_len;
|
||||||
|
int64_t mc_spare[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ucontext_freebsd {
|
||||||
|
struct sigset_freebsd uc_sigmask;
|
||||||
|
struct mcontext_freebsd uc_mcontext;
|
||||||
|
struct ucontext_freebsd *uc_link;
|
||||||
|
struct stack_freebsd uc_stack;
|
||||||
|
int32_t uc_flags;
|
||||||
|
int32_t __spare__[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_FREEBSD_INTERNAL_H_ */
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/lockxchg.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes file.
|
* Deletes file.
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
|
@ -40,11 +41,13 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/w.h"
|
#include "libc/sysv/consts/w.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
|
||||||
struct rusage *opt_out_rusage) {
|
int options,
|
||||||
|
struct rusage *opt_out_rusage) {
|
||||||
int pids[64];
|
int pids[64];
|
||||||
int64_t handle;
|
int64_t handle;
|
||||||
int64_t handles[64];
|
int64_t handles[64];
|
||||||
|
@ -129,3 +132,15 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
||||||
return pids[i];
|
return pids[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
||||||
|
struct rusage *opt_out_rusage) {
|
||||||
|
int rc;
|
||||||
|
sigset_t mask, oldmask;
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
__sig_mask(SIG_BLOCK, &mask, &oldmask);
|
||||||
|
rc = sys_wait4_nt_impl(pid, opt_out_wstatus, options, opt_out_rusage);
|
||||||
|
__sig_mask(SIG_SETMASK, &oldmask, 0);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/typedef/sigaction_f.h"
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
|
@ -24,14 +25,14 @@
|
||||||
#include "libc/nt/enum/signal.h"
|
#include "libc/nt/enum/signal.h"
|
||||||
#include "libc/nt/struct/ntexceptionpointers.h"
|
#include "libc/nt/struct/ntexceptionpointers.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/sicode.h"
|
#include "libc/sysv/consts/sicode.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
|
textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
|
||||||
int sig, rva, code;
|
int64_t rip;
|
||||||
struct Goodies {
|
int sig, code;
|
||||||
ucontext_t ctx;
|
ucontext_t ctx;
|
||||||
struct siginfo si;
|
|
||||||
} g;
|
|
||||||
STRACE("__wincrash");
|
STRACE("__wincrash");
|
||||||
switch (ep->ExceptionRecord->ExceptionCode) {
|
switch (ep->ExceptionRecord->ExceptionCode) {
|
||||||
case kNtSignalBreakpoint:
|
case kNtSignalBreakpoint:
|
||||||
|
@ -96,12 +97,22 @@ textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
|
||||||
default:
|
default:
|
||||||
return kNtExceptionContinueSearch;
|
return kNtExceptionContinueSearch;
|
||||||
}
|
}
|
||||||
bzero(&g, sizeof(g));
|
rip = ep->ContextRecord->Rip;
|
||||||
g.si.si_code = code;
|
|
||||||
rva = __sighandrvas[sig];
|
if (__sighandflags[sig] & SA_SIGINFO) {
|
||||||
if (rva >= kSigactionMinRva) {
|
_ntcontext2linux(&ctx, ep->ContextRecord);
|
||||||
ntcontext2linux(&g.ctx, ep->ContextRecord);
|
__sig_handle(false, sig, code, &ctx);
|
||||||
((sigaction_f)(_base + rva))(sig, &g.si, &g.ctx);
|
_ntlinux2context(ep->ContextRecord, &ctx);
|
||||||
|
} else {
|
||||||
|
__sig_handle(false, sig, code, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows seems to be the only operating system that traps INT3 at
|
||||||
|
// addressof(INT3) rather than addressof(INT3)+1. So we must adjust
|
||||||
|
// RIP to prevent the same INT3 from being trapped forevermore.
|
||||||
|
if (sig == SIGTRAP && rip == ep->ContextRecord->Rip) {
|
||||||
|
ep->ContextRecord->Rip++;
|
||||||
|
}
|
||||||
|
|
||||||
return kNtExceptionContinueExecution;
|
return kNtExceptionContinueExecution;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sig.internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
@ -29,22 +30,10 @@
|
||||||
#include "libc/nt/struct/overlapped.h"
|
#include "libc/nt/struct/overlapped.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/sicode.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static textwindows ssize_t sys_write_nt_epipe(int fd) {
|
|
||||||
siginfo_t info;
|
|
||||||
STRACE("WriteFile(%d:%p) → %m", fd, g_fds.p[fd].handle);
|
|
||||||
if (!__sighandrvas[SIGPIPE]) {
|
|
||||||
__restorewintty();
|
|
||||||
_Exit(128 + SIGPIPE);
|
|
||||||
} else if (__sighandrvas[SIGPIPE] >= kSigactionMinRva) {
|
|
||||||
bzero(&info, sizeof(info));
|
|
||||||
((sigaction_f)(_base + __sighandrvas[SIGPIPE]))(SIGPIPE, &info, 0);
|
|
||||||
}
|
|
||||||
return epipe();
|
|
||||||
}
|
|
||||||
|
|
||||||
static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
ssize_t offset) {
|
ssize_t offset) {
|
||||||
uint32_t sent;
|
uint32_t sent;
|
||||||
|
@ -53,7 +42,8 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
|
||||||
_offset2overlap(offset, &overlap))) {
|
_offset2overlap(offset, &overlap))) {
|
||||||
return sent;
|
return sent;
|
||||||
} else if (GetLastError() == kNtErrorBrokenPipe) {
|
} else if (GetLastError() == kNtErrorBrokenPipe) {
|
||||||
return sys_write_nt_epipe(fd);
|
__sig_raise(SIGPIPE, SI_KERNEL);
|
||||||
|
return epipe();
|
||||||
} else {
|
} else {
|
||||||
return __winerr();
|
return __winerr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/alg/reverse.internal.h"
|
#include "libc/alg/reverse.internal.h"
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/likely.h"
|
#include "libc/bits/likely.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
@ -29,6 +28,7 @@
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/asancodes.h"
|
#include "libc/intrin/asancodes.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
@ -842,7 +842,7 @@ void *__asan_morgue_add(void *p) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
i = __asan_morgue.i;
|
i = __asan_morgue.i;
|
||||||
j = (i + 1) & (ARRAYLEN(__asan_morgue.p) - 1);
|
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];
|
r = __asan_morgue.p[i];
|
||||||
__asan_morgue.p[i] = p;
|
__asan_morgue.p[i] = p;
|
||||||
return r;
|
return r;
|
||||||
|
@ -855,7 +855,7 @@ static void __asan_morgue_flush(void) {
|
||||||
void *p;
|
void *p;
|
||||||
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
||||||
p = __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)) {
|
if (weaken(dlfree)) {
|
||||||
weaken(dlfree)(p);
|
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) {
|
void __asan_report_load(uint8_t *addr, int size) {
|
||||||
if (cmpxchg(&__asan_noreentry, false, true)) {
|
if (_lockcmpxchg(&__asan_noreentry, false, true)) {
|
||||||
if (!__vforked) {
|
if (!__vforked) {
|
||||||
__asan_report_memory_fault(addr, size, "load")();
|
__asan_report_memory_fault(addr, size, "load")();
|
||||||
__asan_unreachable();
|
__asan_unreachable();
|
||||||
|
@ -1219,7 +1219,7 @@ void __asan_report_load(uint8_t *addr, int size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_report_store(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) {
|
if (!__vforked) {
|
||||||
__asan_report_memory_fault(addr, size, "store")();
|
__asan_report_memory_fault(addr, size, "store")();
|
||||||
__asan_unreachable();
|
__asan_unreachable();
|
||||||
|
@ -1364,7 +1364,7 @@ static textstartup void __asan_shadow_existing_mappings(void) {
|
||||||
textstartup void __asan_init(int argc, char **argv, char **envp,
|
textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||||
intptr_t *auxv) {
|
intptr_t *auxv) {
|
||||||
static bool once;
|
static bool once;
|
||||||
if (!cmpxchg(&once, false, true)) return;
|
if (!_lockcmpxchg(&once, false, true)) return;
|
||||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||||
__write_str("error: asan binaries require windows10\r\n");
|
__write_str("error: asan binaries require windows10\r\n");
|
||||||
__restorewintty();
|
__restorewintty();
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -29,17 +30,19 @@
|
||||||
*/
|
*/
|
||||||
relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
||||||
int line) {
|
int line) {
|
||||||
|
int rc;
|
||||||
static bool noreentry;
|
static bool noreentry;
|
||||||
kprintf("%s:%d: assert(%s) failed%n", file, line, expr);
|
kprintf("%s:%d: assert(%s) failed%n", file, line, expr);
|
||||||
if (cmpxchg(&noreentry, false, true)) {
|
if (_lockcmpxchg(&noreentry, false, true)) {
|
||||||
if (weaken(__die)) {
|
if (weaken(__die)) {
|
||||||
weaken(__die)();
|
weaken(__die)();
|
||||||
} else {
|
} else {
|
||||||
kprintf("can't backtrace b/c `__die` not linked%n");
|
kprintf("can't backtrace b/c `__die` not linked%n");
|
||||||
}
|
}
|
||||||
__restorewintty();
|
rc = 23;
|
||||||
_Exit(23);
|
} else {
|
||||||
|
rc = 24;
|
||||||
}
|
}
|
||||||
__restorewintty();
|
__restorewintty();
|
||||||
_Exit(24);
|
_Exit(rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,21 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/atomic_load.h"
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atomically loads value.
|
* Reads scalar from memory w/ one operation.
|
||||||
*
|
*
|
||||||
* This macro is intended to prevent things like compiler load tearing
|
* This macro is intended to prevent things like compiler load tearing
|
||||||
* optimizations.
|
* 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(atomic_load)(void *p, size_t n) {
|
||||||
intptr_t x = 0;
|
intptr_t x = 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_ */
|
|
@ -16,15 +16,23 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/atomic_store.h"
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atomically stores value.
|
* Saves scalar to memory w/ one operation.
|
||||||
*
|
*
|
||||||
* This macro is intended to prevent things like compiler store tearing
|
* This is guaranteed to happen in either one or zero operations,
|
||||||
* optimizations.
|
* 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) {
|
intptr_t(atomic_store)(void *p, intptr_t x, size_t n) {
|
||||||
switch (n) {
|
switch (n) {
|
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_ */
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/cmpxchg.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares and exchanges.
|
* Compares and exchanges.
|
||||||
|
@ -24,23 +24,23 @@
|
||||||
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||||
* @param size is automatically supplied by macro wrapper
|
* @param size is automatically supplied by macro wrapper
|
||||||
* @return true if value was exchanged, otherwise false
|
* @return true if value was exchanged, otherwise false
|
||||||
* @see lockcmpxchg()
|
* @see _lockcmpxchg()
|
||||||
*/
|
*/
|
||||||
bool(cmpxchg)(void *ifthing, intptr_t isequaltome, intptr_t replaceitwithme,
|
bool(_cmpxchg)(void *ifthing, intptr_t isequaltome, intptr_t replaceitwithme,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
return cmpxchg((int8_t *)ifthing, (int8_t)isequaltome,
|
return _cmpxchg((int8_t *)ifthing, (int8_t)isequaltome,
|
||||||
(int8_t)replaceitwithme);
|
(int8_t)replaceitwithme);
|
||||||
case 2:
|
case 2:
|
||||||
return cmpxchg((int16_t *)ifthing, (int16_t)isequaltome,
|
return _cmpxchg((int16_t *)ifthing, (int16_t)isequaltome,
|
||||||
(int16_t)replaceitwithme);
|
(int16_t)replaceitwithme);
|
||||||
case 4:
|
case 4:
|
||||||
return cmpxchg((int32_t *)ifthing, (int32_t)isequaltome,
|
return _cmpxchg((int32_t *)ifthing, (int32_t)isequaltome,
|
||||||
(int32_t)replaceitwithme);
|
(int32_t)replaceitwithme);
|
||||||
case 8:
|
case 8:
|
||||||
return cmpxchg((int64_t *)ifthing, (int64_t)isequaltome,
|
return _cmpxchg((int64_t *)ifthing, (int64_t)isequaltome,
|
||||||
(int64_t)replaceitwithme);
|
(int64_t)replaceitwithme);
|
||||||
default:
|
default:
|
||||||
return false;
|
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_ */
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_BITS_CMPXCHG16B_INTERNAL_H_
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
|
@ -16,6 +16,8 @@ const char *DescribeNtFileFlagsAndAttributes(uint32_t);
|
||||||
const char *DescribeNtFileShareFlags(uint32_t);
|
const char *DescribeNtFileShareFlags(uint32_t);
|
||||||
const char *DescribeNtFileAccessFlags(uint32_t);
|
const char *DescribeNtFileAccessFlags(uint32_t);
|
||||||
const char *DescribeNtProcessAccessFlags(uint32_t);
|
const char *DescribeNtProcessAccessFlags(uint32_t);
|
||||||
|
const char *DescribeNtConsoleModeInputFlags(uint32_t);
|
||||||
|
const char *DescribeNtConsoleModeOutputFlags(uint32_t);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#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);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,46 +16,21 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/runtime/internal.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
|
||||||
#include "libc/sysv/consts/nr.h"
|
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
.privileged
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
|
|
||||||
// Terminates program abnormally.
|
static const struct DescribeFlags kConsoleModeOutputFlags[] = {
|
||||||
//
|
{kNtEnableProcessedOutput, "EnableProcessedOutput"}, //
|
||||||
// This function first tries to trigger your SIGABRT handler. If
|
{kNtEnableWrapAtEolOutput, "EnableWrapAtEolOutput"}, //
|
||||||
// there isn't one or execution resumes, then abort() terminates
|
{kNtEnableVirtualTerminalProcessing, "EnableVirtualTerminalProcessing"}, //
|
||||||
// the program using an escalating variety methods of increasing
|
{kNtDisableNewlineAutoReturn, "DisableNewlineAutoReturn"}, //
|
||||||
// brutality.
|
{kNtEnableLvbGridWorldwide, "EnableLvbGridWorldwide"}, //
|
||||||
//
|
};
|
||||||
// @forcealignargpointer
|
|
||||||
// @asyncsignalsafe
|
const char *DescribeNtConsoleModeOutputFlags(uint32_t x) {
|
||||||
// @noreturn
|
static char consolemodeoutputflags[128];
|
||||||
abort: push %rbp
|
return DescribeFlags(consolemodeoutputflags, sizeof(consolemodeoutputflags),
|
||||||
mov %rsp,%rbp
|
kConsoleModeOutputFlags,
|
||||||
and $-16,%rsp
|
ARRAYLEN(kConsoleModeOutputFlags), "kNt", x);
|
||||||
sub $16,%rsp
|
}
|
||||||
#if SupportsWindows()
|
|
||||||
testb IsWindows()
|
|
||||||
jnz sys_abort_nt
|
|
||||||
#endif
|
|
||||||
mov SIG_SETMASK,%edi
|
|
||||||
mov %rsp,%rsi
|
|
||||||
push $0xffffffffffffffdf # all bits blocked but SIGABRT
|
|
||||||
push $0xffffffffffffffff # assumes von neum. arithmetic
|
|
||||||
pop 8(%rsi)
|
|
||||||
pop (%rsi)
|
|
||||||
xor %edx,%edx # don't care about old sigmask
|
|
||||||
pushpop 4*4,%r10 # sizeof(sigset_t) for systemd
|
|
||||||
mov __NR_sigprocmask,%eax # sys_sigprocmask is hookable
|
|
||||||
syscall
|
|
||||||
mov __NR_getpid,%eax
|
|
||||||
syscall
|
|
||||||
mov %eax,%edi
|
|
||||||
mov SIGABRT,%esi
|
|
||||||
mov __NR_kill,%eax
|
|
||||||
syscall # avoid hook and less bt noise
|
|
||||||
call _Exit
|
|
||||||
.endfn abort,globl,protected
|
|
|
@ -21,20 +21,20 @@
|
||||||
#include "libc/nt/enum/processaccess.h"
|
#include "libc/nt/enum/processaccess.h"
|
||||||
|
|
||||||
static const struct DescribeFlags kProcessAccessflags[] = {
|
static const struct DescribeFlags kProcessAccessflags[] = {
|
||||||
{kNtProcessAllAccess, "AllAccess"},
|
{kNtProcessAllAccess, "AllAccess"}, //
|
||||||
{kNtProcessCreateProcess, "CreateProcess"},
|
{kNtProcessCreateProcess, "CreateProcess"}, //
|
||||||
{kNtProcessCreateThread, "CreateThread"},
|
{kNtProcessCreateThread, "CreateThread"}, //
|
||||||
{kNtProcessDupHandle, "DupHandle"},
|
{kNtProcessDupHandle, "DupHandle"}, //
|
||||||
{kNtProcessQueryInformation, "QueryInformation"},
|
{kNtProcessQueryInformation, "QueryInformation"}, //
|
||||||
{kNtProcessQueryLimitedInformation, "QueryLimitedInformation"},
|
{kNtProcessQueryLimitedInformation, "QueryLimitedInformation"}, //
|
||||||
{kNtProcessSetInformation, "SetInformation"},
|
{kNtProcessSetInformation, "SetInformation"}, //
|
||||||
{kNtProcessSetQuota, "SetQuota"},
|
{kNtProcessSetQuota, "SetQuota"}, //
|
||||||
{kNtProcessSuspendResume, "SuspendResume"},
|
{kNtProcessSuspendResume, "SuspendResume"}, //
|
||||||
{kNtProcessTerminate, "Terminate"},
|
{kNtProcessTerminate, "Terminate"}, //
|
||||||
{kNtProcessVmOperation, "VmOperation"},
|
{kNtProcessVmOperation, "VmOperation"}, //
|
||||||
{kNtProcessVmRead, "VmRead"},
|
{kNtProcessVmRead, "VmRead"}, //
|
||||||
{kNtProcessVmWrite, "VmWrite"},
|
{kNtProcessVmWrite, "VmWrite"}, //
|
||||||
{kNtProcessSynchronize, "Synchronize"},
|
{kNtProcessSynchronize, "Synchronize"}, //
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *DescribeNtProcessAccessFlags(uint32_t x) {
|
const char *DescribeNtProcessAccessFlags(uint32_t x) {
|
||||||
|
|
|
@ -16,68 +16,63 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "dsp/core/core.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "dsp/mpeg/mpeg.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/rand/rand.h"
|
|
||||||
#include "libc/runtime/buffer.h"
|
|
||||||
#include "libc/testlib/ezbench.h"
|
|
||||||
#include "libc/testlib/testlib.h"
|
|
||||||
|
|
||||||
short pcm[8][8];
|
/**
|
||||||
float binary32[8][8];
|
* Returns current thread id.
|
||||||
struct GuardedBuffer b1, b2;
|
* @asyncsignalsafe
|
||||||
|
*/
|
||||||
|
int gettid(void) {
|
||||||
|
int rc;
|
||||||
|
int64_t wut;
|
||||||
|
|
||||||
TEST(float2short, test) {
|
if (IsLinux()) {
|
||||||
binary32[0][0] = -0.5;
|
asm("syscall"
|
||||||
binary32[0][1] = 0.0;
|
: "=a"(rc) // man says always succeeds
|
||||||
binary32[0][2] = 0.5;
|
: "0"(186) // __NR_gettid
|
||||||
float2short(8, pcm, binary32);
|
: "rcx", "r11", "memory");
|
||||||
EXPECT_EQ(-16384, pcm[0][0]);
|
return rc;
|
||||||
EXPECT_EQ(0, pcm[0][1]);
|
|
||||||
EXPECT_EQ(16384, pcm[0][2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(float2short, testOverflow) {
|
|
||||||
binary32[0][0] = -1.1;
|
|
||||||
binary32[0][1] = -1.0;
|
|
||||||
binary32[0][2] = 1.0;
|
|
||||||
binary32[0][3] = 1.1;
|
|
||||||
float2short(8, pcm, binary32);
|
|
||||||
EXPECT_EQ(-32768, pcm[0][0]);
|
|
||||||
EXPECT_EQ(-32768, pcm[0][1]);
|
|
||||||
EXPECT_EQ(32767, pcm[0][2]);
|
|
||||||
EXPECT_EQ(32767, pcm[0][3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unclamped(size_t n, short pcm16[n][8], const float binary32[n][8]) {
|
|
||||||
size_t i, j;
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
for (j = 0; j < 8; ++j) {
|
|
||||||
pcm16[i][j] = binary32[i][j] * 32768;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
plm_samples_t samps;
|
if (IsXnu()) {
|
||||||
|
asm("syscall" // xnu/osfmk/kern/ipc_tt.c
|
||||||
void randomizeaudio(void) {
|
: "=a"(rc) // assume success
|
||||||
size_t i;
|
: "0"(0x1000000 | 27) // Mach thread_self_trap()
|
||||||
for (i = 0; i < ARRAYLEN(samps.interleaved); ++i) {
|
: "rcx", "r11", "memory", "cc");
|
||||||
samps.interleaved[i] = randf();
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void float2short_pure(void) {
|
if (IsOpenbsd()) {
|
||||||
float2short(ARRAYLEN(samps.interleaved) / 8, pcm, (void *)samps.interleaved);
|
asm("syscall"
|
||||||
}
|
: "=a"(rc) // man says always succeeds
|
||||||
|
: "0"(299) // getthrid()
|
||||||
|
: "rcx", "r11", "memory", "cc");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void float2short_unclamped(void) {
|
if (IsNetbsd()) {
|
||||||
unclamped(ARRAYLEN(samps.interleaved) / 8, pcm, (void *)samps.interleaved);
|
asm("syscall"
|
||||||
}
|
: "=a"(rc) // man says always succeeds
|
||||||
|
: "0"(311) // _lwp_self()
|
||||||
|
: "rcx", "r11", "memory", "cc");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
BENCH(float2short, audioframe) {
|
if (IsFreebsd()) {
|
||||||
EZBENCH(randomizeaudio(), float2short_pure());
|
asm("syscall"
|
||||||
EZBENCH(randomizeaudio(), float2short_unclamped());
|
: "=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_INTRIN_A_DIRECTDEPS = \
|
||||||
LIBC_STUBS \
|
LIBC_STUBS \
|
||||||
LIBC_SYSV \
|
LIBC_SYSV \
|
||||||
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_NEXGEN32E \
|
LIBC_NEXGEN32E \
|
||||||
LIBC_NT_KERNEL32
|
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/createfile.greg.o \
|
||||||
o/$(MODE)/libc/intrin/createpipe.greg.o \
|
o/$(MODE)/libc/intrin/createpipe.greg.o \
|
||||||
o/$(MODE)/libc/intrin/closehandle.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/createthread.greg.o \
|
||||||
o/$(MODE)/libc/intrin/createprocess.greg.o \
|
o/$(MODE)/libc/intrin/createprocess.greg.o \
|
||||||
o/$(MODE)/libc/intrin/describeflags.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/deviceiocontrol.greg.o \
|
||||||
o/$(MODE)/libc/intrin/createdirectory.greg.o \
|
o/$(MODE)/libc/intrin/createdirectory.greg.o \
|
||||||
o/$(MODE)/libc/intrin/flushfilebuffers.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/getfileattributes.greg.o \
|
||||||
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
|
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
|
||||||
o/$(MODE)/libc/intrin/createfilemappingnuma.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/kstarttsc.o \
|
||||||
o/$(MODE)/libc/intrin/nomultics.o \
|
o/$(MODE)/libc/intrin/nomultics.o \
|
||||||
o/$(MODE)/libc/intrin/ntconsolemode.o: \
|
o/$(MODE)/libc/intrin/ntconsolemode.o: \
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#define ShouldUseMsabiAttribute() 1
|
#define ShouldUseMsabiAttribute() 1
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/likely.h"
|
#include "libc/bits/likely.h"
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
|
@ -27,7 +26,10 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/divmod10.internal.h"
|
#include "libc/fmt/divmod10.internal.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
#include "libc/str/utf16.h"
|
#include "libc/str/utf16.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/time/clockstonanos.internal.h"
|
||||||
|
|
||||||
struct Timestamps {
|
struct Timestamps {
|
||||||
unsigned long long birth;
|
unsigned long long birth;
|
||||||
|
@ -51,14 +54,7 @@ struct Timestamps {
|
||||||
extern int __pid;
|
extern int __pid;
|
||||||
extern bool __replmode;
|
extern bool __replmode;
|
||||||
extern bool __nomultics;
|
extern bool __nomultics;
|
||||||
volatile unsigned long long __kbirth;
|
unsigned long long __kbirth; // see fork-nt.c
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
privileged static struct Timestamps kenter(void) {
|
privileged static struct Timestamps kenter(void) {
|
||||||
struct Timestamps ts;
|
struct Timestamps ts;
|
||||||
|
@ -67,7 +63,7 @@ privileged static struct Timestamps kenter(void) {
|
||||||
if (!ts.birth) {
|
if (!ts.birth) {
|
||||||
ts.birth = kStartTsc;
|
ts.birth = kStartTsc;
|
||||||
if (!ts.birth) ts.birth = 1;
|
if (!ts.birth) ts.birth = 1;
|
||||||
cmpxchg(&__kbirth, 0, ts.birth);
|
_lockcmpxchg(&__kbirth, 0, ts.birth);
|
||||||
}
|
}
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +74,9 @@ privileged static void kleave(struct Timestamps ts) {
|
||||||
elapse = unsignedsubtract(finish, ts.start);
|
elapse = unsignedsubtract(finish, ts.start);
|
||||||
adjust = ts.birth + elapse;
|
adjust = ts.birth + elapse;
|
||||||
if (!adjust) adjust = 1;
|
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) {
|
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;
|
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().
|
* Privileged vsnprintf().
|
||||||
*
|
*
|
||||||
|
|
|
@ -5,6 +5,7 @@ COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
void kprintf(const char *, ...);
|
void kprintf(const char *, ...);
|
||||||
size_t ksnprintf(char *, size_t, const char *, ...);
|
size_t ksnprintf(char *, size_t, const char *, ...);
|
||||||
|
size_t kusnprintf(char *, size_t, const char *, ...);
|
||||||
void kvprintf(const char *, va_list);
|
void kvprintf(const char *, va_list);
|
||||||
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
||||||
bool kisdangerous(const void *);
|
bool kisdangerous(const void *);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares and exchanges w/ lock prefix.
|
* Compares and exchanges w/ lock prefix.
|
||||||
|
@ -24,23 +24,23 @@
|
||||||
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
* @param ifthing is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||||
* @param size is automatically supplied by macro wrapper
|
* @param size is automatically supplied by macro wrapper
|
||||||
* @return true if value was exchanged, otherwise false
|
* @return true if value was exchanged, otherwise false
|
||||||
* @see cmpxchg()
|
* @see cmpxchg() if only written by one thread
|
||||||
*/
|
*/
|
||||||
bool(lockcmpxchg)(void *ifthing, intptr_t isequaltome, intptr_t replaceitwithme,
|
bool(_lockcmpxchg)(void *ifthing, intptr_t isequaltome,
|
||||||
size_t size) {
|
intptr_t replaceitwithme, size_t size) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
return lockcmpxchg((int8_t *)ifthing, (int8_t)isequaltome,
|
return _lockcmpxchg((int8_t *)ifthing, (int8_t)isequaltome,
|
||||||
(int8_t)replaceitwithme);
|
(int8_t)replaceitwithme);
|
||||||
case 2:
|
case 2:
|
||||||
return lockcmpxchg((int16_t *)ifthing, (int16_t)isequaltome,
|
return _lockcmpxchg((int16_t *)ifthing, (int16_t)isequaltome,
|
||||||
(int16_t)replaceitwithme);
|
(int16_t)replaceitwithme);
|
||||||
case 4:
|
case 4:
|
||||||
return lockcmpxchg((int32_t *)ifthing, (int32_t)isequaltome,
|
return _lockcmpxchg((int32_t *)ifthing, (int32_t)isequaltome,
|
||||||
(int32_t)replaceitwithme);
|
(int32_t)replaceitwithme);
|
||||||
case 8:
|
case 8:
|
||||||
return lockcmpxchg((int64_t *)ifthing, (int64_t)isequaltome,
|
return _lockcmpxchg((int64_t *)ifthing, (int64_t)isequaltome,
|
||||||
(int64_t)replaceitwithme);
|
(int64_t)replaceitwithme);
|
||||||
default:
|
default:
|
||||||
return false;
|
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_ */
|
|
@ -1,9 +1,10 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_H_
|
||||||
#define COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_H_
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||||
/**
|
/**
|
||||||
* Compares and exchanges 128-bit value, i.e.
|
* Compares and exchanges 128-bit value, i.e.
|
||||||
*
|
*
|
||||||
|
@ -38,7 +39,8 @@ static inline bool _lockcmpxchg16b(uint128_t *IfThing, uint128_t *IsEqualToMe,
|
||||||
}
|
}
|
||||||
return DidIt;
|
return DidIt;
|
||||||
}
|
}
|
||||||
|
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_INTERNAL_H_ */
|
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKCMPXCHG16B_H_ */
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│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 │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,12 +16,29 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/limits.h"
|
#include "libc/intrin/lockxadd.h"
|
||||||
#include "libc/rand/internal.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/rand/lcg.internal.h"
|
|
||||||
#include "libc/rand/rand.h"
|
|
||||||
|
|
||||||
float randf(void) {
|
/**
|
||||||
return (double)(int)(KnuthLinearCongruentialGenerator(&g_rando) >> 32) /
|
* Compares and exchanges w/ lock prefix.
|
||||||
INT_MAX;
|
*
|
||||||
|
* @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();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKXADD_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_BITS_LOCKXADD_H_
|
||||||
#define COSMOPOLITAN_LIBC_BITS_LOCKXADD_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_BITS_LOCKXADD_H_
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
intptr_t _lockxadd(void *, intptr_t, size_t);
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||||
#define _lockxadd(PTR, VAL) \
|
#define _lockxadd(PTR, VAL) \
|
||||||
({ \
|
({ \
|
||||||
typeof(*(PTR)) Res; \
|
typeof(*(PTR)) Res; \
|
||||||
|
@ -10,7 +13,10 @@ COSMOPOLITAN_C_START_
|
||||||
asm volatile("lock xadd\t%0,%1" : "=r"(Res), "+m"(*(PTR)) : "0"(Val)); \
|
asm volatile("lock xadd\t%0,%1" : "=r"(Res), "+m"(*(PTR)) : "0"(Val)); \
|
||||||
Res; /* contains *PTR before addition cf. InterlockedAdd() */ \
|
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_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKXADD_INTERNAL_H_ */
|
#endif /* COSMOPOLITAN_LIBC_BITS_LOCKXADD_H_ */
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/lockxchg.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares and exchanges w/ lock prefix.
|
* Compares and exchanges w/ lock prefix.
|
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"
|
#include "libc/runtime/internal.h"
|
||||||
|
|
||||||
uint32_t __ntconsolemode[2];
|
uint32_t __ntconsolemode[3];
|
||||||
|
|
|
@ -23,7 +23,12 @@
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
|
|
||||||
uint32_t __winmainpid;
|
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.
|
* Puts cmd.exe gui back the way it was.
|
||||||
|
@ -31,7 +36,7 @@ const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle};
|
||||||
noasan void __restorewintty(void) {
|
noasan void __restorewintty(void) {
|
||||||
int i;
|
int i;
|
||||||
if (IsWindows() && GetCurrentProcessId() == __winmainpid) {
|
if (IsWindows() && GetCurrentProcessId() == __winmainpid) {
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
||||||
}
|
}
|
||||||
__winmainpid = 0;
|
__winmainpid = 0;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,24 +16,35 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns current thread id.
|
* Acquires spinlock.
|
||||||
* @asyncsignalsafe
|
|
||||||
*/
|
*/
|
||||||
uint32_t gettid(void) {
|
void cthread_spinlock(cthread_spinlock_t *lock) {
|
||||||
uint32_t res;
|
#if 0
|
||||||
if (!IsWindows()) {
|
// TODO(jart): possibly reenable for !NDEBUG when we have TLS
|
||||||
res = sys_gettid();
|
int me = gettid();
|
||||||
if (res <= 0) {
|
if (lock->x && lock->owner == me) {
|
||||||
res = getpid();
|
assert(!"cosmo spinlock not intended to be reentrant");
|
||||||
}
|
return;
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
return GetCurrentThreadId();
|
|
||||||
}
|
}
|
||||||
|
#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_ */
|
|
@ -16,9 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
@ -33,18 +32,18 @@
|
||||||
*/
|
*/
|
||||||
relegated wontreturn void __die(void) {
|
relegated wontreturn void __die(void) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
|
int rc;
|
||||||
static bool once;
|
static bool once;
|
||||||
kprintf("__die() called%n");
|
if (_lockcmpxchg(&once, false, true)) {
|
||||||
if (lockcmpxchg(&once, false, true)) {
|
|
||||||
__restore_tty(1);
|
__restore_tty(1);
|
||||||
if (IsDebuggerPresent(false)) {
|
if (IsDebuggerPresent(false)) {
|
||||||
DebugBreak();
|
DebugBreak();
|
||||||
}
|
}
|
||||||
ShowBacktrace(2, NULL);
|
ShowBacktrace(2, NULL);
|
||||||
__restorewintty();
|
rc = 77;
|
||||||
_Exit(77);
|
} else {
|
||||||
|
rc = 78;
|
||||||
}
|
}
|
||||||
kprintf("panic: __die() died%n");
|
|
||||||
__restorewintty();
|
__restorewintty();
|
||||||
_Exit(78);
|
_Exit(rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -72,7 +73,7 @@ static noasan bool HasLeaks(void) {
|
||||||
*/
|
*/
|
||||||
noasan void CheckForMemoryLeaks(void) {
|
noasan void CheckForMemoryLeaks(void) {
|
||||||
struct mallinfo mi;
|
struct mallinfo mi;
|
||||||
if (!lockcmpxchg(&once, false, true)) {
|
if (!_lockcmpxchg(&once, false, true)) {
|
||||||
kprintf("CheckForMemoryLeaks() may only be called once\n");
|
kprintf("CheckForMemoryLeaks() may only be called once\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
|
@ -25,6 +24,7 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/gdb.h"
|
#include "libc/log/gdb.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
|
@ -301,7 +301,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||||
static bool noreentry, notpossible;
|
static bool noreentry, notpossible;
|
||||||
st = __strace, __strace = 0;
|
st = __strace, __strace = 0;
|
||||||
ft = g_ftrace, g_ftrace = 0;
|
ft = g_ftrace, g_ftrace = 0;
|
||||||
if (lockcmpxchg(&noreentry, false, true)) {
|
if (_lockcmpxchg(&noreentry, false, true)) {
|
||||||
if (!__vforked) {
|
if (!__vforked) {
|
||||||
rip = ctx ? ctx->uc_mcontext.rip : 0;
|
rip = ctx ? ctx->uc_mcontext.rip : 0;
|
||||||
err = errno;
|
err = errno;
|
||||||
|
@ -331,7 +331,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||||
g_ftrace = ft;
|
g_ftrace = ft;
|
||||||
__strace = st;
|
__strace = st;
|
||||||
return;
|
return;
|
||||||
} else if (lockcmpxchg(¬possible, false, true)) {
|
} else if (_lockcmpxchg(¬possible, false, true)) {
|
||||||
__minicrash(sig, si, ctx, "WHILE CRASHING");
|
__minicrash(sig, si, ctx, "WHILE CRASHING");
|
||||||
} else {
|
} else {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_RDTSCP_H_
|
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_RDTSCP_H_
|
||||||
#define COSMOPOLITAN_LIBC_NEXGEN32E_RDTSCP_H_
|
#define COSMOPOLITAN_LIBC_NEXGEN32E_RDTSCP_H_
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
|
@ -17,7 +17,6 @@ void rt_end(double *, double *, double *, double *, double *);
|
||||||
char *strfry(char *);
|
char *strfry(char *);
|
||||||
int getentropy(void *, size_t);
|
int getentropy(void *, size_t);
|
||||||
ssize_t getrandom(void *, size_t, unsigned);
|
ssize_t getrandom(void *, size_t, unsigned);
|
||||||
float randf(void);
|
|
||||||
char *initstate(unsigned, char *, size_t);
|
char *initstate(unsigned, char *, size_t);
|
||||||
char *setstate(char *);
|
char *setstate(char *);
|
||||||
long random(void);
|
long random(void);
|
||||||
|
|
|
@ -18,11 +18,9 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/lockcmpxchg16b.internal.h"
|
|
||||||
#include "libc/bits/lockxadd.internal.h"
|
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/nexgen32e/rdtsc.h"
|
#include "libc/nexgen32e/rdtsc.h"
|
||||||
#include "libc/nt/thread.h"
|
#include "libc/nt/thread.h"
|
||||||
#include "libc/rand/rand.h"
|
#include "libc/rand/rand.h"
|
||||||
|
@ -32,8 +30,8 @@
|
||||||
|
|
||||||
extern int __pid;
|
extern int __pid;
|
||||||
static int thepid;
|
static int thepid;
|
||||||
static int thecount;
|
|
||||||
static uint128_t thepool;
|
static uint128_t thepool;
|
||||||
|
static cthread_spinlock_t rand64_lock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns nondeterministic random data.
|
* Returns nondeterministic random data.
|
||||||
|
@ -48,48 +46,35 @@ static uint128_t thepool;
|
||||||
* @see rdseed(), rdrand(), rand(), random(), rngset()
|
* @see rdseed(), rdrand(), rand(), random(), rngset()
|
||||||
* @note this function is not intended for cryptography
|
* @note this function is not intended for cryptography
|
||||||
* @note this function passes bigcrush and practrand
|
* @note this function passes bigcrush and practrand
|
||||||
* @note this function takes at minimum 30 cycles
|
* @note this function takes at minimum 15 cycles
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
uint64_t rand64(void) {
|
uint64_t rand64(void) {
|
||||||
void *d;
|
void *p;
|
||||||
int c1, p1, p2;
|
uint128_t s;
|
||||||
uint128_t s1, s2;
|
cthread_spinlock(&rand64_lock);
|
||||||
do {
|
if (__pid == thepid) {
|
||||||
p1 = __pid;
|
s = thepool; // normal path
|
||||||
p2 = thepid;
|
} else {
|
||||||
c1 = thecount;
|
if (!thepid) {
|
||||||
asm volatile("" ::: "memory");
|
if (AT_RANDOM && (p = (void *)getauxval(AT_RANDOM))) {
|
||||||
s1 = thepool;
|
// linux / freebsd kernel supplied entropy
|
||||||
if (p1 == p2) {
|
memcpy(&s, p, 16);
|
||||||
// fast path
|
|
||||||
s2 = s1;
|
|
||||||
} else {
|
|
||||||
// slow path
|
|
||||||
if (!p2) {
|
|
||||||
// first call so get some cheap entropy
|
|
||||||
if ((d = (void *)getauxval(AT_RANDOM))) {
|
|
||||||
memcpy(&s2, d, 16); // kernel entropy
|
|
||||||
} else {
|
|
||||||
s2 = kStartTsc; // rdtsc() @ _start()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// process contention so blend a timestamp
|
// otherwise initialize w/ cheap timestamp
|
||||||
s2 = s1 ^ rdtsc();
|
s = kStartTsc;
|
||||||
}
|
}
|
||||||
// toss the new pid in there
|
} else {
|
||||||
s2 ^= p1;
|
// blend another timestamp on fork contention
|
||||||
// ordering for thepid probably doesn't matter
|
s = thepool ^ rdtsc();
|
||||||
thepid = p1;
|
|
||||||
}
|
}
|
||||||
// lemur64 pseudorandom number generator
|
// blend the pid on startup and fork contention
|
||||||
s2 *= 15750249268501108917ull;
|
s ^= __pid;
|
||||||
// sadly 128-bit values aren't atomic on x86
|
thepid = __pid;
|
||||||
_lockcmpxchg16b(&thepool, &s1, s2);
|
}
|
||||||
// do it again if there's thread contention
|
thepool = (s *= 15750249268501108917ull); // lemur64
|
||||||
} while (_lockxadd(&thecount, 1) != c1);
|
cthread_spunlock(&rand64_lock);
|
||||||
// the most important step in the prng
|
return s >> 64;
|
||||||
return s2 >> 64;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/rand/rand.h"
|
#include "libc/rand/rand.h"
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/asmflag.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/rand/rand.h"
|
#include "libc/rand/rand.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,22 +16,32 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/typedef/sigaction_f.h"
|
#include "libc/calls/sig.internal.h"
|
||||||
|
#include "libc/calls/sigbits.h"
|
||||||
|
#include "libc/calls/struct/sigset.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
textwindows wontreturn void sys_abort_nt(void) {
|
/**
|
||||||
int rva;
|
* Terminates program abnormally.
|
||||||
siginfo_t info;
|
*
|
||||||
bzero(&info, sizeof(info));
|
* This function first tries to trigger your SIGABRT handler. If
|
||||||
info.si_signo = SIGABRT;
|
* there isn't one or execution resumes, then abort() terminates
|
||||||
rva = __sighandrvas[SIGABRT];
|
* the program using an escalating variety methods of increasing
|
||||||
if (rva >= kSigactionMinRva) {
|
* brutality.
|
||||||
if (((sigaction_f)(_base + rva))) {
|
*
|
||||||
((sigaction_f)(_base + rva))(SIGABRT, &info, NULL);
|
* @asyncsignalsafe
|
||||||
}
|
* @noreturn
|
||||||
}
|
*/
|
||||||
|
privileged void abort(void) {
|
||||||
|
sigset_t sm;
|
||||||
|
sigfillset(&sm);
|
||||||
|
sigdelset(&sm, SIGABRT);
|
||||||
|
sigprocmask(SIG_SETMASK, &sm, 0);
|
||||||
|
raise(SIGABRT);
|
||||||
|
__restorewintty();
|
||||||
_Exit(128 + SIGABRT);
|
_Exit(128 + SIGABRT);
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/asmflag.h"
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
@ -113,12 +114,14 @@ static int arch_prctl_freebsd(int code, int64_t addr) {
|
||||||
|
|
||||||
static privileged dontinline int arch_prctl_xnu(int code, int64_t addr) {
|
static privileged dontinline int arch_prctl_xnu(int code, int64_t addr) {
|
||||||
int ax;
|
int ax;
|
||||||
|
bool failed;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ARCH_SET_GS:
|
case ARCH_SET_GS:
|
||||||
asm volatile("syscall"
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
: "=a"(ax)
|
: CFLAG_CONSTRAINT(failed), "=a"(ax)
|
||||||
: "0"(0x3000003), "D"(addr - 0x8a0 /* wat */)
|
: "1"(0x3000003), "D"(addr - 0x8a0 /* wat */)
|
||||||
: "rcx", "r11", "memory", "cc");
|
: "rcx", "r11", "memory", "cc");
|
||||||
|
if (failed) errno = ax, ax = -1;
|
||||||
return ax;
|
return ax;
|
||||||
case ARCH_GET_FS:
|
case ARCH_GET_FS:
|
||||||
case ARCH_SET_FS:
|
case ARCH_SET_FS:
|
||||||
|
@ -130,21 +133,30 @@ static privileged dontinline int arch_prctl_xnu(int code, int64_t addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static privileged dontinline int arch_prctl_openbsd(int code, int64_t addr) {
|
static privileged dontinline int arch_prctl_openbsd(int code, int64_t addr) {
|
||||||
|
bool failed;
|
||||||
int64_t rax;
|
int64_t rax;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ARCH_GET_FS:
|
case ARCH_GET_FS:
|
||||||
asm volatile("syscall"
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
: "=a"(rax)
|
: CFLAG_CONSTRAINT(failed), "=a"(rax)
|
||||||
: "0"(0x014a /* __get_tcb */)
|
: "1"(0x014a /* __get_tcb */)
|
||||||
: "rcx", "r11", "cc", "memory");
|
: "rcx", "r11", "cc", "memory");
|
||||||
|
if (failed) {
|
||||||
|
errno = rax;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*(int64_t *)addr = rax;
|
*(int64_t *)addr = rax;
|
||||||
return 0;
|
return 0;
|
||||||
case ARCH_SET_FS:
|
case ARCH_SET_FS:
|
||||||
asm volatile("syscall"
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
: "=a"(rax)
|
: CFLAG_CONSTRAINT(failed), "=a"(rax)
|
||||||
: "0"(0x0149 /* __set_tcb */), "D"(addr)
|
: "1"(0x0149 /* __set_tcb */), "D"(addr)
|
||||||
: "rcx", "r11", "cc", "memory");
|
: "rcx", "r11", "cc", "memory");
|
||||||
return 0;
|
if (failed) {
|
||||||
|
errno = rax;
|
||||||
|
rax = -1;
|
||||||
|
}
|
||||||
|
return rax;
|
||||||
case ARCH_GET_GS:
|
case ARCH_GET_GS:
|
||||||
case ARCH_SET_GS:
|
case ARCH_SET_GS:
|
||||||
return enosys();
|
return enosys();
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/lockxchg.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,8 +25,10 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/nexgen32e/nt2sysv.h"
|
#include "libc/nexgen32e/nt2sysv.h"
|
||||||
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/enum/filemapflags.h"
|
#include "libc/nt/enum/filemapflags.h"
|
||||||
#include "libc/nt/enum/pageflags.h"
|
#include "libc/nt/enum/pageflags.h"
|
||||||
|
#include "libc/nt/enum/processcreationflags.h"
|
||||||
#include "libc/nt/enum/startf.h"
|
#include "libc/nt/enum/startf.h"
|
||||||
#include "libc/nt/ipc.h"
|
#include "libc/nt/ipc.h"
|
||||||
#include "libc/nt/memory.h"
|
#include "libc/nt/memory.h"
|
||||||
|
@ -49,6 +51,7 @@ extern unsigned char __data_start[]; /* αpε */
|
||||||
extern unsigned char __data_end[]; /* αpε */
|
extern unsigned char __data_end[]; /* αpε */
|
||||||
extern unsigned char __bss_start[]; /* αpε */
|
extern unsigned char __bss_start[]; /* αpε */
|
||||||
extern unsigned char __bss_end[]; /* αpε */
|
extern unsigned char __bss_end[]; /* αpε */
|
||||||
|
bool32 __onntconsoleevent_nt(uint32_t);
|
||||||
|
|
||||||
static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||||
*x = 0;
|
*x = 0;
|
||||||
|
@ -219,6 +222,9 @@ textwindows void WinMainForked(void) {
|
||||||
if (weaken(__wincrash_nt)) {
|
if (weaken(__wincrash_nt)) {
|
||||||
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt));
|
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt));
|
||||||
}
|
}
|
||||||
|
if (weaken(__onntconsoleevent_nt)) {
|
||||||
|
SetConsoleCtrlHandler(weaken(__onntconsoleevent_nt), 1);
|
||||||
|
}
|
||||||
longjmp(jb, 1);
|
longjmp(jb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +263,8 @@ textwindows int sys_fork_nt(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar,
|
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar,
|
||||||
&kNtIsInheritable, NULL, true, 0, NULL, &startinfo,
|
&kNtIsInheritable, NULL, true,
|
||||||
|
0 /* kNtCreateNewProcessGroup */, NULL, &startinfo,
|
||||||
&procinfo) != -1) {
|
&procinfo) != -1) {
|
||||||
CloseHandle(reader);
|
CloseHandle(reader);
|
||||||
CloseHandle(procinfo.hThread);
|
CloseHandle(procinfo.hThread);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/lockxchg.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -84,7 +84,7 @@ privileged noinstrument noasan noubsan void ftracer(void) {
|
||||||
uint64_t stamp;
|
uint64_t stamp;
|
||||||
static bool noreentry;
|
static bool noreentry;
|
||||||
struct StackFrame *frame;
|
struct StackFrame *frame;
|
||||||
if (!cmpxchg(&noreentry, 0, 1)) return;
|
if (!_cmpxchg(&noreentry, 0, 1)) return;
|
||||||
if (ftrace_enabled && g_symbols) {
|
if (ftrace_enabled && g_symbols) {
|
||||||
stamp = rdtsc();
|
stamp = rdtsc();
|
||||||
frame = __builtin_frame_address(0);
|
frame = __builtin_frame_address(0);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
extern uint32_t __ntconsolemode[2];
|
extern uint32_t __ntconsolemode[3];
|
||||||
extern const char v_ntsubsystem[] __attribute__((__weak__));
|
extern const char v_ntsubsystem[] __attribute__((__weak__));
|
||||||
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
|
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
|
||||||
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));
|
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
typedef void *pthread_t;
|
typedef void *pthread_t;
|
||||||
|
@ -25,7 +25,7 @@ typedef bool pthread_once_t;
|
||||||
typedef int pthread_mutex_t;
|
typedef int pthread_mutex_t;
|
||||||
|
|
||||||
int pthread_once(pthread_once_t *once, void init(void)) {
|
int pthread_once(pthread_once_t *once, void init(void)) {
|
||||||
if (lockcmpxchg(once, 0, 1)) init();
|
if (_lockcmpxchg(once, 0, 1)) init();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,15 +80,17 @@ struct WinArgs {
|
||||||
extern int __pid;
|
extern int __pid;
|
||||||
extern bool __nomultics;
|
extern bool __nomultics;
|
||||||
extern uint32_t __winmainpid;
|
extern uint32_t __winmainpid;
|
||||||
extern const char kConsoleHandles[2];
|
extern const char kConsoleHandles[3];
|
||||||
|
|
||||||
static const short kConsoleModes[2] = {
|
static const short kConsoleModes[3] = {
|
||||||
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
|
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
|
||||||
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
|
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
|
||||||
kNtEnableAutoPosition | kNtEnableInsertMode |
|
kNtEnableAutoPosition | kNtEnableInsertMode |
|
||||||
kNtEnableVirtualTerminalInput,
|
kNtEnableVirtualTerminalInput,
|
||||||
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
|
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
|
||||||
kNtEnableVirtualTerminalProcessing,
|
kNtEnableVirtualTerminalProcessing,
|
||||||
|
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
|
||||||
|
kNtEnableVirtualTerminalProcessing,
|
||||||
};
|
};
|
||||||
|
|
||||||
forceinline void MakeLongDoubleLongAgain(void) {
|
forceinline void MakeLongDoubleLongAgain(void) {
|
||||||
|
@ -128,7 +130,7 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
|
||||||
STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc);
|
STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc);
|
||||||
rc = SetConsoleOutputCP(kNtCpUtf8);
|
rc = SetConsoleOutputCP(kNtCpUtf8);
|
||||||
STRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc);
|
STRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc);
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
hand = GetStdHandle(kConsoleHandles[i]);
|
hand = GetStdHandle(kConsoleHandles[i]);
|
||||||
rc = GetConsoleMode(hand, __ntconsolemode + i);
|
rc = GetConsoleMode(hand, __ntconsolemode + i);
|
||||||
STRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i], rc);
|
STRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i], rc);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/lockxchg.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.internal.inc"
|
|
||||||
.scall setpgid,0x052052052205206d,globl
|
|
2
libc/sysv/calls/sys_setpgid.s
Normal file
2
libc/sysv/calls/sys_setpgid.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "o/libc/sysv/macros.internal.inc"
|
||||||
|
.scall sys_setpgid,0x052052052205206d,globl,hidden
|
|
@ -149,7 +149,7 @@ scall getpgrp 0x051051051205106f globl
|
||||||
scall sys_setsid 0x0930930932093070 globl hidden
|
scall sys_setsid 0x0930930932093070 globl hidden
|
||||||
scall sys_getsid 0x11e0ff136213607c globl hidden
|
scall sys_getsid 0x11e0ff136213607c globl hidden
|
||||||
scall sys_getpgid 0x0cf0cf0cf2097079 globl hidden
|
scall sys_getpgid 0x0cf0cf0cf2097079 globl hidden
|
||||||
scall setpgid 0x052052052205206d globl
|
scall sys_setpgid 0x052052052205206d globl hidden
|
||||||
scall geteuid 0xfff019019201906b globl
|
scall geteuid 0xfff019019201906b globl
|
||||||
scall getegid 0xfff02b02b202b06c globl
|
scall getegid 0xfff02b02b202b06c globl
|
||||||
scall getgroups 0x04f04f04f204f073 globl
|
scall getgroups 0x04f04f04f204f073 globl
|
||||||
|
|
112
libc/thread/freebsd.internal.h
Normal file
112
libc/thread/freebsd.internal.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_THREAD_FREEBSD_INTERNAL_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_THREAD_FREEBSD_INTERNAL_H_
|
||||||
|
#include "libc/bits/asmflag.h"
|
||||||
|
#include "libc/calls/struct/timespec.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview FreeBSD Threading
|
||||||
|
*
|
||||||
|
* @note even though FreeBSD uses a 64-bit type for thread IDs the
|
||||||
|
* maximum legal range is PID_MAX + 2 (100001) through INT_MAX
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct rtprio {
|
||||||
|
uint16_t type; /* scheduling class */
|
||||||
|
uint16_t prio;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thr_param {
|
||||||
|
void (*start_func)(void *);
|
||||||
|
void *arg;
|
||||||
|
char *stack_base;
|
||||||
|
uint64_t stack_size;
|
||||||
|
char *tls_base;
|
||||||
|
uint64_t tls_size;
|
||||||
|
int64_t *child_tid;
|
||||||
|
int64_t *parent_tid;
|
||||||
|
int32_t flags;
|
||||||
|
struct rtprio *rtp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline wontreturn void thr_exit(int64_t *opt_out_state) {
|
||||||
|
long ax, di;
|
||||||
|
asm volatile("syscall"
|
||||||
|
: "=a"(ax)
|
||||||
|
: "0"(431), "D"(opt_out_state)
|
||||||
|
: "memory", "cc");
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thr_new(struct thr_param *param, int param_size) {
|
||||||
|
bool failed;
|
||||||
|
long ax, di, si;
|
||||||
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
|
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=D"(di), "=S"(si)
|
||||||
|
: "1"(455), "2"(param), "3"(param_size)
|
||||||
|
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
|
||||||
|
if (failed) ax = -ax;
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thr_kill(int64_t id, int sig) {
|
||||||
|
bool failed;
|
||||||
|
long ax, di, si;
|
||||||
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
|
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=D"(di), "=S"(si)
|
||||||
|
: "1"(433), "2"(id), "3"(sig)
|
||||||
|
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
|
||||||
|
if (failed) ax = -ax;
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thr_suspend(const struct timespec *opt_timeout) {
|
||||||
|
bool failed;
|
||||||
|
long ax, di;
|
||||||
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
|
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=D"(di)
|
||||||
|
: "1"(442), "2"(opt_timeout)
|
||||||
|
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory");
|
||||||
|
if (failed) ax = -ax;
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thr_wake(int64_t id) {
|
||||||
|
bool failed;
|
||||||
|
long ax, di;
|
||||||
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
|
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=D"(di)
|
||||||
|
: "1"(443), "2"(id)
|
||||||
|
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory");
|
||||||
|
if (failed) ax = -ax;
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thr_set_name(int64_t id, const char *name) {
|
||||||
|
bool failed;
|
||||||
|
long ax, di, si;
|
||||||
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
|
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=D"(di), "=S"(si)
|
||||||
|
: "1"(464), "2"(id), "3"(name)
|
||||||
|
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
|
||||||
|
if (failed) ax = -ax;
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int thr_kill2(int pid, int64_t id, int sig) {
|
||||||
|
bool failed;
|
||||||
|
long ax, di, si, dx;
|
||||||
|
asm volatile(CFLAG_ASM("syscall")
|
||||||
|
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=D"(di), "=S"(si),
|
||||||
|
"=d"(dx)
|
||||||
|
: "1"(481), "2"(pid), "3"(id), "4"(sig)
|
||||||
|
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||||
|
if (failed) ax = -ax;
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_THREAD_FREEBSD_INTERNAL_H_ */
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/atomic.h"
|
#include "libc/bits/atomic.h"
|
||||||
|
#include "libc/intrin/atomic_load.h"
|
||||||
#include "libc/thread/sem.h"
|
#include "libc/thread/sem.h"
|
||||||
#include "libc/thread/wait.h"
|
#include "libc/thread/wait.h"
|
||||||
#include "libc/thread/yield.h"
|
#include "libc/thread/yield.h"
|
||||||
|
@ -37,6 +38,7 @@ int cthread_sem_init(cthread_sem_t* sem, int count) {
|
||||||
sem->linux.count = count;
|
sem->linux.count = count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cthread_sem_destroy(cthread_sem_t* sem) {
|
int cthread_sem_destroy(cthread_sem_t* sem) {
|
||||||
(void)sem;
|
(void)sem;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -44,7 +46,7 @@ int cthread_sem_destroy(cthread_sem_t* sem) {
|
||||||
|
|
||||||
int cthread_sem_signal(cthread_sem_t* sem) {
|
int cthread_sem_signal(cthread_sem_t* sem) {
|
||||||
uint64_t count;
|
uint64_t count;
|
||||||
asm volatile("lock xadd\t%1, %0"
|
asm volatile("lock xadd\t%1,%0"
|
||||||
: "+m"(sem->linux.count), "=r"(count)
|
: "+m"(sem->linux.count), "=r"(count)
|
||||||
: "1"(1)
|
: "1"(1)
|
||||||
: "cc");
|
: "cc");
|
||||||
|
@ -62,7 +64,7 @@ int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) {
|
||||||
uint64_t count;
|
uint64_t count;
|
||||||
|
|
||||||
// record current thread as waiter
|
// record current thread as waiter
|
||||||
asm volatile("lock xadd\t%1, %0"
|
asm volatile("lock xadd\t%1,%0"
|
||||||
: "+m"(sem->linux.count), "=r"(count)
|
: "+m"(sem->linux.count), "=r"(count)
|
||||||
: "1"((uint64_t)1 << CTHREAD_THREAD_VAL_BITS)
|
: "1"((uint64_t)1 << CTHREAD_THREAD_VAL_BITS)
|
||||||
: "cc");
|
: "cc");
|
||||||
|
@ -77,7 +79,7 @@ int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: an offset of 4 bytes would be required on little-endian archs
|
// WARNING: an offset of 4 bytes would be required on little-endian archs
|
||||||
void* wait_address = &sem->linux.count;
|
void* wait_address = &sem->linux.count;
|
||||||
cthread_memory_wait32(wait_address, count, timeout);
|
cthread_memory_wait32(wait_address, count, timeout);
|
||||||
|
@ -91,16 +93,17 @@ int cthread_sem_wait_spin(cthread_sem_t* sem, uint64_t count, int spin,
|
||||||
const struct timespec* timeout) {
|
const struct timespec* timeout) {
|
||||||
// spin on pause
|
// spin on pause
|
||||||
for (int attempt = 0; attempt < spin; ++attempt) {
|
for (int attempt = 0; attempt < spin; ++attempt) {
|
||||||
//if ((count >> CTHREAD_THREAD_VAL_BITS) != 0) break;
|
// if ((count >> CTHREAD_THREAD_VAL_BITS) != 0) break;
|
||||||
while ((uint32_t)count > 0) {
|
while ((uint32_t)count > 0) {
|
||||||
// spin is useful if multiple waiters can acquire the semaphore at the same time
|
// spin is useful if multiple waiters can acquire the semaphore at the
|
||||||
|
// same time
|
||||||
if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) {
|
if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pause(attempt);
|
pause(attempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cthread_sem_wait_futex(sem, timeout);
|
return cthread_sem_wait_futex(sem, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,11 +113,12 @@ int cthread_sem_wait(cthread_sem_t* sem, int spin,
|
||||||
|
|
||||||
// uncontended
|
// uncontended
|
||||||
while ((uint32_t)count > 0) {
|
while ((uint32_t)count > 0) {
|
||||||
// spin is useful if multiple waiters can acquire the semaphore at the same time
|
// spin is useful if multiple waiters can acquire the semaphore at the same
|
||||||
|
// time
|
||||||
if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) {
|
if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cthread_sem_wait_spin(sem, count, spin, timeout);
|
return cthread_sem_wait_spin(sem, count, spin, timeout);
|
||||||
}
|
}
|
||||||
|
|
25
libc/thread/xnu.internal.h
Normal file
25
libc/thread/xnu.internal.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_THREAD_XNU_INTERNAL_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_THREAD_XNU_INTERNAL_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XNU thread system calls.
|
||||||
|
* @see darwin-libpthread/kern/kern_support.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *bsdthread_create(void *func, void *func_arg, void *stack, void *pthread,
|
||||||
|
uint32_t flags);
|
||||||
|
int bsdthread_terminate(void *stackaddr, size_t freesize, uint32_t port,
|
||||||
|
uint32_t sem);
|
||||||
|
int bsdthread_register(void *threadstart, void *wqthread, uint32_t flags,
|
||||||
|
void *stack_addr_hint, void *targetconc_ptr,
|
||||||
|
uint32_t dispatchqueue_offset, uint32_t tsd_offset);
|
||||||
|
int bsdthread_ctl(void *cmd, void *arg1, void *arg2, void *arg3);
|
||||||
|
uint64_t thread_selfid(void);
|
||||||
|
uint64_t thread_selfusage(void);
|
||||||
|
int thread_selfcounts(int type, void *buf, uint64_t nbytes);
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_THREAD_XNU_INTERNAL_H_ */
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef COSMOPOLITAN_TOOL_PLINKO_LIB_TIME_H_
|
#ifndef COSMOPOLITAN_LIBC_TIME_CLOCKSTONANOS_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_TOOL_PLINKO_LIB_TIME_H_
|
#define COSMOPOLITAN_LIBC_TIME_CLOCKSTONANOS_INTERNAL_H_
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
@ -12,4 +12,4 @@ static inline uint64_t ClocksToNanos(uint64_t x, uint64_t y) {
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_TOOL_PLINKO_LIB_TIME_H_ */
|
#endif /* COSMOPOLITAN_LIBC_TIME_CLOCKSTONANOS_INTERNAL_H_ */
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
@ -58,7 +58,7 @@ void *xload(bool *o, void **t, const void *p, size_t n, size_t m) {
|
||||||
zs.next_out = (void *)q;
|
zs.next_out = (void *)q;
|
||||||
inflateInit2(&zs, -MAX_WBITS);
|
inflateInit2(&zs, -MAX_WBITS);
|
||||||
inflate(&zs, Z_NO_FLUSH);
|
inflate(&zs, Z_NO_FLUSH);
|
||||||
if (lockcmpxchg(t, 0, q)) {
|
if (_lockcmpxchg(t, 0, q)) {
|
||||||
__cxa_atexit(free, q, 0);
|
__cxa_atexit(free, q, 0);
|
||||||
} else {
|
} else {
|
||||||
free(q);
|
free(q);
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/fmt/leb128.h"
|
#include "libc/fmt/leb128.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/nexgen32e/crc32.h"
|
#include "libc/nexgen32e/crc32.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
@ -69,7 +69,7 @@ void *xloadzd(bool *o, void **t, const void *p, size_t n, size_t m, size_t c,
|
||||||
}
|
}
|
||||||
free(q);
|
free(q);
|
||||||
assert(crc32_z(0, r, c * z) == s);
|
assert(crc32_z(0, r, c * z) == s);
|
||||||
if (lockcmpxchg(t, 0, r)) {
|
if (_lockcmpxchg(t, 0, r)) {
|
||||||
__cxa_atexit(free, r, 0);
|
__cxa_atexit(free, r, 0);
|
||||||
} else {
|
} else {
|
||||||
free(q);
|
free(q);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -129,7 +130,7 @@ int UncacheSslSession(void *data, mbedtls_ssl_session *session) {
|
||||||
ts = time(0);
|
ts = time(0);
|
||||||
if (!(e->time <= ts && ts <= e->time + cache->lifetime)) {
|
if (!(e->time <= ts && ts <= e->time + cache->lifetime)) {
|
||||||
DEBUGF("%u sslcache expired", i);
|
DEBUGF("%u sslcache expired", i);
|
||||||
lockcmpxchg(&e->tick, tick, 0);
|
_lockcmpxchg(&e->tick, tick, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
cert = 0;
|
cert = 0;
|
||||||
|
@ -199,7 +200,7 @@ int CacheSslSession(void *data, const mbedtls_ssl_session *session) {
|
||||||
e->time = time(0);
|
e->time = time(0);
|
||||||
tick = rdtsc();
|
tick = rdtsc();
|
||||||
asm volatile("" ::: "memory");
|
asm volatile("" ::: "memory");
|
||||||
if (tick && lockcmpxchg(&e->pid, pid, 0)) {
|
if (tick && _lockcmpxchg(&e->pid, pid, 0)) {
|
||||||
DEBUGF("%u saved %s%s %`#.*s", i,
|
DEBUGF("%u saved %s%s %`#.*s", i,
|
||||||
mbedtls_ssl_get_ciphersuite_name(session->ciphersuite),
|
mbedtls_ssl_get_ciphersuite_name(session->ciphersuite),
|
||||||
session->compression ? " DEFLATE" : "", session->id_len,
|
session->compression ? " DEFLATE" : "", session->id_len,
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
@ -39,37 +40,10 @@ void OnSigInt(int sig) {
|
||||||
|
|
||||||
void SetUp(void) {
|
void SetUp(void) {
|
||||||
gotsigint = false;
|
gotsigint = false;
|
||||||
/* TODO(jart): Windows needs huge signal overhaul */
|
|
||||||
if (IsWindows()) exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(sigaction, test) {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int pid, status;
|
// test raise()
|
||||||
sigset_t block, ignore, oldmask;
|
|
||||||
struct sigaction saint = {.sa_handler = OnSigInt};
|
|
||||||
sigemptyset(&block);
|
|
||||||
sigaddset(&block, SIGINT);
|
|
||||||
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &block, &oldmask));
|
|
||||||
sigfillset(&ignore);
|
|
||||||
sigdelset(&ignore, SIGINT);
|
|
||||||
EXPECT_NE(-1, sigaction(SIGINT, &saint, &oldsa));
|
|
||||||
ASSERT_NE(-1, (pid = fork()));
|
|
||||||
if (!pid) {
|
|
||||||
EXPECT_NE(-1, kill(getppid(), SIGINT));
|
|
||||||
EXPECT_EQ(-1, sigsuspend(&ignore));
|
|
||||||
EXPECT_EQ(EINTR, errno);
|
|
||||||
EXPECT_TRUE(gotsigint);
|
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(-1, sigsuspend(&ignore));
|
|
||||||
EXPECT_NE(-1, kill(pid, SIGINT));
|
|
||||||
EXPECT_NE(-1, waitpid(pid, &status, 0));
|
|
||||||
EXPECT_EQ(1, WIFEXITED(status));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(status));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(status));
|
|
||||||
EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &oldmask, NULL));
|
|
||||||
EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(sigaction, raise) {
|
TEST(sigaction, raise) {
|
||||||
struct sigaction saint = {.sa_handler = OnSigInt};
|
struct sigaction saint = {.sa_handler = OnSigInt};
|
||||||
|
@ -80,6 +54,58 @@ TEST(sigaction, raise) {
|
||||||
EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL));
|
EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// test kill()
|
||||||
|
|
||||||
|
TEST(sigaction, testPingPongParentChildWithSigint) {
|
||||||
|
int pid, status;
|
||||||
|
sigset_t blockint, oldmask;
|
||||||
|
struct sigaction oldint;
|
||||||
|
struct sigaction ignoreint = {.sa_handler = SIG_IGN};
|
||||||
|
struct sigaction catchint = {.sa_handler = OnSigInt};
|
||||||
|
if (IsWindows()) {
|
||||||
|
// this works if it's run by itself on the command prompt. but it
|
||||||
|
// doesn't currently work if it's launched as a subprocess of some
|
||||||
|
// kind of runner. todo(fixme!)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EXPECT_NE(-1, sigemptyset(&blockint));
|
||||||
|
EXPECT_NE(-1, sigaddset(&blockint, SIGINT));
|
||||||
|
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &blockint, &oldmask));
|
||||||
|
EXPECT_NE(-1, sigaction(SIGINT, &catchint, &oldint));
|
||||||
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
|
if (!pid) {
|
||||||
|
// ping
|
||||||
|
EXPECT_NE(-1, kill(getppid(), SIGINT));
|
||||||
|
EXPECT_FALSE(gotsigint);
|
||||||
|
// pong
|
||||||
|
EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0));
|
||||||
|
EXPECT_EQ(-1, sigsuspend(0));
|
||||||
|
EXPECT_EQ(EINTR, errno);
|
||||||
|
EXPECT_TRUE(gotsigint);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
// pong
|
||||||
|
EXPECT_FALSE(gotsigint);
|
||||||
|
EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0));
|
||||||
|
EXPECT_EQ(-1, sigsuspend(0));
|
||||||
|
EXPECT_TRUE(gotsigint);
|
||||||
|
// ping
|
||||||
|
EXPECT_NE(-1, sigaction(SIGINT, &ignoreint, 0));
|
||||||
|
EXPECT_NE(-1, kill(pid, SIGINT));
|
||||||
|
// cleanup
|
||||||
|
EXPECT_NE(-1, wait4(pid, &status, 0, 0));
|
||||||
|
EXPECT_EQ(1, WIFEXITED(status));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(status));
|
||||||
|
EXPECT_EQ(0, WTERMSIG(status));
|
||||||
|
EXPECT_NE(-1, sigaction(SIGINT, &oldint, 0));
|
||||||
|
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &oldmask, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// test int3 crash
|
||||||
|
// we expect this to be recoverable by default
|
||||||
|
|
||||||
volatile int trapeax;
|
volatile int trapeax;
|
||||||
|
|
||||||
void OnTrap(int sig, struct siginfo *si, struct ucontext *ctx) {
|
void OnTrap(int sig, struct siginfo *si, struct ucontext *ctx) {
|
||||||
|
@ -94,6 +120,10 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) {
|
||||||
EXPECT_NE(-1, sigaction(SIGTRAP, &oldsa, NULL));
|
EXPECT_NE(-1, sigaction(SIGTRAP, &oldsa, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// test fpu crash (unrecoverable)
|
||||||
|
// test signal handler can modify cpu registers (now it's recoverable!)
|
||||||
|
|
||||||
void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) {
|
void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) {
|
||||||
struct XedDecodedInst xedd;
|
struct XedDecodedInst xedd;
|
||||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||||
|
|
|
@ -24,13 +24,12 @@
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
testonly void OnCtrlC(int sig) {
|
testonly void OnUsr1(int sig) {
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(signal, test) {
|
TEST(signal, test) {
|
||||||
if (IsWindows()) return; /* omg */
|
ASSERT_NE(SIG_ERR, signal(SIGUSR1, OnUsr1));
|
||||||
ASSERT_NE(SIG_ERR, signal(SIGINT, OnCtrlC));
|
ASSERT_NE(-1, raise(SIGUSR1));
|
||||||
ASSERT_NE(-1, raise(SIGINT));
|
|
||||||
__die();
|
__die();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,12 @@
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
int n;
|
volatile int n;
|
||||||
|
|
||||||
void OnSig(int sig, siginfo_t *si, ucontext_t *ctx) {
|
void OnSig(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||||
++n;
|
++n;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue