mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-27 04:50:28 +00:00
Implement pthread_atfork()
If threads are being used, then fork() will now acquire and release and runtime locks so that fork() may be safely used from threads. This also makes vfork() thread safe, because pthread mutexes will do nothing when the process is a child of vfork(). More torture tests have been written to confirm this all works like a charm. Additionally: - Invent hexpcpy() api - Rename nsync_malloc_() to kmalloc() - Complete posix named semaphore implementation - Make pthread_create() asynchronous signal safe - Add rm, rmdir, and touch to command interpreter builtins - Invent sigisprecious() and modify sigset functions to use it - Add unit tests for posix_spawn() attributes and fix its bugs One unresolved problem is the reclaiming of *NSYNC waiter memory in the forked child processes, within apps which have threads waiting on locks
This commit is contained in:
parent
64c284003d
commit
60cb435cb4
124 changed files with 2169 additions and 718 deletions
|
@ -84,7 +84,7 @@ int clock_gettime(int clock, struct timespec *ts) {
|
|||
rc = __clock_gettime(clock, ts);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
||||
DescribeTimespec(rc, ts), rc);
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
|
|||
}
|
||||
|
||||
#if SYSDEBUG
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
||||
DescribeSleepFlags(flags), DescribeTimespec(0, req),
|
||||
DescribeTimespec(rc, rem), DescribeErrnoResult(rc));
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
|
@ -58,21 +59,8 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
!__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
kprintf(STRACE_PROLOGUE "execve(%#s, {", prog);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", argv[i]);
|
||||
}
|
||||
kprintf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", envp[i]);
|
||||
}
|
||||
kprintf("})\n");
|
||||
}
|
||||
#endif
|
||||
STRACE("execve(%#s, %s, %s) → ...", prog, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && _weaken(sys_pledge_linux)) {
|
||||
|
|
|
@ -63,7 +63,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
|||
rc = __gettimeofday(tv, tz, 0).ax;
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("gettimeofday([%s], %p) → %d% m", DescribeTimeval(rc, tv), tz, rc);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -56,7 +56,7 @@ static long double GetTimeSample(void) {
|
|||
static long double MeasureNanosPerCycle(void) {
|
||||
int i, n;
|
||||
long double avg, samp;
|
||||
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||
if (__tls_enabled) __get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||
if (IsWindows()) {
|
||||
n = 10;
|
||||
} else {
|
||||
|
@ -66,7 +66,7 @@ static long double MeasureNanosPerCycle(void) {
|
|||
samp = GetTimeSample();
|
||||
avg += (samp - avg) / i;
|
||||
}
|
||||
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||
if (__tls_enabled) __get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
||||
return avg;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ static long double GetTimeSample(void) {
|
|||
static long double MeasureNanosPerCycle(void) {
|
||||
int i, n;
|
||||
long double avg, samp;
|
||||
__get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||
if (__tls_enabled) __get_tls()->tib_flags |= TIB_FLAG_TIME_CRITICAL;
|
||||
if (IsWindows()) {
|
||||
n = 30;
|
||||
} else {
|
||||
|
@ -63,7 +63,7 @@ static long double MeasureNanosPerCycle(void) {
|
|||
samp = GetTimeSample();
|
||||
avg += (samp - avg) / i;
|
||||
}
|
||||
__get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||
if (__tls_enabled) __get_tls()->tib_flags &= ~TIB_FLAG_TIME_CRITICAL;
|
||||
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
|
||||
return avg;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/stdio/lcg.internal.h"
|
||||
|
||||
/**
|
||||
* Returns handles of windows pids being tracked.
|
||||
|
@ -35,12 +35,8 @@
|
|||
textwindows int __sample_pids(int pids[hasatleast 64],
|
||||
int64_t handles[hasatleast 64],
|
||||
bool exploratory) {
|
||||
static uint64_t rando = 1;
|
||||
static pthread_spinlock_t lock;
|
||||
uint32_t i, j, base, count;
|
||||
if (__threaded) pthread_spin_lock(&lock);
|
||||
base = KnuthLinearCongruentialGenerator(&rando) >> 32;
|
||||
pthread_spin_unlock(&lock);
|
||||
base = _rand64() >> 32;
|
||||
for (count = i = 0; i < g_fds.n; ++i) {
|
||||
j = (base + i) % g_fds.n;
|
||||
if (g_fds.p[j].kind == kFdProcess && (!exploratory || !g_fds.p[j].zombie)) {
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -34,7 +34,7 @@ int setpgid(int pid, int pgid) {
|
|||
rc = sys_setpgid(pid, pgid);
|
||||
} else {
|
||||
me = getpid();
|
||||
if (pid == me && pgid == me) {
|
||||
if ((!pid || pid == me) && (!pgid || pgid == me)) {
|
||||
/*
|
||||
* "When a process is created with CREATE_NEW_PROCESS_GROUP
|
||||
* specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
void(__sig_lock)(void) {
|
||||
|
@ -27,6 +28,11 @@ void(__sig_unlock)(void) {
|
|||
pthread_mutex_unlock(&__sig_lock_obj);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void init(void) {
|
||||
void __sig_funlock(void) {
|
||||
bzero(&__sig_lock_obj, sizeof(__sig_lock_obj));
|
||||
__sig_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void __sig_init(void) {
|
||||
pthread_atfork(__sig_lock, __sig_unlock, __sig_funlock);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
|||
|
||||
void __fds_lock(void);
|
||||
void __fds_unlock(void);
|
||||
void __fds_funlock(void);
|
||||
void __sig_lock(void);
|
||||
void __sig_unlock(void);
|
||||
void __sig_funlock(void);
|
||||
|
||||
#ifdef _NOPL0
|
||||
#define __fds_lock() _NOPL0("__threadcalls", __fds_lock)
|
||||
|
@ -35,6 +37,8 @@ void __sig_unlock(void);
|
|||
#define __sig_unlock() (__threaded ? __sig_unlock() : 0)
|
||||
#endif
|
||||
|
||||
#define __vforked (__tls_enabled && (__get_tls()->tib_flags & TIB_FLAG_VFORKED))
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_ */
|
||||
|
|
|
@ -16,6 +16,7 @@ int sigorset(sigset_t *, const sigset_t *, const sigset_t *) paramsnonnull();
|
|||
int sigisemptyset(const sigset_t *) paramsnonnull() nosideeffect;
|
||||
int sigismember(const sigset_t *, int) paramsnonnull() nosideeffect;
|
||||
int sigcountset(const sigset_t *) paramsnonnull() nosideeffect;
|
||||
int sigisprecious(int) nosideeffect;
|
||||
int sigprocmask(int, const sigset_t *, sigset_t *);
|
||||
int sigsuspend(const sigset_t *);
|
||||
int sigpending(sigset_t *);
|
||||
|
|
|
@ -18,21 +18,46 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/ucontext.internal.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/enum/exceptionhandleractions.h"
|
||||
#include "libc/nt/enum/signal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/ntexceptionpointers.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.h"
|
||||
|
||||
privileged unsigned __wincrash(struct NtExceptionPointers *ep) {
|
||||
int64_t rip;
|
||||
int sig, code;
|
||||
ucontext_t ctx;
|
||||
struct CosmoTib *tib;
|
||||
static bool noreentry;
|
||||
|
||||
if ((tib = __tls_enabled ? __get_tls_privileged() : 0)) {
|
||||
if (~tib->tib_flags & TIB_FLAG_WINCRASHING) {
|
||||
tib->tib_flags |= TIB_FLAG_WINCRASHING;
|
||||
} else {
|
||||
WincrashPanic:
|
||||
STRACE("panic: wincrash reentry: rip %x bt %s", ep->ContextRecord->Rip,
|
||||
DescribeBacktrace((struct StackFrame *)ep->ContextRecord->Rbp));
|
||||
ExitProcess(89);
|
||||
}
|
||||
} else {
|
||||
if (!noreentry) {
|
||||
noreentry = true;
|
||||
} else {
|
||||
goto WincrashPanic;
|
||||
}
|
||||
}
|
||||
|
||||
STRACE("__wincrash");
|
||||
|
||||
switch (ep->ExceptionRecord->ExceptionCode) {
|
||||
|
@ -115,5 +140,10 @@ privileged unsigned __wincrash(struct NtExceptionPointers *ep) {
|
|||
ep->ContextRecord->Rip++;
|
||||
}
|
||||
|
||||
noreentry = false;
|
||||
if (tib) {
|
||||
tib->tib_flags &= ~TIB_FLAG_WINCRASHING;
|
||||
}
|
||||
|
||||
return kNtExceptionContinueExecution;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue