Clean up more code

The *NSYNC linked list API is good enough that it deserves to be part of
the C libray, so this change writes an improved version of it which uses
that offsetof() trick from the Linux Kernel. We vendor all of the *NSYNC
tests in third_party which helped confirm the needed refactoring is safe

This change also deletes more old code that didn't pan out. My goal here
is to work towards a vision where the Cosmopolitan core libraries become
less experimental and more focused on curation. This better reflects the
current level of quality we've managed to achieve.
This commit is contained in:
Justine Tunney 2023-07-06 06:57:28 -07:00
parent 88612a2cd7
commit 0a24b4fc3c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
268 changed files with 632 additions and 8688 deletions

View file

@ -2,10 +2,10 @@
#define COSMOPOLITAN_LIBC_THREAD_POSIXTHREAD_INTERNAL_H_
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/dll.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/dll.h"
#define PT_OWNSTACK 1
#define PT_STATIC 2
@ -64,26 +64,28 @@ enum PosixThreadStatus {
kPosixThreadZombie,
};
#define POSIXTHREAD_CONTAINER(e) DLL_CONTAINER(struct PosixThread, list, e)
struct PosixThread {
int flags; // 0x00: see PT_* constants
_Atomic(int) cancelled; // 0x04: thread has bad beliefs
_Atomic(enum PosixThreadStatus) status;
_Atomic(int) ptid; // transitions 0 → tid
void *(*start)(void *); // creation callback
void *arg; // start's parameter
void *rc; // start's return value
char *altstack; // thread sigaltstack
char *tls; // bottom of tls allocation
struct CosmoTib *tib; // middle of tls allocation
nsync_dll_element_ list; // list of threads
jmp_buf exiter; // for pthread_exit
_Atomic(int) ptid; // transitions 0 → tid
void *(*start)(void *); // creation callback
void *arg; // start's parameter
void *rc; // start's return value
char *altstack; // thread sigaltstack
char *tls; // bottom of tls allocation
struct CosmoTib *tib; // middle of tls allocation
struct Dll list; // list of threads
jmp_buf exiter; // for pthread_exit
pthread_attr_t attr;
struct _pthread_cleanup_buffer *cleanup;
};
typedef void (*atfork_f)(void);
extern nsync_dll_list_ _pthread_list;
extern struct Dll *_pthread_list;
extern pthread_spinlock_t _pthread_lock;
extern _Atomic(pthread_key_dtor) _pthread_key_dtor[PTHREAD_KEYS_MAX] _Hide;

View file

@ -20,6 +20,7 @@
#include "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kmalloc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/memtrack.internal.h"
@ -37,10 +38,10 @@ static struct AtForks {
} _atforks;
static void _pthread_purge(void) {
nsync_dll_element_ *e;
while ((e = nsync_dll_first_(_pthread_list))) {
_pthread_list = nsync_dll_remove_(_pthread_list, e);
_pthread_free(e->container);
struct Dll *e;
while ((e = dll_first(_pthread_list))) {
dll_remove(&_pthread_list, e);
_pthread_free(POSIXTHREAD_CONTAINER(e));
}
}
@ -97,9 +98,9 @@ void _pthread_onfork_child(void) {
// delete other threads that existed before forking
// this must come after onfork, since it calls free
_pthread_list = nsync_dll_remove_(_pthread_list, &pt->list);
dll_remove(&_pthread_list, &pt->list);
_pthread_purge();
_pthread_list = nsync_dll_make_first_in_list_(_pthread_list, &pt->list);
dll_make_first(&_pthread_list, &pt->list);
}
int _pthread_atfork(atfork_f prepare, atfork_f parent, atfork_f child) {

View file

@ -26,10 +26,10 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/dll.h"
#include "libc/log/internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/clone.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
@ -43,7 +43,6 @@
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "libc/thread/wait0.internal.h"
#include "third_party/nsync/dll.h"
STATIC_YOINK("nsync_mu_lock");
STATIC_YOINK("nsync_mu_unlock");
@ -246,9 +245,9 @@ static errno_t pthread_create_impl(pthread_t *thread,
// add thread to global list
// we add it to the end since zombies go at the beginning
nsync_dll_init_(&pt->list, pt);
dll_init(&pt->list);
pthread_spin_lock(&_pthread_lock);
_pthread_list = nsync_dll_make_last_in_list_(_pthread_list, &pt->list);
dll_make_last(&_pthread_list, &pt->list);
pthread_spin_unlock(&_pthread_lock);
// launch PosixThread(pt) in new thread
@ -260,7 +259,7 @@ static errno_t pthread_create_impl(pthread_t *thread,
CLONE_CHILD_CLEARTID,
pt, &pt->ptid, __adj_tls(pt->tib), &pt->tib->tib_tid))) {
pthread_spin_lock(&_pthread_lock);
_pthread_list = nsync_dll_remove_(_pthread_list, &pt->list);
dll_remove(&_pthread_list, &pt->list);
pthread_spin_unlock(&_pthread_lock);
_pthread_free(pt);
return rc;

View file

@ -17,29 +17,28 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/atomic.h"
#include "libc/intrin/dll.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/dll.h"
/**
* Releases memory of detached threads that have terminated.
*/
void pthread_decimate_np(void) {
nsync_dll_element_ *e;
struct Dll *e;
struct PosixThread *pt;
enum PosixThreadStatus status;
StartOver:
pthread_spin_lock(&_pthread_lock);
for (e = nsync_dll_first_(_pthread_list); e;
e = nsync_dll_next_(_pthread_list, e)) {
pt = (struct PosixThread *)e->container;
for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) {
pt = POSIXTHREAD_CONTAINER(e);
if (pt->tib == __get_tls()) continue;
status = atomic_load_explicit(&pt->status, memory_order_acquire);
if (status != kPosixThreadZombie) break;
if (!atomic_load_explicit(&pt->tib->tib_tid, memory_order_acquire)) {
_pthread_list = nsync_dll_remove_(_pthread_list, e);
dll_remove(&_pthread_list, e);
pthread_spin_unlock(&_pthread_lock);
_pthread_free(pt);
goto StartOver;

View file

@ -25,7 +25,6 @@
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/spawn.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/dll.h"
/**
* Asks POSIX thread to free itself automatically upon termination.

View file

@ -29,7 +29,6 @@
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#include "third_party/nsync/dll.h"
#include "third_party/nsync/futex.internal.h"
static void CleanupThread(struct PosixThread *pt) {

View file

@ -1,91 +0,0 @@
/*-*- 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/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/dll.h"
#define N 2048
#define M 15
#define append(f, ...) o += f(buf + o, N - o, __VA_ARGS__)
static const char *DescribeStatus(enum PosixThreadStatus status) {
switch (status) {
case kPosixThreadJoinable:
return "JOINAB";
case kPosixThreadDetached:
return "DETACH";
case kPosixThreadTerminated:
return "TERMIN";
case kPosixThreadZombie:
return "ZOMBIE";
default:
__builtin_unreachable();
}
}
static const char *DescribeFlags(char buf[M], struct PosixThread *pt) {
char *p = buf;
if (pt->cancelled) *p++ = '*';
if (pt->flags & PT_EXITING) *p++ = 'X';
if (pt->flags & PT_STATIC) *p++ = 'S';
if (pt->flags & PT_OWNSTACK) *p++ = 'O';
if (pt->flags & PT_ASYNC) *p++ = 'A';
if (pt->flags & PT_MASKED) *p++ = 'M';
if (pt->flags & PT_OPENBSD_KLUDGE) *p++ = 'K';
if (pt->flags & PT_INCANCEL) *p++ = '?';
if (pt->flags & PT_NOCANCEL) *p++ = '!';
*p = 0;
return buf;
}
int pthread_print_np(int fd, const char *fmt, ...) {
va_list va;
int rc, o = 0;
nsync_dll_element_ *e;
struct PosixThread *pt;
char buf[N], flagbuf[M];
pthread_spin_lock(&_pthread_lock);
if (fmt) {
va_start(va, fmt);
append(kvsnprintf, fmt, va);
va_end(va);
append(ksnprintf, "\n");
}
append(ksnprintf, "%6s %6s %6s %6s %s\n", "ptid", "tid", "status", "flags",
"start");
for (e = nsync_dll_first_(_pthread_list); e;
e = nsync_dll_next_(_pthread_list, e)) {
pt = (struct PosixThread *)e->container;
append(ksnprintf, "%-6d %-6d %6s %6s %t\n", pt->ptid, pt->tib->tib_tid,
DescribeStatus(pt->status), DescribeFlags(flagbuf, pt), pt->start);
}
pthread_spin_unlock(&_pthread_lock);
BLOCK_CANCELLATIONS;
strace_enabled(-1);
rc = write(fd, buf, strlen(buf));
strace_enabled(+1);
ALLOW_CANCELLATIONS;
return rc;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/dll.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread2.h"
#include "libc/thread/tls.h"
@ -60,7 +61,7 @@ errno_t pthread_timedjoin_np(pthread_t thread, void **value_ptr,
_unassert(status == kPosixThreadJoinable || status == kPosixThreadTerminated);
if (!(rc = _wait0(&pt->tib->tib_tid, abstime))) {
pthread_spin_lock(&_pthread_lock);
_pthread_list = nsync_dll_remove_(_pthread_list, &pt->list);
dll_remove(&_pthread_list, &pt->list);
pthread_spin_unlock(&_pthread_lock);
if (value_ptr) {
*value_ptr = pt->rc;

View file

@ -16,13 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/dll.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h"
#include "third_party/nsync/dll.h"
void _pthread_zombify(struct PosixThread *pt) {
pthread_spin_lock(&_pthread_lock);
_pthread_list = nsync_dll_remove_(_pthread_list, &pt->list);
_pthread_list = nsync_dll_make_first_in_list_(_pthread_list, &pt->list);
dll_remove(&_pthread_list, &pt->list);
dll_make_first(&_pthread_list, &pt->list);
pthread_spin_unlock(&_pthread_lock);
}

View file

@ -22,7 +22,6 @@
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/clone.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"

View file

@ -170,7 +170,6 @@ int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int) paramsnonnull();
int pthread_mutexattr_settype(pthread_mutexattr_t *, int) paramsnonnull();
int pthread_once(pthread_once_t *, void (*)(void)) paramsnonnull();
int pthread_orphan_np(void);
int pthread_print_np(int, const char *, ...);
int pthread_rwlock_destroy(pthread_rwlock_t *) paramsnonnull();
int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *) paramsnonnull((1));
int pthread_rwlock_rdlock(pthread_rwlock_t *) paramsnonnull();