mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make POSIX threads improvements
- Ensure SIGTHR isn't blocked in newly created threads - Use TIB rather than thread_local for thread atexits - Make POSIX thread keys atomic within thread - Don't bother logging prctl() to --strace - Log thread destructor names to --strace
This commit is contained in:
parent
387310c659
commit
76957983cf
11 changed files with 57 additions and 71 deletions
|
@ -53,15 +53,5 @@ int prctl(int operation, ...) {
|
|||
rc = enosys();
|
||||
}
|
||||
|
||||
#if SYSDEBUG
|
||||
if (operation == PR_CAPBSET_READ || operation == PR_CAPBSET_DROP) {
|
||||
STRACE("prctl(%s, %s) → %d% m", DescribePrctlOperation(operation),
|
||||
DescribeCapability(a), rc);
|
||||
} else {
|
||||
STRACE("prctl(%s, %p, %p, %p, %p) → %d% m",
|
||||
DescribePrctlOperation(operation), a, b, c, d, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ const char *DescribeFlags(char *, size_t, const struct DescribeFlags *, size_t,
|
|||
|
||||
const char *DescribeArchPrctlCode(char[12], int) libcesque;
|
||||
const char *DescribeCancelState(char[12], int, int *) libcesque;
|
||||
const char *DescribeCapability(char[32], int) libcesque;
|
||||
const char *DescribeClockName(char[32], int) libcesque;
|
||||
const char *DescribeControlKeyState(char[64], uint32_t) libcesque;
|
||||
const char *DescribeDirfd(char[12], int) libcesque;
|
||||
|
@ -47,7 +46,6 @@ const char *DescribeOpenFlags(char[128], int) libcesque;
|
|||
const char *DescribeOpenMode(char[15], int, int) libcesque;
|
||||
const char *DescribePersonalityFlags(char[128], int) libcesque;
|
||||
const char *DescribePollFlags(char[64], int) libcesque;
|
||||
const char *DescribePrctlOperation(int) libcesque;
|
||||
const char *DescribeProtFlags(char[48], int) libcesque;
|
||||
const char *DescribePtrace(char[12], int) libcesque;
|
||||
const char *DescribePtraceEvent(char[32], int) libcesque;
|
||||
|
@ -69,9 +67,7 @@ const char *DescribeVirtualKeyCode(char[32], uint32_t) libcesque;
|
|||
const char *DescribeWhence(char[12], int) libcesque;
|
||||
const char *DescribeWhichPrio(char[12], int) libcesque;
|
||||
|
||||
#define DescribeArchPrctlCode(x) DescribeArchPrctlCode(alloca(12), x)
|
||||
#define DescribeCancelState(x, y) DescribeCancelState(alloca(12), x, y)
|
||||
#define DescribeCapability(x) DescribeCapability(alloca(32), x)
|
||||
#define DescribeClockName(x) DescribeClockName(alloca(32), x)
|
||||
#define DescribeControlKeyState(x) DescribeControlKeyState(alloca(64), x)
|
||||
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/cxaatexit.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
|
@ -30,8 +31,6 @@ struct Dtor {
|
|||
struct Dtor *next;
|
||||
};
|
||||
|
||||
static _Thread_local struct Dtor *__cxa_thread_atexit_list;
|
||||
|
||||
static void _pthread_unwind(struct CosmoTib *tib) {
|
||||
struct PosixThread *pt;
|
||||
struct _pthread_cleanup_buffer *cb;
|
||||
|
@ -42,24 +41,24 @@ static void _pthread_unwind(struct CosmoTib *tib) {
|
|||
}
|
||||
}
|
||||
|
||||
static void __cxa_thread_unkey(struct CosmoTib *tib) {
|
||||
void *val;
|
||||
int i, j, gotsome;
|
||||
pthread_key_dtor dtor;
|
||||
for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; ++j) {
|
||||
for (gotsome = i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
if ((val = tib->tib_keys[i]) &&
|
||||
(dtor = atomic_load_explicit(_pthread_key_dtor + i,
|
||||
memory_order_relaxed)) &&
|
||||
dtor != (pthread_key_dtor)-1) {
|
||||
gotsome = 1;
|
||||
tib->tib_keys[i] = 0;
|
||||
static void _pthread_unkey(struct CosmoTib *tib) {
|
||||
for (int j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; ++j) {
|
||||
bool gotsome = false;
|
||||
for (int i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
void *val;
|
||||
pthread_key_dtor dtor;
|
||||
if ((dtor = atomic_load_explicit(&_pthread_key_dtor[i],
|
||||
memory_order_acquire)) &&
|
||||
dtor != (pthread_key_dtor)-1 &&
|
||||
(val = atomic_exchange_explicit(&tib->tib_keys[i], 0,
|
||||
memory_order_relaxed))) {
|
||||
STRACE("_pthread_unkey(%t, %p)", dtor, val);
|
||||
gotsome = true;
|
||||
dtor(val);
|
||||
}
|
||||
}
|
||||
if (!gotsome) {
|
||||
if (!gotsome)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,9 +66,8 @@ static void _pthread_ungarbage(struct CosmoTib *tib) {
|
|||
struct Garbages *g;
|
||||
while ((g = tib->tib_garbages)) {
|
||||
tib->tib_garbages = 0;
|
||||
while (g->i--) {
|
||||
while (g->i--)
|
||||
((void (*)(intptr_t))g->p[g->i].fn)(g->p[g->i].arg);
|
||||
}
|
||||
_weaken(free)(g->p);
|
||||
_weaken(free)(g);
|
||||
}
|
||||
|
@ -82,10 +80,11 @@ void __cxa_thread_finalize(void) {
|
|||
_pthread_unwind(tib);
|
||||
if (tib->tib_nsync)
|
||||
_weaken(nsync_waiter_destroy)(tib->tib_nsync);
|
||||
__cxa_thread_unkey(tib);
|
||||
_pthread_unkey(tib);
|
||||
_pthread_ungarbage(tib);
|
||||
while ((dtor = __cxa_thread_atexit_list)) {
|
||||
__cxa_thread_atexit_list = dtor->next;
|
||||
while ((dtor = tib->tib_atexit)) {
|
||||
STRACE("__cxa_finalize(%t, %p)", dtor->fun, dtor->arg);
|
||||
tib->tib_atexit = dtor->next;
|
||||
((void (*)(void *))dtor->fun)(dtor->arg);
|
||||
_weaken(free)(dtor);
|
||||
}
|
||||
|
@ -97,9 +96,11 @@ int __cxa_thread_atexit_impl(void *fun, void *arg, void *dso_symbol) {
|
|||
return -1;
|
||||
if (!(dtor = _weaken(malloc)(sizeof(struct Dtor))))
|
||||
return -1;
|
||||
struct CosmoTib *tib;
|
||||
tib = __get_tls();
|
||||
dtor->fun = fun;
|
||||
dtor->arg = arg;
|
||||
dtor->next = __cxa_thread_atexit_list;
|
||||
__cxa_thread_atexit_list = dtor;
|
||||
dtor->next = tib->tib_atexit;
|
||||
tib->tib_atexit = dtor;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -54,9 +54,8 @@ long _pthread_cancel_ack(void) {
|
|||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
pt->pt_flags |= PT_NOCANCEL;
|
||||
if (IsOpenbsd()) {
|
||||
if (IsOpenbsd())
|
||||
pt->pt_flags |= PT_OPENBSD_KLUDGE;
|
||||
}
|
||||
return ecanceled();
|
||||
}
|
||||
|
||||
|
@ -351,6 +350,7 @@ static errno_t _pthread_cancel_everyone(void) {
|
|||
* @param thread may be 0 to cancel all threads except self
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise ESRCH if system thread wasn't alive or we lost a race
|
||||
* @cancelationpoint
|
||||
*/
|
||||
errno_t pthread_cancel(pthread_t thread) {
|
||||
struct PosixThread *arg;
|
||||
|
@ -401,6 +401,7 @@ void pthread_testcancel(void) {
|
|||
*
|
||||
* @return 0 if not cancelled or cancelation is blocked or `ECANCELED`
|
||||
* in masked mode when the calling thread has been cancelled
|
||||
* @cancelationpoint
|
||||
*/
|
||||
errno_t pthread_testcancel_np(void) {
|
||||
struct PosixThread *pt;
|
||||
|
|
|
@ -117,6 +117,7 @@ static int PosixThread(void *arg, int tid) {
|
|||
}
|
||||
// set long jump handler so pthread_exit can bring control back here
|
||||
if (!setjmp(pt->pt_exiter)) {
|
||||
sigdelset(&pt->pt_attr.__sigmask, SIGTHR);
|
||||
if (IsWindows()) {
|
||||
atomic_store_explicit(&__get_tls()->tib_sigmask, pt->pt_attr.__sigmask,
|
||||
memory_order_release);
|
||||
|
|
|
@ -48,9 +48,9 @@ int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
|
|||
if (!dtor)
|
||||
dtor = (pthread_key_dtor)-1;
|
||||
for (i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
||||
if (!(expect = atomic_load_explicit(_pthread_key_dtor + i,
|
||||
memory_order_acquire)) &&
|
||||
atomic_compare_exchange_strong_explicit(_pthread_key_dtor + i, &expect,
|
||||
if (!(expect = atomic_load_explicit(&_pthread_key_dtor[i],
|
||||
memory_order_relaxed)) &&
|
||||
atomic_compare_exchange_strong_explicit(&_pthread_key_dtor[i], &expect,
|
||||
dtor, memory_order_release,
|
||||
memory_order_relaxed)) {
|
||||
*key = i;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
|
@ -32,10 +31,12 @@
|
|||
*
|
||||
* @param key was created by pthread_key_create()
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EINVAL if `key` is invalid
|
||||
*/
|
||||
int pthread_key_delete(pthread_key_t k) {
|
||||
unassert(0 <= k && k < PTHREAD_KEYS_MAX);
|
||||
unassert(atomic_load_explicit(_pthread_key_dtor + k, memory_order_acquire));
|
||||
atomic_store_explicit(_pthread_key_dtor + k, 0, memory_order_release);
|
||||
if (!(0 <= k && k < PTHREAD_KEYS_MAX))
|
||||
return EINVAL; // corrupt key identifier
|
||||
if (!atomic_exchange_explicit(&_pthread_key_dtor[k], 0, memory_order_acq_rel))
|
||||
return EINVAL; // delete called twice
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_THREAD_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_THREAD_H_
|
||||
|
||||
#define PTHREAD_KEYS_MAX 48
|
||||
#define PTHREAD_KEYS_MAX 46
|
||||
#define PTHREAD_STACK_MIN 65536
|
||||
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@ struct CosmoTib {
|
|||
uint32_t tib_sigstack_flags;
|
||||
_Atomic(int) tib_relock_maps;
|
||||
void *tib_nsync;
|
||||
void *tib_keys[47];
|
||||
void *tib_atexit;
|
||||
_Atomic(void *) tib_keys[46];
|
||||
} __attribute__((__aligned__(64)));
|
||||
|
||||
extern int __threaded;
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
#include "ctl/array.h"
|
||||
#include "libc/mem/leaks.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#define ctl std
|
||||
// #include <algorithm>
|
||||
// #include <array>
|
||||
// #define ctl std
|
||||
|
||||
int
|
||||
main()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2024 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,24 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/sysv/consts/pr.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
const char *DescribePrctlOperation(int x) {
|
||||
switch (x) {
|
||||
case PR_GET_NAME:
|
||||
return "PR_GET_NAME";
|
||||
case PR_SET_NO_NEW_PRIVS:
|
||||
return "PR_SET_NO_NEW_PRIVS";
|
||||
case PR_SET_SECCOMP:
|
||||
return "PR_SET_SECCOMP";
|
||||
case PR_GET_SECCOMP:
|
||||
return "PR_GET_SECCOMP";
|
||||
case PR_CAPBSET_READ:
|
||||
return "PR_CAPBSET_READ";
|
||||
case PR_CAPBSET_DROP:
|
||||
return "PR_CAPBSET_DROP";
|
||||
default:
|
||||
return "PRCTL_???";
|
||||
}
|
||||
void *wut(void *arg) {
|
||||
pthread_id_np_t tid;
|
||||
pthread_getunique_np(pthread_self(), &tid);
|
||||
ASSERT_EQ(gettid(), tid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_getunique_np, test) {
|
||||
pthread_t id;
|
||||
ASSERT_EQ(0, pthread_create(&id, 0, wut, (void *)1));
|
||||
ASSERT_EQ(0, pthread_join(id, 0));
|
||||
}
|
Loading…
Reference in a new issue