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:
Justine Tunney 2022-10-16 12:05:08 -07:00
parent 64c284003d
commit 60cb435cb4
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
124 changed files with 2169 additions and 718 deletions

View file

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

View file

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

View file

@ -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)) {

View file

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

View file

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

View file

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

View file

@ -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)) {

View file

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

View file

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

View file

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

View file

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

View file

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