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

@ -28,3 +28,11 @@ void(__cxa_lock)(void) {
void(__cxa_unlock)(void) {
pthread_mutex_unlock(&__cxa_lock_obj);
}
void(__cxa_funlock)(void) {
pthread_mutex_init(&__cxa_lock_obj, 0);
}
__attribute__((__constructor__)) static void __cxa_init(void) {
pthread_atfork(__cxa_lock, __cxa_unlock, __cxa_funlock);
}

View file

@ -0,0 +1,40 @@
/*-*- 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/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/nexgen32e/stackframe.h"
#define N 64
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
const char *(DescribeBacktrace)(char buf[N], struct StackFrame *fr) {
int o = 0;
bool gotsome = false;
while (fr) {
if (gotsome) {
append(" ");
} else {
gotsome = true;
}
append("%x", fr->addr);
fr = fr->next;
}
return buf;
}

View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_INTERNAL_H_
#define COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_INTERNAL_H_
#include "libc/mem/alloca.h"
#include "libc/nexgen32e/stackframe.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
const char *DescribeBacktrace(char[64], struct StackFrame *);
#define DescribeBacktrace(x) DescribeBacktrace(alloca(64), x)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBEBACKTRACE_INTERNAL_H_ */

View file

@ -62,6 +62,7 @@ const char *DescribeSocketFamily(char[12], int);
const char *DescribeSocketProtocol(char[12], int);
const char *DescribeSocketType(char[64], int);
const char *DescribeStdioState(char[12], int);
const char *DescribeStringList(char[300], char *const[]);
const char *DescribeWhence(char[12], int);
const char *DescribeWhichPrio(char[12], int);
@ -69,6 +70,7 @@ const char *DescribeWhichPrio(char[12], int);
#define DescribeCapability(x) DescribeCapability(alloca(20), x)
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
#define DescribeDnotifyFlags(x) DescribeDnotifyFlags(alloca(80), x)
#define DescribeErrno(x) DescribeErrno(alloca(12), x)
#define DescribeErrnoResult(x) DescribeErrnoResult(alloca(12), x)
#define DescribeFcntlCmd(x) DescribeFcntlCmd(alloca(20), x)
@ -111,9 +113,9 @@ const char *DescribeWhichPrio(char[12], int);
#define DescribeSocketProtocol(x) DescribeSocketProtocol(alloca(12), x)
#define DescribeSocketType(x) DescribeSocketType(alloca(64), x)
#define DescribeStdioState(x) DescribeStdioState(alloca(12), x)
#define DescribeStringList(x) DescribeStringList(alloca(300), x)
#define DescribeWhence(x) DescribeWhence(alloca(12), x)
#define DescribeWhichPrio(x) DescribeWhichPrio(alloca(12), x)
#define DescribeDnotifyFlags(x) DescribeDnotifyFlags(alloca(80), x)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -54,8 +54,8 @@ static const char *GetFrameName(int x) {
return "g_fds";
} else if (IsZiposFrame(x)) {
return "zipos";
} else if (IsNsyncFrame(x)) {
return "nsync";
} else if (IsKmallocFrame(x)) {
return "kmalloc";
} else if (IsMemtrackFrame(x)) {
return "memtrack";
} else if (IsOldStackFrame(x)) {

View file

@ -23,14 +23,15 @@
#include "libc/intrin/kprintf.h"
#include "libc/intrin/popcnt.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
#define N 128
#define append(...) i += ksnprintf(buf + i, N - i, __VA_ARGS__)
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
int i, sig;
bool gotsome;
int sig, o = 0;
sigset_t sigset;
if (rc == -1) return "n/a";
@ -41,17 +42,22 @@ const char *(DescribeSigset)(char buf[N], int rc, const sigset_t *ss) {
return buf;
}
i = 0;
sigset = *ss;
gotsome = false;
if (popcnt(sigset.__bits[0] & 0xffffffff) > 16) {
if (sigcountset(ss) > 16) {
append("~");
sigset.__bits[0] = ~sigset.__bits[0];
sigset.__bits[1] = ~sigset.__bits[1];
sigemptyset(&sigset);
for (sig = 1; sig <= NSIG; ++sig) {
if (!sigismember(ss, sig)) {
sigaddset(&sigset, sig);
}
}
} else {
sigset = *ss;
}
append("{");
for (sig = 1; sig < 32; ++sig) {
if (sigismember(&sigset, sig)) {
gotsome = false;
for (sig = 1; sig <= NSIG; ++sig) {
if (sigismember(&sigset, sig) > 0) {
if (gotsome) {
append(",");
} else {

View file

@ -24,10 +24,10 @@
#define N 300
#define append(...) i += ksnprintf(buf + i, N - i, __VA_ARGS__)
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
const char *(DescribeStat)(char buf[N], int rc, const struct stat *st) {
int i = 0;
int o = 0;
if (rc == -1) return "n/a";
if (!st) return "NULL";
@ -59,6 +59,10 @@ const char *(DescribeStat)(char buf[N], int rc, const struct stat *st) {
append(", .st_%s=%lu", "gid", st->st_gid);
}
if (st->st_dev) {
append(", .st_%s=%lu", "dev", st->st_dev);
}
if (st->st_ino) {
append(", .st_%s=%lu", "ino", st->st_ino);
}

View file

@ -0,0 +1,46 @@
/*-*- 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/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#define N 300
#define append(...) o += ksnprintf(buf + o, N - o, __VA_ARGS__)
const char *(DescribeStringList)(char buf[N], char *const list[]) {
int i, o = 0;
if (!list) return "NULL";
if (IsAsan() && !__asan_is_valid_strlist(list)) {
ksnprintf(buf, N, "%p", list);
return buf;
}
append("{");
i = 0;
do {
if (i++) append(", ");
append("%#s", *list);
} while (*list++);
append("}");
return buf;
}

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(__fds_lock)(void) {
@ -26,3 +27,8 @@ void(__fds_lock)(void) {
void(__fds_unlock)(void) {
pthread_mutex_unlock(&__fds_lock_obj);
}
void __fds_funlock(void) {
bzero(&__fds_lock_obj, sizeof(__fds_lock_obj));
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
}

View file

@ -23,6 +23,7 @@
#include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/thread/thread.h"
@ -43,6 +44,8 @@ static textwindows dontinline void SetupWinStd(struct Fds *fds, int i, int x) {
textstartup void InitializeFileDescriptors(void) {
struct Fds *fds;
__fds_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
pthread_atfork(_weaken(__fds_lock), _weaken(__fds_unlock),
_weaken(__fds_funlock));
fds = VEIL("r", &g_fds);
fds->p = fds->e = (void *)kMemtrackFdsStart;
fds->n = 4;

75
libc/intrin/kmalloc.c Normal file
View file

@ -0,0 +1,75 @@
/*-*- 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/atomic.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/extend.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#define KMALLOC_ALIGN __BIGGEST_ALIGNMENT__
static struct {
char *endptr;
size_t total;
pthread_spinlock_t lock;
} g_kmalloc;
static void kmalloc_lock(void) {
if (__threaded) pthread_spin_lock(&g_kmalloc.lock);
}
static void kmalloc_unlock(void) {
pthread_spin_unlock(&g_kmalloc.lock);
}
__attribute__((__constructor__)) static void kmalloc_init(void) {
pthread_atfork(kmalloc_lock, kmalloc_unlock, kmalloc_unlock);
}
/**
* Allocates permanent memory.
*
* The code malloc() depends upon uses this function to allocate memory.
* The returned memory can't be freed, and leak detection is impossible.
* This function panics when memory isn't available.
*/
void *kmalloc(size_t size) {
char *start;
size_t i, n;
n = ROUNDUP(size + (IsAsan() * 8), KMALLOC_ALIGN);
kmalloc_lock();
i = g_kmalloc.total;
g_kmalloc.total += n;
start = (char *)kMemtrackKmallocStart;
if (!g_kmalloc.endptr) g_kmalloc.endptr = start;
g_kmalloc.endptr =
_extend(start, g_kmalloc.total, g_kmalloc.endptr, MAP_PRIVATE,
kMemtrackKmallocStart + kMemtrackKmallocSize);
kmalloc_unlock();
_unassert(!((intptr_t)(start + i) & (KMALLOC_ALIGN - 1)));
if (IsAsan()) __asan_poison(start + i + size, n - size, kAsanHeapOverrun);
return start + i;
}

10
libc/intrin/kmalloc.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_KMALLOC_H_
#define COSMOPOLITAN_LIBC_INTRIN_KMALLOC_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void *kmalloc(size_t) attributeallocsize((1)) mallocesque returnsnonnull;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_KMALLOC_H_ */

View file

@ -206,6 +206,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
const char *abet;
signed char type;
const char *s, *f;
struct CosmoTib *tib;
unsigned long long x;
unsigned i, j, m, rem, sign, hash, cols, prec;
char c, *p, *e, pdot, zero, flip, dang, base, quot, uppr, ansi, z[128];
@ -323,12 +324,12 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
goto FormatUnsigned;
case 'P':
if (!__vforked) {
if (!__tls_enabled) {
x = __pid;
tib = __tls_enabled ? __get_tls_privileged() : 0;
if (!(tib && (tib->tib_flags & TIB_FLAG_VFORKED))) {
if (tib) {
x = atomic_load_explicit(&tib->tib_tid, memory_order_relaxed);
} else {
x = atomic_load_explicit(&__get_tls_privileged()->tib_tid,
memory_order_relaxed);
x = sys_gettid();
}
if (!__nocolor && p + 7 <= e) {
*p++ = '\e';

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/memtrack.internal.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
// this lock currently needs to be (1) recursive and (2) not nsync
@ -30,3 +31,12 @@ void(__mmi_lock)(void) {
void(__mmi_unlock)(void) {
pthread_mutex_unlock(&__mmi_lock_obj);
}
void(__mmi_funlock)(void) {
bzero(&__mmi_lock_obj, sizeof(__mmi_lock_obj));
__mmi_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
}
__attribute__((__constructor__)) static void init(void) {
pthread_atfork(__mmi_lock, __mmi_unlock, __mmi_funlock);
}

View file

@ -0,0 +1,84 @@
/*-*- 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/weaken.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
/**
* Registers fork() handlers.
*
* Parent and child functions are called in the same order they're
* registered. Prepare functions are called in reverse order.
*
* Here's an example of how pthread_atfork() can be used:
*
* static struct {
* pthread_once_t once;
* pthread_mutex_t lock;
* // data structures...
* } g_lib;
*
* static void lib_lock(void) {
* pthread_mutex_lock(&g_lib.lock);
* }
*
* static void lib_unlock(void) {
* pthread_mutex_unlock(&g_lib.lock);
* }
*
* static void lib_funlock(void) {
* pthread_mutex_init(&g_lib.lock, 0);
* }
*
* static void lib_setup(void) {
* lib_funlock();
* pthread_atfork(lib_lock, lib_unlock, lib_funlock);
* }
*
* static void lib_init(void) {
* pthread_once(&g_lib.once, lib_setup);
* }
*
* void lib(void) {
* lib_init();
* lib_lock();
* // do stuff...
* lib_unlock();
* }
*
* This won't actually aspect fork() until pthread_create() is called,
* since we don't want normal non-threaded programs to have to acquire
* exclusive locks on every resource in the entire app just to fork().
*
* The vfork() function is *never* aspected. What happens instead is a
* global variable named `__vforked` is set to true in the child which
* causes lock functions to do nothing. So far, it works like a charm.
*
* @param prepare is run by fork() before forking happens
* @param parent is run by fork() after forking happens in parent process
* @param child is run by fork() after forking happens in childe process
* @return 0 on success, or errno on error
*/
int pthread_atfork(atfork_f prepare, atfork_f parent, atfork_f child) {
if (_weaken(_pthread_atfork)) {
return _weaken(_pthread_atfork)(prepare, parent, child);
} else {
return 0;
}
}

View file

@ -28,7 +28,7 @@
*/
int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
int i, j, rc = EAGAIN;
pthread_spin_lock(&_pthread_keys_lock);
_pthread_key_lock();
for (i = 0; i < (PTHREAD_KEYS_MAX + 63) / 64; ++i) {
if (~_pthread_key_usage[i]) {
j = _bsrl(~_pthread_key_usage[i]);
@ -39,14 +39,29 @@ int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
break;
}
}
pthread_spin_unlock(&_pthread_keys_lock);
_pthread_key_unlock();
return rc;
}
void _pthread_key_lock(void) {
pthread_spin_lock(&_pthread_keys_lock);
}
void _pthread_key_unlock(void) {
pthread_spin_unlock(&_pthread_keys_lock);
}
static void _pthread_key_funlock(void) {
pthread_spin_init(&_pthread_keys_lock, 0);
}
static textexit void _pthread_key_atexit(void) {
_pthread_key_destruct(0);
}
__attribute__((__constructor__)) static textstartup void _pthread_key_init() {
atexit(_pthread_key_atexit);
pthread_atfork(_pthread_key_lock, //
_pthread_key_unlock, //
_pthread_key_funlock);
}

View file

@ -25,7 +25,7 @@
*/
int pthread_key_delete(pthread_key_t key) {
int rc;
pthread_spin_lock(&_pthread_keys_lock);
_pthread_key_lock();
if (key < PTHREAD_KEYS_MAX) {
_pthread_key_usage[key / 64] &= ~(1ul << (key % 64));
_pthread_key_dtor[key] = 0;
@ -33,6 +33,6 @@ int pthread_key_delete(pthread_key_t key) {
} else {
rc = EINVAL;
}
pthread_spin_unlock(&_pthread_keys_lock);
_pthread_key_unlock();
return rc;
}

View file

@ -21,13 +21,14 @@
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
// TODO(jart): why does this even need a lock?
void _pthread_key_destruct(void *key[PTHREAD_KEYS_MAX]) {
int i, j;
uint64_t x;
void *value;
pthread_key_dtor dtor;
if (!__tls_enabled) return;
pthread_spin_lock(&_pthread_keys_lock);
_pthread_key_lock();
if (!key) key = __get_tls()->tib_keys;
StartOver:
for (i = 0; i < (PTHREAD_KEYS_MAX + 63) / 64; ++i) {
@ -36,13 +37,13 @@ StartOver:
j = _bsrl(x);
if ((value = key[i * 64 + j]) && (dtor = _pthread_key_dtor[i * 64 + j])) {
key[i * 64 + j] = 0;
pthread_spin_unlock(&_pthread_keys_lock);
_pthread_key_unlock();
dtor(value);
pthread_spin_lock(&_pthread_keys_lock);
_pthread_key_lock();
goto StartOver;
}
x &= ~(1ul << j);
}
}
pthread_spin_unlock(&_pthread_keys_lock);
_pthread_key_unlock();
}

View file

@ -17,9 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/mu.h"
@ -55,12 +58,19 @@
* pthread_mutex_unlock(&lock);
* pthread_mutex_destroy(&lock);
*
* This function does nothing in vfork() children.
*
* @return 0 on success, or error number on failure
* @see pthread_spin_lock()
* @vforksafe
*/
int pthread_mutex_lock(pthread_mutex_t *mutex) {
int c, d, t;
if (__vforked) return 0;
LOCKTRACE("pthread_mutex_lock(%t)", mutex);
if (__tls_enabled && //
mutex->_type == PTHREAD_MUTEX_NORMAL && //
mutex->_pshared == PTHREAD_PROCESS_PRIVATE && //
@ -96,6 +106,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
mutex->_depth = 0;
mutex->_owner = t;
mutex->_pid = __pid;
return 0;
}

View file

@ -17,9 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/mu.h"
@ -27,12 +30,19 @@
/**
* Releases mutex.
*
* This function does nothing in vfork() children.
*
* @return 0 on success or error number on failure
* @raises EPERM if in error check mode and not owned by caller
* @vforksafe
*/
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
int c, t;
if (__vforked) return 0;
LOCKTRACE("pthread_mutex_unlock(%t)", mutex);
if (__tls_enabled && //
mutex->_type == PTHREAD_MUTEX_NORMAL && //
mutex->_pshared == PTHREAD_PROCESS_PRIVATE && //
@ -47,7 +57,11 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex) {
}
t = gettid();
if (mutex->_owner != t) {
// we allow unlocking an initialized lock that wasn't locked, but we
// don't allow unlocking a lock held by another thread, on unlocking
// recursive locks from a forked child, since it should be re-init'd
if (mutex->_owner && (mutex->_owner != t || mutex->_pid != __pid)) {
return EPERM;
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
/**
@ -29,7 +30,9 @@
int sigaddset(sigset_t *set, int sig) {
_Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
if (1 <= sig && sig <= NSIG) {
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
if (!sigisprecious(sig)) {
set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
}
return 0;
} else {
return einval();

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/struct/sigset.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
/**
* Adds all signals to set.
@ -28,5 +29,7 @@
*/
int sigfillset(sigset_t *set) {
memset(set->__bits, -1, sizeof(set->__bits));
sigdelset(set, SIGKILL);
sigdelset(set, SIGSTOP);
return 0;
}

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
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
@ -16,5 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/sysv/consts/sig.h"
int __vforked;
/**
* Returns true if you're not authorized to block this signal.
*/
int sigisprecious(int sig) {
return sig == SIGKILL || //
sig == SIGSTOP;
}

View file

@ -7,7 +7,8 @@
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _STDIOTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define _LOCKTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %6P %'18T "
@ -55,6 +56,12 @@ COSMOPOLITAN_C_START_
#define NTTRACE(FMT, ...) (void)0
#endif
#if defined(SYSDEBUG) && _LOCKTRACE
#define LOCKTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__)
#else
#define LOCKTRACE(FMT, ...) (void)0
#endif
void __stracef(const char *, ...);
COSMOPOLITAN_C_END_

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/strace.internal.h"
#include "libc/thread/tls.h"
void __require_tls(void) {

View file

@ -228,8 +228,8 @@ static void __ubsan_warning(const struct UbsanSourceLocation *loc,
dontdiscard __ubsan_die_f *__ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
kprintf("\n%s:%d: %subsan error%s: %s\n", loc->file, loc->line, RED2, RESET,
description);
kprintf("\n%s:%d: %subsan error%s: %s (tid %d)\n", loc->file, loc->line, RED2,
RESET, description, gettid());
return __ubsan_die();
}