mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-29 05:50:27 +00:00
Make improvements
- We now serialize the file descriptor table when spawning / executing processes on Windows. This means you can now inherit more stuff than just standard i/o. It's needed by bash, which duplicates the console to file descriptor #255. We also now do a better job serializing the environment variables, so you're less likely to encounter E2BIG when using your bash shell. We also no longer coerce environ to uppercase - execve() on Windows now remotely controls its parent process to make them spawn a replacement for itself. Then it'll be able to terminate immediately once the spawn succeeds, without having to linger around for the lifetime as a shell process for proxying the exit code. When process worker thread running in the parent sees the child die, it's given a handle to the new child, to replace it in the process table. - execve() and posix_spawn() on Windows will now provide CreateProcess an explicit handle list. This allows us to remove handle locks which enables better fork/spawn concurrency, with seriously correct thread safety. Other codebases like Go use the same technique. On the other hand fork() still favors the conventional WIN32 inheritence approach which can be a little bit messy, but is *controlled* by guaranteeing perfectly clean slates at both the spawning and execution boundaries - sigset_t is now 64 bits. Having it be 128 bits was a mistake because there's no reason to use that and it's only supported by FreeBSD. By using the system word size, signal mask manipulation on Windows goes very fast. Furthermore @asyncsignalsafe funcs have been rewritten on Windows to take advantage of signal masking, now that it's much more pleasant to use. - All the overlapped i/o code on Windows has been rewritten for pretty good signal and cancelation safety. We're now able to ensure overlap data structures are cleaned up so long as you don't longjmp() out of out of a signal handler that interrupted an i/o operation. Latencies are also improved thanks to the removal of lots of "busy wait" code. Waits should be optimal for everything except poll(), which shall be the last and final demon we slay in the win32 i/o horror show. - getrusage() on Windows is now able to report RUSAGE_CHILDREN as well as RUSAGE_SELF, thanks to aggregation in the process manager thread.
This commit is contained in:
parent
af7cb3c82f
commit
791f79fcb3
382 changed files with 4008 additions and 4511 deletions
|
@ -19,9 +19,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
|
||||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
privileged struct Env __getenv(char **p, const char *k) {
|
||||
char *t;
|
||||
int i, j;
|
||||
|
@ -32,7 +29,7 @@ privileged struct Env __getenv(char **p, const char *k) {
|
|||
if (t[j] == '=') return (struct Env){t + j + 1, i};
|
||||
break;
|
||||
}
|
||||
if (ToUpper(k[j] & 255) != ToUpper(t[j] & 255)) {
|
||||
if (k[j] != t[j]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -28,7 +27,6 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
|||
|
||||
static void bzero128(char *p, size_t n) {
|
||||
xmm_t v = {0};
|
||||
if (IsAsan()) __asan_verify(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
|
@ -46,7 +44,6 @@ static void bzero128(char *p, size_t n) {
|
|||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
_Microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
||||
xmm_t v = {0};
|
||||
if (IsAsan()) __asan_verify(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "libc/thread/tls.h"
|
||||
#ifdef MODE_DBG
|
||||
|
||||
int begin_cancellation_point(void) {
|
||||
int begin_cancelation_point(void) {
|
||||
int state = 0;
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
|
@ -38,7 +38,7 @@ int begin_cancellation_point(void) {
|
|||
return state;
|
||||
}
|
||||
|
||||
void end_cancellation_point(int state) {
|
||||
void end_cancelation_point(int state) {
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__tls_enabled) {
|
||||
|
@ -50,7 +50,7 @@ void end_cancellation_point(int state) {
|
|||
}
|
||||
}
|
||||
|
||||
void report_cancellation_point(void) {
|
||||
void report_cancelation_point(void) {
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
const char *(DescribeErrno)(char buf[20], int ax) {
|
||||
const char *(DescribeErrno)(char buf[30], int ax) {
|
||||
char *p = buf;
|
||||
const char *s;
|
||||
if (ax < 0) {
|
||||
|
|
|
@ -19,7 +19,7 @@ const char *DescribeClockName(char[32], int);
|
|||
const char *DescribeControlKeyState(char[64], uint32_t);
|
||||
const char *DescribeDirfd(char[12], int);
|
||||
const char *DescribeDnotifyFlags(char[80], int);
|
||||
const char *DescribeErrno(char[20], int);
|
||||
const char *DescribeErrno(char[30], int);
|
||||
const char *DescribeFcntlCmd(char[20], int);
|
||||
const char *DescribeFlockType(char[12], int);
|
||||
const char *DescribeFrame(char[32], int);
|
||||
|
@ -78,7 +78,7 @@ const char *DescribeWhichPrio(char[12], int);
|
|||
#define DescribeControlKeyState(x) DescribeControlKeyState(alloca(64), x)
|
||||
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
|
||||
#define DescribeDnotifyFlags(x) DescribeDnotifyFlags(alloca(80), x)
|
||||
#define DescribeErrno(x) DescribeErrno(alloca(20), x)
|
||||
#define DescribeErrno(x) DescribeErrno(alloca(30), x)
|
||||
#define DescribeFcntlCmd(x) DescribeFcntlCmd(alloca(20), x)
|
||||
#define DescribeFlockType(x) DescribeFlockType(alloca(12), x)
|
||||
#define DescribeFrame(x) DescribeFrame(alloca(32), x)
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
|
@ -31,6 +33,7 @@
|
|||
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
|
||||
|
||||
const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
||||
int olderr;
|
||||
bool gotsome;
|
||||
const char *s;
|
||||
int sig, o = 0;
|
||||
|
@ -43,13 +46,14 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
|||
ksnprintf(buf, N, "%p", ss);
|
||||
return buf;
|
||||
}
|
||||
olderr = errno;
|
||||
|
||||
if (sigcountset(ss) > 16) {
|
||||
append("~");
|
||||
sigemptyset(&sigset);
|
||||
for (sig = 1; sig <= _NSIG; ++sig) {
|
||||
if (!sigismember(ss, sig)) {
|
||||
sigset.__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
sigaddset(&sigset, sig);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -74,5 +78,6 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
|
|||
}
|
||||
append("}");
|
||||
|
||||
errno = olderr;
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,14 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
|||
handle = g_fds.p[fd].handle;
|
||||
}
|
||||
|
||||
// mark map handle as inheritable if fork might need it
|
||||
const struct NtSecurityAttributes *mapsec;
|
||||
if ((flags & MAP_TYPE) == MAP_SHARED) {
|
||||
mapsec = &kNtIsInheritable;
|
||||
} else {
|
||||
mapsec = 0;
|
||||
}
|
||||
|
||||
// nt will whine under many circumstances if we change the execute bit
|
||||
// later using mprotect(). the workaround is to always request execute
|
||||
// and then virtualprotect() it away until we actually need it. please
|
||||
|
@ -73,7 +81,7 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
|||
int e = errno;
|
||||
struct DirectMap dm;
|
||||
TryAgain:
|
||||
if ((dm.maphandle = CreateFileMapping(handle, 0, fl.flags1,
|
||||
if ((dm.maphandle = CreateFileMapping(handle, mapsec, fl.flags1,
|
||||
(size + off) >> 32, (size + off), 0))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
|
||||
size, addr))) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -32,16 +33,14 @@
|
|||
|
||||
#define G FRAMESIZE
|
||||
|
||||
static void *_mapframe(void *p, int f) {
|
||||
static void *_mapframe_impl(void *p, int f) {
|
||||
int rc, prot, flags;
|
||||
struct DirectMap dm;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
flags = f | MAP_ANONYMOUS | MAP_FIXED;
|
||||
if ((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr == p) {
|
||||
__mmi_lock();
|
||||
rc = __track_memory(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
|
||||
dm.maphandle, prot, flags, false, false, 0, G);
|
||||
__mmi_unlock();
|
||||
if (!rc) {
|
||||
return p;
|
||||
} else {
|
||||
|
@ -54,6 +53,17 @@ static void *_mapframe(void *p, int f) {
|
|||
}
|
||||
}
|
||||
|
||||
static void *_mapframe(void *p, int f) {
|
||||
void *res;
|
||||
// mmap isn't required to be @asyncsignalsafe but this is
|
||||
BLOCK_SIGNALS;
|
||||
__mmi_lock();
|
||||
res = _mapframe_impl(p, f);
|
||||
__mmi_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends static allocation.
|
||||
*
|
||||
|
@ -72,6 +82,7 @@ static void *_mapframe(void *p, int f) {
|
|||
* @param f should be `MAP_PRIVATE` or `MAP_SHARED`
|
||||
* @return new value for `e` or null w/ errno
|
||||
* @raise ENOMEM if we require more vespene gas
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
|
||||
char *q;
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
pthread_mutex_t __fds_lock_obj;
|
||||
pthread_mutex_t __fds_lock_obj = {._type = PTHREAD_MUTEX_RECURSIVE};
|
||||
|
|
|
@ -30,14 +30,12 @@ __msabi extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers;
|
|||
* file is opened in a direct non-caching mode. One main advantage here
|
||||
* seems to be coherency.
|
||||
*
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
* @note consider buying a ups
|
||||
* @see FlushViewOfFile()
|
||||
*/
|
||||
textwindows bool32 FlushFileBuffers(int64_t hFile) {
|
||||
bool32 ok;
|
||||
ok = __imp_FlushFileBuffers(hFile);
|
||||
if (!ok) __winerr();
|
||||
NTTRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok);
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/extend.internal.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/pushpop.internal.h"
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
@ -50,28 +51,34 @@ __static_yoink("_init_g_fds");
|
|||
struct Fds g_fds;
|
||||
static struct Fd g_fds_static[OPEN_MAX];
|
||||
|
||||
static int Atoi(const char *str) {
|
||||
int i;
|
||||
for (i = 0; '0' <= *str && *str <= '9'; ++str) {
|
||||
i *= 10;
|
||||
i += *str - '0';
|
||||
static bool TokAtoi(const char **str, long *res) {
|
||||
int c, d;
|
||||
unsigned long x = 0;
|
||||
d = **str == '-' ? -1 : 1;
|
||||
while ((c = *(*str)++)) {
|
||||
if (('0' <= c && c <= '9')) {
|
||||
x *= 10;
|
||||
x += (c - '0') * d;
|
||||
} else {
|
||||
*res = x;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
return false;
|
||||
}
|
||||
|
||||
static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x,
|
||||
int sockset) {
|
||||
static textwindows void SetupWinStd(struct Fds *fds, int i, uint32_t x) {
|
||||
int64_t h;
|
||||
uint32_t cm;
|
||||
h = GetStdHandle(x);
|
||||
if (!h || h == -1) return;
|
||||
fds->p[i].kind = ((1 << i) & sockset) ? pushpop(kFdSocket) : pushpop(kFdFile);
|
||||
fds->p[i].kind = GetConsoleMode(h, &cm) ? kFdConsole : kFdFile;
|
||||
fds->p[i].handle = h;
|
||||
atomic_store_explicit(&fds->f, i + 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
textstartup void __init_fds(int argc, char **argv, char **envp) {
|
||||
struct Fds *fds;
|
||||
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
|
||||
fds = __veil("r", &g_fds);
|
||||
fds->n = 4;
|
||||
atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
|
||||
|
@ -84,6 +91,8 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
|
|||
fds->p = g_fds_static;
|
||||
fds->e = g_fds_static + OPEN_MAX;
|
||||
}
|
||||
|
||||
// inherit standard i/o file descriptors
|
||||
if (IsMetal()) {
|
||||
extern const char vga_console[];
|
||||
fds->f = 3;
|
||||
|
@ -100,30 +109,48 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
|
|||
fds->p[1].handle = __veil("r", 0x3F8ull);
|
||||
fds->p[2].handle = __veil("r", 0x3F8ull);
|
||||
} else if (IsWindows()) {
|
||||
int sockset = 0;
|
||||
struct Env var;
|
||||
var = __getenv(envp, "__STDIO_SOCKETS");
|
||||
if (var.s) {
|
||||
int i = var.i + 1;
|
||||
do {
|
||||
envp[i - 1] = envp[i];
|
||||
} while (envp[i]);
|
||||
sockset = Atoi(var.s);
|
||||
for (long i = 0; i < 3; ++i) {
|
||||
SetupWinStd(fds, i, kNtStdio[i]);
|
||||
}
|
||||
if (sockset && !_weaken(socket)) {
|
||||
#ifdef SYSDEBUG
|
||||
kprintf("%s: parent process passed sockets as stdio, but this program"
|
||||
" can't use them since it didn't link the socket() function\n",
|
||||
argv[0]);
|
||||
_Exit(1);
|
||||
#else
|
||||
sockset = 0; // let ReadFile() fail
|
||||
#endif
|
||||
}
|
||||
SetupWinStd(fds, 0, kNtStdInputHandle, sockset);
|
||||
SetupWinStd(fds, 1, kNtStdOutputHandle, sockset);
|
||||
SetupWinStd(fds, 2, kNtStdErrorHandle, sockset);
|
||||
}
|
||||
fds->p[0].flags = O_RDONLY;
|
||||
fds->p[1].flags = O_WRONLY | O_APPEND;
|
||||
fds->p[2].flags = O_WRONLY | O_APPEND;
|
||||
|
||||
// inherit file descriptors from cosmo parent process
|
||||
if (IsWindows()) {
|
||||
const char *fdspec;
|
||||
if ((fdspec = getenv("_COSMO_FDS"))) {
|
||||
unsetenv("_COSMO_FDS");
|
||||
for (;;) {
|
||||
long fd, kind, flags, mode, handle, pointer, type, family, protocol;
|
||||
if (!TokAtoi(&fdspec, &fd)) break;
|
||||
if (!TokAtoi(&fdspec, &handle)) break;
|
||||
if (!TokAtoi(&fdspec, &kind)) break;
|
||||
if (!TokAtoi(&fdspec, &flags)) break;
|
||||
if (!TokAtoi(&fdspec, &mode)) break;
|
||||
if (!TokAtoi(&fdspec, &pointer)) break;
|
||||
if (!TokAtoi(&fdspec, &type)) break;
|
||||
if (!TokAtoi(&fdspec, &family)) break;
|
||||
if (!TokAtoi(&fdspec, &protocol)) break;
|
||||
__ensurefds_unlocked(fd);
|
||||
struct Fd *f = fds->p + fd;
|
||||
if (f->handle && f->handle != -1 && f->handle != handle) {
|
||||
CloseHandle(f->handle);
|
||||
if (fd < 3) {
|
||||
SetStdHandle(kNtStdio[fd], handle);
|
||||
}
|
||||
}
|
||||
f->handle = handle;
|
||||
f->kind = kind;
|
||||
f->flags = flags;
|
||||
f->mode = mode;
|
||||
f->pointer = pointer;
|
||||
f->type = type;
|
||||
f->family = family;
|
||||
f->protocol = protocol;
|
||||
atomic_store_explicit(&fds->f, fd + 1, memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ privileged long __get_safe_size(long want, long extraspace) {
|
|||
(char *)sp <= tib->tib_sigstack_addr + tib->tib_sigstack_size) {
|
||||
bottom = (long)tib->tib_sigstack_addr;
|
||||
} else if ((pt = (struct PosixThread *)tib->tib_pthread) &&
|
||||
pt->attr.__stacksize) {
|
||||
bottom = (long)pt->attr.__stackaddr + pt->attr.__guardsize;
|
||||
pt->pt_attr.__stacksize) {
|
||||
bottom = (long)pt->pt_attr.__stackaddr + pt->pt_attr.__guardsize;
|
||||
} else {
|
||||
return want;
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_HANDLOCK_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_HANDLOCK_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void __hand_wipe(void);
|
||||
void __hand_rlock(void);
|
||||
void __hand_runlock(void);
|
||||
void __hand_lock(void);
|
||||
void __hand_unlock(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_HANDLOCK_INTERNAL_H_ */
|
|
@ -52,7 +52,7 @@ int IsDebuggerPresent(bool force) {
|
|||
if (!PLEDGED(RPATH)) return false;
|
||||
res = 0;
|
||||
e = errno;
|
||||
BLOCK_CANCELLATIONS;
|
||||
BLOCK_CANCELATION;
|
||||
if ((fd = __sys_openat(AT_FDCWD, "/proc/self/status", O_RDONLY, 0)) >= 0) {
|
||||
if ((got = sys_read(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||
buf[got] = '\0';
|
||||
|
@ -63,7 +63,7 @@ int IsDebuggerPresent(bool force) {
|
|||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
ALLOW_CANCELATION;
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -16,47 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
||||
/**
|
||||
* @fileoverview r/w lock for maanging windows file inheritence
|
||||
*/
|
||||
|
||||
static nsync_mu __hand_mu;
|
||||
|
||||
void __hand_wipe(void) {
|
||||
if (!SupportsWindows()) return;
|
||||
bzero(&__hand_mu, sizeof(__hand_mu));
|
||||
}
|
||||
|
||||
void __hand_rlock(void) {
|
||||
if (!IsWindows()) return;
|
||||
if (_weaken(nsync_mu_rlock) && __threaded) {
|
||||
_weaken(nsync_mu_rlock)(&__hand_mu);
|
||||
}
|
||||
}
|
||||
|
||||
void __hand_runlock(void) {
|
||||
if (!IsWindows()) return;
|
||||
if (_weaken(nsync_mu_runlock) && __threaded) {
|
||||
_weaken(nsync_mu_runlock)(&__hand_mu);
|
||||
}
|
||||
}
|
||||
|
||||
void __hand_lock(void) {
|
||||
if (!IsWindows()) return;
|
||||
if (_weaken(nsync_mu_lock) && __threaded) {
|
||||
_weaken(nsync_mu_lock)(&__hand_mu);
|
||||
}
|
||||
}
|
||||
|
||||
void __hand_unlock(void) {
|
||||
if (!IsWindows()) return;
|
||||
if (_weaken(nsync_mu_unlock) && __threaded) {
|
||||
_weaken(nsync_mu_unlock)(&__hand_mu);
|
||||
}
|
||||
}
|
||||
const signed char kNtStdio[3] = {
|
||||
(signed char)kNtStdInputHandle,
|
||||
(signed char)kNtStdOutputHandle,
|
||||
(signed char)kNtStdErrorHandle,
|
||||
};
|
|
@ -399,8 +399,10 @@ privileged void klog(const char *b, size_t n) {
|
|||
}
|
||||
if (IsWindows()) {
|
||||
e = __imp_GetLastError();
|
||||
__imp_WriteFile(h, b, n, &wrote, 0);
|
||||
__imp_SetLastError(e);
|
||||
if (!__imp_WriteFile(h, b, n, &wrote, 0)) {
|
||||
__imp_SetLastError(e);
|
||||
__klog_handle = 0;
|
||||
}
|
||||
} else if (IsMetal()) {
|
||||
if (_weaken(_klog_vga)) {
|
||||
_weaken(_klog_vga)(b, n);
|
||||
|
@ -424,7 +426,7 @@ privileged void klog(const char *b, size_t n) {
|
|||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
// this isn't a cancellation point because we don't acknowledge eintr
|
||||
// this isn't a cancelation point because we don't acknowledge eintr
|
||||
// on xnu we use the "nocancel" version of the system call for safety
|
||||
register long r0 asm("x0") = kloghandle();
|
||||
register long r1 asm("x1") = (long)b;
|
||||
|
@ -586,7 +588,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
|
|||
*p++ = '1';
|
||||
*p++ = ';';
|
||||
*p++ = '3';
|
||||
*p++ = '0' + x % 8;
|
||||
*p++ = '0' + x % 7;
|
||||
*p++ = 'm';
|
||||
ansi = 1;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
@ -70,7 +69,6 @@ static inline const unsigned char *memchr_sse(const unsigned char *s,
|
|||
void *memchr(const void *s, int c, size_t n) {
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
const void *r;
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
const unsigned char *p = (const unsigned char *)s;
|
||||
while (n && ((intptr_t)p & 15)) {
|
||||
if (*p == (unsigned char)c) {
|
||||
|
|
|
@ -226,8 +226,6 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
*(xmm_t *)(d + n + 16) = w;
|
||||
} while (n >= 32);
|
||||
} else {
|
||||
if (IsAsan()) __asan_verify(d, n);
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
asm("std\n\t"
|
||||
"rep movsb\n\t"
|
||||
"cld"
|
||||
|
@ -248,8 +246,6 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
s += i;
|
||||
n -= i;
|
||||
} else {
|
||||
if (IsAsan()) __asan_verify(d, n);
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
asm("rep movsb"
|
||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
||||
: "m"(*(char(*)[n])s));
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -71,7 +70,6 @@ static inline const unsigned char *memrchr_sse(const unsigned char *s,
|
|||
void *memrchr(const void *s, int c, size_t n) {
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
const void *r;
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
r = memrchr_sse(s, c, n);
|
||||
return (void *)r;
|
||||
#else
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -29,7 +28,6 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
|||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
static void *memset_sse(char *p, char c, size_t n) {
|
||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
if (IsAsan()) __asan_verify(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
|
@ -50,7 +48,6 @@ static void *memset_sse(char *p, char c, size_t n) {
|
|||
_Microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) {
|
||||
char *t;
|
||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
if (IsAsan()) __asan_verify(p, n);
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
|
|
|
@ -25,4 +25,4 @@ __static_yoink("_init__mmi");
|
|||
#endif
|
||||
|
||||
struct MemoryIntervals _mmi;
|
||||
pthread_mutex_t __mmi_lock_obj; // recursive :'(
|
||||
pthread_mutex_t __mmi_lock_obj = {._type = PTHREAD_MUTEX_RECURSIVE};
|
||||
|
|
|
@ -22,5 +22,4 @@
|
|||
.init.start 200,_init__mmi
|
||||
movb $16,_mmi+8
|
||||
movl $_mmi+24,_mmi+16
|
||||
movb $PTHREAD_MUTEX_RECURSIVE,__mmi_lock_obj+4(%rip)
|
||||
.init.end 200,_init__mmi
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
void(pthread_cleanup_pop)(struct _pthread_cleanup_buffer *cb, int execute) {
|
||||
struct PosixThread *pt;
|
||||
if (__tls_enabled && (pt = _pthread_self())) {
|
||||
unassert(cb == pt->cleanup);
|
||||
pt->cleanup = cb->__prev;
|
||||
unassert(cb == pt->pt_cleanup);
|
||||
pt->pt_cleanup = cb->__prev;
|
||||
}
|
||||
if (execute) {
|
||||
cb->__routine(cb->__arg);
|
||||
|
|
|
@ -26,7 +26,7 @@ void(pthread_cleanup_push)(struct _pthread_cleanup_buffer *cb,
|
|||
cb->__routine = routine;
|
||||
cb->__arg = arg;
|
||||
if (__tls_enabled && (pt = _pthread_self())) {
|
||||
cb->__prev = pt->cleanup;
|
||||
pt->cleanup = cb;
|
||||
cb->__prev = pt->pt_cleanup;
|
||||
pt->pt_cleanup = cb;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,15 +27,15 @@
|
|||
/**
|
||||
* Sets cancelability state.
|
||||
*
|
||||
* This function may be used to temporarily disable cancellation for the
|
||||
* calling thread, which is necessary in cases when a @cancellationpoint
|
||||
* This function may be used to temporarily disable cancelation for the
|
||||
* calling thread, which is necessary in cases when a @cancelationpoint
|
||||
* function is invoked from an @asyncsignalsafe function.
|
||||
*
|
||||
* Cosmopolitan Libc supports the Musl Libc `PTHREAD_CANCEL_MASKED`
|
||||
* non-POSIX extension. Any thread may use this setting, in which case
|
||||
* the thread won't be abruptly destroyed upon a cancellation and have
|
||||
* the thread won't be abruptly destroyed upon a cancelation and have
|
||||
* its stack unwound; instead, the thread will encounter an `ECANCELED`
|
||||
* errno the next time it calls a cancellation point.
|
||||
* errno the next time it calls a cancelation point.
|
||||
*
|
||||
* @param state may be one of:
|
||||
* - `PTHREAD_CANCEL_ENABLE` (default)
|
||||
|
@ -89,12 +89,12 @@ errno_t pthread_setcancelstate(int state, int *oldstate) {
|
|||
return err;
|
||||
}
|
||||
|
||||
int _pthread_block_cancellations(void) {
|
||||
int _pthread_block_cancelation(void) {
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
return oldstate;
|
||||
}
|
||||
|
||||
void _pthread_allow_cancellations(int oldstate) {
|
||||
void _pthread_allow_cancelation(int oldstate) {
|
||||
pthread_setcancelstate(oldstate, 0);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,13 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
pthread_spinlock_t _pthread_lock;
|
||||
pthread_spinlock_t _pthread_lock_obj;
|
||||
|
||||
void _pthread_lock(void) {
|
||||
pthread_spin_lock(&_pthread_lock_obj);
|
||||
}
|
||||
|
||||
void _pthread_unlock(void) {
|
||||
pthread_spin_unlock(&_pthread_lock_obj);
|
||||
}
|
||||
|
|
96
libc/intrin/reservefd.c
Normal file
96
libc/intrin/reservefd.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/extend.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
|
||||
static volatile size_t mapsize;
|
||||
|
||||
/**
|
||||
* Grows file descriptor array memory if needed.
|
||||
*
|
||||
* @see libc/runtime/memtrack64.txt
|
||||
* @see libc/runtime/memtrack32.txt
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __ensurefds_unlocked(int fd) {
|
||||
size_t n;
|
||||
if (fd < g_fds.n) return fd;
|
||||
n = fd + 1;
|
||||
g_fds.e = _extend(g_fds.p, n * sizeof(*g_fds.p), g_fds.e, MAP_PRIVATE,
|
||||
kMemtrackFdsStart + kMemtrackFdsSize);
|
||||
g_fds.n = n;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows file descriptor array memory if needed.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __ensurefds(int fd) {
|
||||
__fds_lock();
|
||||
fd = __ensurefds_unlocked(fd);
|
||||
__fds_unlock();
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds open file descriptor slot.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __reservefd_unlocked(int start) {
|
||||
int fd, f1, f2;
|
||||
for (;;) {
|
||||
f1 = atomic_load_explicit(&g_fds.f, memory_order_acquire);
|
||||
for (fd = MAX(start, f1); fd < g_fds.n; ++fd) {
|
||||
if (!g_fds.p[fd].kind) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fd = __ensurefds_unlocked(fd);
|
||||
bzero(g_fds.p + fd, sizeof(*g_fds.p));
|
||||
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
|
||||
// g_fds.f isn't guarded by our mutex
|
||||
do {
|
||||
f2 = MAX(fd + 1, f1);
|
||||
} while (!atomic_compare_exchange_weak_explicit(
|
||||
&g_fds.f, &f1, f2, memory_order_release, memory_order_relaxed));
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds open file descriptor slot.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __reservefd(int start) {
|
||||
int fd;
|
||||
__fds_lock();
|
||||
fd = __reservefd_unlocked(start);
|
||||
__fds_unlock();
|
||||
return fd;
|
||||
}
|
|
@ -23,7 +23,6 @@
|
|||
// Relinquishes scheduled quantum.
|
||||
//
|
||||
// @return 0 on success, or -1 w/ errno
|
||||
// @norestart
|
||||
.ftrace1
|
||||
sched_yield:
|
||||
.ftrace2
|
||||
|
@ -63,6 +62,7 @@ sched_yield:
|
|||
// be polyfilled using select() with a zero timeout, which
|
||||
// means to wait zero microseconds and then returns a zero
|
||||
// and this hopefully will give other threads a chance too
|
||||
// XNU has a special version we use called select_nocancel
|
||||
//
|
||||
// "If the readfds, writefds, and errorfds arguments are
|
||||
// all null pointers and the timeout argument is not a
|
||||
|
|
|
@ -16,6 +16,48 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
struct Signals __sig;
|
||||
|
||||
sigset_t __sig_block(void) {
|
||||
if (IsWindows()) {
|
||||
return atomic_exchange_explicit(&__get_tls()->tib_sigmask, -1,
|
||||
memory_order_acq_rel);
|
||||
} else {
|
||||
sigset_t res, neu = -1;
|
||||
sys_sigprocmask(SIG_SETMASK, &neu, &res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
void __sig_unblock(sigset_t m) {
|
||||
if (IsWindows()) {
|
||||
atomic_store_explicit(&__get_tls()->tib_sigmask, m, memory_order_release);
|
||||
if (_weaken(__sig_check)) {
|
||||
_weaken(__sig_check)();
|
||||
}
|
||||
} else {
|
||||
sys_sigprocmask(SIG_SETMASK, &m, 0);
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int __sig_enqueue(int sig) {
|
||||
__get_tls()->tib_sigpending |= 1ull << (sig - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
textwindows sigset_t __sig_beginwait(sigset_t waitmask) {
|
||||
return atomic_exchange_explicit(&__get_tls()->tib_sigmask, waitmask,
|
||||
memory_order_acq_rel);
|
||||
}
|
||||
|
||||
textwindows void __sig_finishwait(sigset_t m) {
|
||||
atomic_store_explicit(&__get_tls()->tib_sigmask, m, memory_order_release);
|
||||
}
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -30,11 +29,9 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigaddset(sigset_t *set, int sig) {
|
||||
_Static_assert(NSIG == sizeof(set->__bits) * CHAR_BIT, "");
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
|
||||
*set |= 1ull << (sig - 1);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Bitwise ANDs two signal sets.
|
||||
|
@ -28,9 +26,6 @@
|
|||
* @vforksafe
|
||||
*/
|
||||
int sigandset(sigset_t *set, const sigset_t *x, const sigset_t *y) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(set->__bits); ++i) {
|
||||
set->__bits[i] = x->__bits[i] & y->__bits[i];
|
||||
}
|
||||
*set = *x & *y;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/sysparam.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
|
||||
/**
|
||||
|
@ -28,22 +29,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigcountset(const sigset_t *set) {
|
||||
int x, y;
|
||||
switch (_NSIG) {
|
||||
case 32:
|
||||
x = (uint32_t)set->__bits[0];
|
||||
y = 0;
|
||||
break;
|
||||
case 64:
|
||||
x = set->__bits[0];
|
||||
y = 0;
|
||||
break;
|
||||
case 128:
|
||||
x = set->__bits[0];
|
||||
y = set->__bits[1];
|
||||
break;
|
||||
default:
|
||||
notpossible;
|
||||
}
|
||||
return popcnt(x) + popcnt(y);
|
||||
uint64_t x = *set;
|
||||
if (IsOpenbsd() || IsXnu()) x &= 0xffffffff;
|
||||
return popcnt(x);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -28,10 +28,8 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigdelset(sigset_t *set, int sig) {
|
||||
_Static_assert(NSIG == sizeof(set->__bits) * CHAR_BIT, "");
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
set->__bits[(sig - 1) >> 6] &= ~(1ull << ((sig - 1) & 63));
|
||||
*set &= ~(1ull << (sig - 1));
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Removes all signals from set.
|
||||
|
@ -26,6 +25,6 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigemptyset(sigset_t *set) {
|
||||
bzero(set->__bits, sizeof(set->__bits));
|
||||
*set = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,30 +17,23 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
* Adds all signals to set.
|
||||
* Fills up signal set.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int sigfillset(sigset_t *set) {
|
||||
memset(set->__bits, -1, sizeof(set->__bits));
|
||||
#define M(x) set->__bits[(x - 1) >> 6] &= ~(1ull << ((x - 1) & 63));
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
switch (_NSIG) {
|
||||
case 32:
|
||||
set->__bits[0] &= 0xffffffff;
|
||||
break;
|
||||
case 64:
|
||||
set->__bits[1] = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*set = -1;
|
||||
*set &= ~(1ull << (SIGTHR - 1)); // only libc should mask
|
||||
*set &= ~(1ull << (SIGABRT - 1)); // it's annoying to mask
|
||||
*set &= ~(1ull << (SIGKILL - 1)); // it's impossible to mask
|
||||
*set &= ~(1ull << (SIGSTOP - 1)); // it's impossible to mask
|
||||
if (IsOpenbsd()) *set &= 0xffffffff; // it doesn't really exist
|
||||
if (IsXnu()) *set &= 0xffffffff; // it doesn't really exist
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
unsigned __sighandrvas[NSIG + 1];
|
||||
unsigned __sighandflags[NSIG + 1];
|
||||
sigset_t __sighandmask[NSIG + 1];
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Determines if signal set is empty.
|
||||
|
@ -28,11 +26,5 @@
|
|||
* @vforksafe
|
||||
*/
|
||||
int sigisemptyset(const sigset_t *set) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(set->__bits); ++i) {
|
||||
if (set->__bits[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return *set == 0;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -30,10 +30,9 @@
|
|||
* @vforksafe
|
||||
*/
|
||||
int sigismember(const sigset_t *set, int sig) {
|
||||
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
if (1 <= sig && sig <= _NSIG) {
|
||||
return !!(set->__bits[(sig - 1) >> 6] & (1ull << ((sig - 1) & 63)));
|
||||
return !!(*set & (1ull << (sig - 1)));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
M(SIGKILL)
|
||||
M(SIGABRT)
|
||||
M(SIGSTOP)
|
||||
M(SIGTHR)
|
|
@ -17,8 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Bitwise ORs two signal sets.
|
||||
|
@ -28,9 +26,6 @@
|
|||
* @vforksafe
|
||||
*/
|
||||
int sigorset(sigset_t *set, const sigset_t *x, const sigset_t *y) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(set->__bits); ++i) {
|
||||
set->__bits[i] = x->__bits[i] | y->__bits[i];
|
||||
}
|
||||
*set = *x | *y;
|
||||
return 0;
|
||||
}
|
||||
|
|
65
libc/intrin/sigprocmask-nt.c
Normal file
65
libc/intrin/sigprocmask-nt.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
||||
|
||||
// validate api usage
|
||||
if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
// get address of sigset to modify
|
||||
_Atomic(uint64_t) *mask = &__get_tls()->tib_sigmask;
|
||||
|
||||
// handle read-only case
|
||||
sigset_t oldmask;
|
||||
if (neu) {
|
||||
if (how == SIG_BLOCK) {
|
||||
oldmask = atomic_fetch_or_explicit(mask, *neu, memory_order_acq_rel);
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
oldmask = atomic_fetch_and_explicit(mask, *neu, memory_order_acq_rel);
|
||||
} else { // SIG_SETMASK
|
||||
oldmask = atomic_exchange_explicit(mask, *neu, memory_order_acq_rel);
|
||||
}
|
||||
} else {
|
||||
oldmask = atomic_load_explicit(mask, memory_order_acquire);
|
||||
}
|
||||
|
||||
// return old signal mask to caller
|
||||
if (old) {
|
||||
*old = oldmask;
|
||||
}
|
||||
|
||||
if (_weaken(__sig_check)) {
|
||||
_weaken(__sig_check)();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
39
libc/intrin/sigprocmask-sysv.c
Normal file
39
libc/intrin/sigprocmask-sysv.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int sys_sigprocmask(int how, const sigset_t *opt_set,
|
||||
sigset_t *opt_out_oldset) {
|
||||
int rc;
|
||||
uint64_t old[2] = {0};
|
||||
if (!IsOpenbsd()) {
|
||||
rc = __sys_sigprocmask(how, opt_set ? (uint64_t[2]){*opt_set} : 0, old, 8);
|
||||
} else {
|
||||
old[0] = (uint32_t)(uintptr_t)__sys_sigprocmask(
|
||||
how, opt_set ? (sigset_t *)(intptr_t)(uint32_t)*opt_set : 0, 0, 0);
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != -1 && opt_out_oldset) {
|
||||
*opt_out_oldset = old[0];
|
||||
}
|
||||
return rc;
|
||||
}
|
70
libc/intrin/sigprocmask.c
Normal file
70
libc/intrin/sigprocmask.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes signal blocking state of calling thread, e.g.:
|
||||
*
|
||||
* sigset_t neu,old;
|
||||
* sigfillset(&neu);
|
||||
* sigprocmask(SIG_BLOCK, &neu, &old);
|
||||
* sigprocmask(SIG_SETMASK, &old, NULL);
|
||||
*
|
||||
* @param how can be SIG_BLOCK (U), SIG_UNBLOCK (/), SIG_SETMASK (=)
|
||||
* @param set is the new mask content (optional)
|
||||
* @param oldset will receive the old mask (optional) and can't overlap
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EFAULT if `set` or `oldset` is bad memory
|
||||
* @raise EINVAL if `how` is invalid
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
*/
|
||||
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
|
||||
int rc;
|
||||
sigset_t old = {0};
|
||||
if (IsAsan() &&
|
||||
((opt_set && !__asan_is_valid(opt_set, sizeof(*opt_set))) ||
|
||||
(opt_out_oldset &&
|
||||
!__asan_is_valid(opt_out_oldset, sizeof(*opt_out_oldset))))) {
|
||||
rc = efault();
|
||||
} else if (IsMetal() || IsWindows()) {
|
||||
rc = __sig_mask(how, opt_set, &old);
|
||||
} else {
|
||||
rc = sys_sigprocmask(how, opt_set, opt_out_oldset ? &old : 0);
|
||||
}
|
||||
if (rc != -1 && opt_out_oldset) {
|
||||
*opt_out_oldset = old;
|
||||
}
|
||||
STRACE("sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(how),
|
||||
DescribeSigset(0, opt_set), DescribeSigset(rc, opt_out_oldset), rc);
|
||||
return rc;
|
||||
}
|
|
@ -35,9 +35,6 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
|||
*/
|
||||
char *stpcpy(char *d, const char *s) {
|
||||
size_t i = 0;
|
||||
if (IsAsan()) {
|
||||
__asan_verify(d, strlen(s) + 1);
|
||||
}
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
for (; (uintptr_t)(s + i) & 15; ++i) {
|
||||
if (!(d[i] = s[i])) {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
@ -96,7 +95,6 @@ static inline const char *strchr_x64(const char *p, uint64_t c) {
|
|||
* @vforksafe
|
||||
*/
|
||||
char *strchr(const char *s, int c) {
|
||||
if (IsAsan()) __asan_verify_str(s);
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
const char *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
@ -94,7 +93,6 @@ static const char *strchrnul_x64(const char *p, uint64_t c) {
|
|||
* NUL terminator if c is not found
|
||||
*/
|
||||
char *strchrnul(const char *s, int c) {
|
||||
if (IsAsan()) __asan_verify_str(s);
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
const char *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
||||
|
@ -34,8 +33,6 @@ int strcmp(const char *a, const char *b) {
|
|||
size_t i = 0;
|
||||
uint64_t v, w;
|
||||
if (a == b) return 0;
|
||||
if (IsAsan()) __asan_verify_str(a);
|
||||
if (IsAsan()) __asan_verify_str(b);
|
||||
if ((c = (*a & 255) - (*b & 255))) return c;
|
||||
if (!IsTiny() && ((uintptr_t)a & 7) == ((uintptr_t)b & 7)) {
|
||||
for (; (uintptr_t)(a + i) & 7; ++i) {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
||||
|
@ -35,10 +34,6 @@ typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
|||
*/
|
||||
char *strcpy(char *d, const char *s) {
|
||||
size_t i = 0;
|
||||
if (IsAsan()) {
|
||||
__asan_verify_str(s);
|
||||
__asan_verify(d, strlen(s) + 1);
|
||||
}
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
for (; (uintptr_t)(s + i) & 15; ++i) {
|
||||
if (!(d[i] = s[i])) {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
||||
|
@ -29,7 +28,6 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
size_t strlen(const char *s) {
|
||||
if (IsAsan()) __asan_verify_str(s);
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
xmm_t z = {0};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
@ -45,7 +44,6 @@ static size_t strnlen_x64(const char *s, size_t n, size_t i) {
|
|||
*/
|
||||
size_t strnlen(const char *s, size_t n) {
|
||||
size_t i;
|
||||
if (IsAsan() && n) __asan_verify(s, 1);
|
||||
for (i = 0; (uintptr_t)(s + i) & 7; ++i) {
|
||||
if (i == n || !s[i]) return i;
|
||||
}
|
||||
|
@ -54,7 +52,6 @@ size_t strnlen(const char *s, size_t n) {
|
|||
if (i == n || !s[i]) break;
|
||||
}
|
||||
unassert(i == n || (i < n && !s[i]));
|
||||
if (IsAsan()) __asan_verify(s, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,12 +26,10 @@ __msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
|
|||
|
||||
/**
|
||||
* Terminates the specified process and all of its threads.
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
*/
|
||||
textwindows bool32 TerminateProcess(int64_t hProcess, uint32_t uWaitStatus) {
|
||||
bool32 ok;
|
||||
ok = __imp_TerminateProcess(hProcess, uWaitStatus);
|
||||
if (!ok) __winerr();
|
||||
NTTRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uWaitStatus, ok);
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
|
||||
|
@ -33,6 +34,8 @@ textwindows dontinstrument void __bootstrap_tls(struct CosmoTib *tib,
|
|||
tib->tib_self = tib;
|
||||
tib->tib_self2 = tib;
|
||||
tib->tib_sigmask = -1;
|
||||
tib->tib_strace = __strace;
|
||||
tib->tib_ftrace = __ftrace;
|
||||
tib->tib_sigstack_size = 57344;
|
||||
tib->tib_sigstack_addr = bp - 57344;
|
||||
tib->tib_tid = __imp_GetCurrentThreadId();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue