mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 17:28:30 +00:00
Make _Thread_local more seamlessly working
This commit is contained in:
parent
5f4f6b0e69
commit
5fa77f1e8f
23 changed files with 217 additions and 283 deletions
|
@ -1,58 +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 2020 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/bits/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Detaches thread.
|
||||
*
|
||||
* Calling this function will cause the thread to free its own memory
|
||||
* once it exits. Using this function is mutually exclusive from the
|
||||
* chtread_join() API.
|
||||
*
|
||||
* @return 0 on success or errno number on failure
|
||||
* @raises EINVAL if thread isn't joinable
|
||||
* @raises ESRCH if no such thread exists
|
||||
* @threadsafe
|
||||
*/
|
||||
int cthread_detach(cthread_t td) {
|
||||
int rc, tid;
|
||||
if (!td || (IsAsan() && !__asan_is_valid(td, sizeof(*td)))) {
|
||||
rc = ESRCH;
|
||||
tid = -1;
|
||||
} else if ((tid = td->tid) == gettid()) {
|
||||
rc = EDEADLK;
|
||||
} else if (atomic_load(&td->state) & (cthread_detached | cthread_joining)) {
|
||||
rc = EINVAL;
|
||||
} else if (!atomic_fetch_add(&td->state, cthread_detached) &
|
||||
cthread_finished) {
|
||||
rc = 0;
|
||||
} else if (!munmap(td->alloc.bottom, td->alloc.top - td->alloc.bottom)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = errno;
|
||||
}
|
||||
STRACE("cthread_detached(%d) → %s", tid, !rc ? "0" : strerrno(rc));
|
||||
return rc;
|
||||
}
|
|
@ -1,33 +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 2020 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/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Exits cosmopolitan thread.
|
||||
*
|
||||
* @param exitcode is passed along to cthread_join()
|
||||
* @threadsafe
|
||||
* @noreturn
|
||||
*/
|
||||
wontreturn void cthread_exit(void *exitcode) {
|
||||
STRACE("cthread_exit(%p)", exitcode);
|
||||
longerjmp(cthread_self()->exiter, (intptr_t)exitcode);
|
||||
}
|
|
@ -4,8 +4,9 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern uint64_t _pthread_key_usage[(PTHREAD_KEYS_MAX + 63) / 64];
|
||||
extern pthread_key_dtor _pthread_key_dtor[PTHREAD_KEYS_MAX];
|
||||
hidden extern uint64_t _pthread_key_usage[(PTHREAD_KEYS_MAX + 63) / 64];
|
||||
hidden extern pthread_key_dtor _pthread_key_dtor[PTHREAD_KEYS_MAX];
|
||||
hidden extern _Thread_local void *_pthread_keys[PTHREAD_KEYS_MAX];
|
||||
|
||||
void _pthread_key_destruct(void *[PTHREAD_KEYS_MAX]);
|
||||
|
||||
|
|
|
@ -18,5 +18,11 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/thread/internal.h"
|
||||
|
||||
// tls value slots for pthread keys api
|
||||
_Thread_local void *_pthread_keys[PTHREAD_KEYS_MAX];
|
||||
|
||||
// bitset of tls key registrations
|
||||
uint64_t _pthread_key_usage[(PTHREAD_KEYS_MAX + 63) / 64];
|
||||
|
||||
// pthread tls key destructors
|
||||
pthread_key_dtor _pthread_key_dtor[PTHREAD_KEYS_MAX];
|
||||
|
|
|
@ -18,16 +18,15 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/thread/internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
STATIC_YOINK("_main_thread_ctor");
|
||||
|
||||
/**
|
||||
* Gets value of TLS slot for current thread.
|
||||
*/
|
||||
void *pthread_getspecific(pthread_key_t key) {
|
||||
if (key < PTHREAD_KEYS_MAX) {
|
||||
return ((cthread_t)__get_tls_inline())->key[key];
|
||||
if (0 <= key && key < PTHREAD_KEYS_MAX) {
|
||||
return _pthread_keys[key];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#include "libc/thread/internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
STATIC_YOINK("_main_thread_ctor");
|
||||
|
||||
/**
|
||||
* Allocates TLS slot.
|
||||
*/
|
||||
|
@ -43,7 +41,7 @@ int pthread_key_create(pthread_key_t *key, pthread_key_dtor dtor) {
|
|||
}
|
||||
|
||||
static textexit void _pthread_key_atexit(void) {
|
||||
_pthread_key_destruct(((cthread_t)__get_tls())->key);
|
||||
_pthread_key_destruct(_pthread_keys);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static textstartup void _pthread_key_init() {
|
||||
|
|
|
@ -18,16 +18,15 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/thread/internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
STATIC_YOINK("_main_thread_ctor");
|
||||
|
||||
/**
|
||||
* Sets value of TLS slot for current thread.
|
||||
*/
|
||||
int pthread_setspecific(pthread_key_t key, void *val) {
|
||||
if (key < PTHREAD_KEYS_MAX) {
|
||||
((cthread_t)__get_tls_inline())->key[key] = val;
|
||||
if (0 <= key && key < PTHREAD_KEYS_MAX) {
|
||||
_pthread_keys[key] = val;
|
||||
return 0;
|
||||
} else {
|
||||
return EINVAL;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
STATIC_YOINK("_main_thread_ctor");
|
||||
|
@ -29,7 +30,7 @@ static void Pause(int attempt) {
|
|||
__builtin_ia32_pause();
|
||||
}
|
||||
} else {
|
||||
cthread_yield();
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,19 @@
|
|||
STATIC_YOINK("_main_thread_ctor");
|
||||
|
||||
/**
|
||||
* @fileoverview Simple System Threads API
|
||||
* @fileoverview Simple threading API
|
||||
*
|
||||
* This API is supported on all six operating systems. We have this
|
||||
* because the POSIX threads API is positively enormous. We currently
|
||||
* only implement a small subset of POSIX threads, e.g. mutexes. So
|
||||
* until we can implement all of POSIX threads, this API is great. If we
|
||||
* consider that the classic forking concurrency library consists of a
|
||||
* single function, it's a shame POSIX didn't define threads in the past
|
||||
* to just be this. Since create/join/atomics is really all we need.
|
||||
*
|
||||
* Your spawn library abstracts clone() which also works on all
|
||||
* platforms; however our implementation of clone() is significantly
|
||||
* complicated so we strongly recommend always favoring this API.
|
||||
*/
|
||||
|
||||
#define _TLSZ ((intptr_t)_tls_size)
|
||||
|
@ -50,7 +62,7 @@ STATIC_YOINK("_main_thread_ctor");
|
|||
* @param arg shall be passed to `fun`
|
||||
* @param opt_out_thread needn't be initialiized and is always clobbered
|
||||
* except when it isn't specified, in which case, the thread is kind
|
||||
* of detached and will leak in stack / tls memory
|
||||
* of detached and will (currently) just leak the stack / tls memory
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int _spawn(int fun(void *, int), void *arg, struct spawn *opt_out_thread) {
|
||||
|
|
|
@ -23,17 +23,11 @@ struct cthread_descriptor_t {
|
|||
int32_t __pad0; /* 0x10 */
|
||||
int32_t state; /* 0x14 */
|
||||
void *arg; /* 0x18 */
|
||||
void *pthread_ret_ptr; /* 0x20 */
|
||||
int64_t __pad1; /* 0x28 */
|
||||
int64_t __pad1; /* 0x20 */
|
||||
int64_t __pad2; /* 0x28 */
|
||||
struct cthread_descriptor_t *self2; /* 0x30 */
|
||||
int32_t tid; /* 0x38 */
|
||||
int32_t err; /* 0x3c */
|
||||
void *exitcode;
|
||||
struct {
|
||||
char *top, *bottom;
|
||||
} stack, alloc;
|
||||
jmp_buf exiter;
|
||||
void *key[PTHREAD_KEYS_MAX];
|
||||
};
|
||||
|
||||
typedef struct cthread_descriptor_t *cthread_t;
|
||||
|
@ -49,16 +43,7 @@ typedef struct cthread_attr_t {
|
|||
int mode;
|
||||
} cthread_attr_t;
|
||||
|
||||
extern const void *const _main_thread_ctor[];
|
||||
|
||||
int cthread_create(cthread_t *, const cthread_attr_t *, void *(*)(void *),
|
||||
void *);
|
||||
|
||||
int cthread_yield(void);
|
||||
cthread_t cthread_self(void);
|
||||
int cthread_join(cthread_t, void **);
|
||||
void cthread_exit(void *) wontreturn;
|
||||
int cthread_detach(cthread_t);
|
||||
int cthread_attr_init(cthread_attr_t *);
|
||||
int cthread_attr_destroy(cthread_attr_t *);
|
||||
int cthread_attr_setstacksize(cthread_attr_t *, size_t);
|
||||
|
|
|
@ -1,27 +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 2020 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/calls.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Asks operating system to handoff remaining time slice.
|
||||
*/
|
||||
int cthread_yield(void) {
|
||||
return sched_yield();
|
||||
}
|
|
@ -1,51 +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/bits/atomic.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static struct Zombie {
|
||||
struct Zombie *next;
|
||||
cthread_t td;
|
||||
} * cthread_zombies;
|
||||
|
||||
void cthread_zombies_add(cthread_t td) {
|
||||
struct Zombie *z;
|
||||
if ((z = malloc(sizeof(struct Zombie)))) {
|
||||
z->td = td;
|
||||
z->next = atomic_load(&cthread_zombies);
|
||||
for (;;) {
|
||||
if (atomic_compare_exchange_weak(&cthread_zombies, &z->next, z)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cthread_zombies_reap(void) {
|
||||
struct Zombie *z;
|
||||
// TODO(jart): Is this right? Update to not use malloc/free?
|
||||
while ((z = atomic_load(&cthread_zombies)) && !atomic_load(&z->td->tid)) {
|
||||
if (atomic_compare_exchange_weak(&cthread_zombies, &z, z->next)) {
|
||||
munmap(z->td->alloc.bottom, z->td->alloc.top - z->td->alloc.bottom);
|
||||
free(z);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue