Refactor some code

- Write tests for cthreads
- Fix bugs in pe2.com tool
- Fix ASAN issue with GetDosEnviron()
- Consolidate the cthread header files
- Some code size optimizations for MODE=
- Attempted to squash a tls linker warning
- Attempted to get futexes working on FreeBSD
This commit is contained in:
Justine Tunney 2022-05-28 05:50:01 -07:00
parent 909e54510d
commit 425ff5dff0
61 changed files with 529 additions and 382 deletions

View file

@ -18,7 +18,7 @@
*/
#include "libc/errno.h"
#include "libc/runtime/stack.h"
#include "libc/thread/attr.h"
#include "libc/thread/thread.h"
#define MIN_STACKSIZE (8 * PAGESIZE) // includes guard, rounds up to FRAMESIZE
#define MIN_GUARDSIZE PAGESIZE

View file

@ -1,30 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_ATTR_H_
#define COSMOPOLITAN_LIBC_THREAD_ATTR_H_
#define CTHREAD_CREATE_DETACHED 1
#define CTHREAD_CREATE_JOINABLE 0
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview cosmopolitan thread attributes
*/
typedef struct cthread_attr_t {
size_t stacksize, guardsize;
int mode;
} cthread_attr_t;
int cthread_attr_init(cthread_attr_t*);
int cthread_attr_destroy(cthread_attr_t*);
int cthread_attr_setstacksize(cthread_attr_t*, size_t);
size_t thread_attr_getstacksize(const cthread_attr_t*);
int cthread_attr_setguardsize(cthread_attr_t*, size_t);
size_t cthread_attr_getguardsize(const cthread_attr_t*);
int cthread_attr_setdetachstate(cthread_attr_t*, int);
int cthread_attr_getdetachstate(const cthread_attr_t*);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_ATTR_H_ */

View file

@ -28,10 +28,7 @@
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/attr.h"
#include "libc/thread/create.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/zombie.h"
#include "libc/thread/thread.h"
STATIC_YOINK("_main_thread_ctor");
@ -99,8 +96,8 @@ static int cthread_start(void *arg) {
* @return 0 on success, or error number on failure
* @threadsafe
*/
int cthread_create(cthread_t *restrict ptd, const cthread_attr_t *restrict attr,
void *(*func)(void *), void *restrict arg) {
int cthread_create(cthread_t *ptd, const cthread_attr_t *attr,
void *(*func)(void *), void *arg) {
int rc, tid;
cthread_t td;
cthread_attr_t default_attr;

View file

@ -1,17 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_CREATE_H_
#define COSMOPOLITAN_LIBC_THREAD_CREATE_H_
#include "libc/thread/attr.h"
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview Create a cosmopolitan thread
*/
int cthread_create(cthread_t *restrict, const cthread_attr_t *restrict,
void *(*)(void *), void *restrict);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_CREATE_H_ */

View file

@ -1,41 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
#define COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "libc/runtime/runtime.h"
/**
* @fileoverview thread types
*/
enum cthread_state {
cthread_started = 0,
cthread_joining = 1,
cthread_finished = 2,
cthread_detached = 4,
cthread_main = 127,
};
struct cthread_descriptor_t {
struct cthread_descriptor_t *self; /* 0x00 */
void *(*func)(void *); /* 0x08 */
int32_t __pad0; /* 0x10 */
int32_t state; /* 0x14 */
void *arg; /* 0x18 */
void *pthread_ret_ptr; /* 0x20 */
int64_t __pad1; /* 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;
};
typedef struct cthread_descriptor_t *cthread_t;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_ */

View file

@ -22,8 +22,7 @@
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/detach.h"
#include "libc/thread/thread.h"
/**
* Detaches thread.

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_DETACH_H_
#define COSMOPOLITAN_LIBC_THREAD_DETACH_H_
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview detach a thread
*/
int cthread_detach(cthread_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_DETACH_H_ */

View file

@ -18,8 +18,7 @@
*/
#include "libc/calls/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/exit.h"
#include "libc/thread/self.h"
#include "libc/thread/thread.h"
/**
* Exits cosmopolitan thread.

View file

@ -1,10 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_EXIT_H_
#define COSMOPOLITAN_LIBC_THREAD_EXIT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
wontreturn void cthread_exit(void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_EXIT_H_ */

View file

@ -3,8 +3,6 @@
#include "libc/bits/asmflag.h"
#include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview FreeBSD Threading
@ -13,6 +11,13 @@ COSMOPOLITAN_C_START_
* maximum legal range is PID_MAX + 2 (100001) through INT_MAX
*/
#define UMTX_OP_MUTEX_WAIT 17
#define UMTX_OP_MUTEX_WAKE 18
#define UMTX_ABSTIME 1
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct rtprio {
uint16_t type; /* scheduling class */
uint16_t prio;
@ -31,6 +36,14 @@ struct thr_param {
struct rtprio *rtp;
};
struct _umtx_time {
struct timespec _timeout;
uint32_t _flags;
uint32_t _clockid;
};
int _umtx_op(void *, int, unsigned long, void *, void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_FREEBSD_INTERNAL_H_ */

View file

@ -27,8 +27,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/self.h"
#include "libc/thread/thread.h"
static textstartup void _main_thread_init(void) {
_Static_assert(offsetof(struct cthread_descriptor_t, self) == 0x00, "");
@ -67,6 +66,7 @@ static textstartup void _main_thread_init(void) {
// Set FS
__install_tls((char *)td);
assert(cthread_self()->tid == gettid());
__threaded = true;
}
const void *const _main_thread_ctor[] initarray = {

View file

@ -27,8 +27,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/futex.h"
#include "libc/sysv/consts/nr.h"
#include "libc/thread/descriptor.h"
#include "libc/thread/join.h"
#include "libc/thread/thread.h"
/**
* Waits for thread to terminate and frees its memory.
@ -43,7 +42,7 @@
* @threadsafe
*/
int cthread_join(cthread_t td, void **exitcode) {
int rc, tid;
int x, rc, tid;
// otherwise, tid could be set to 0 even though `state` is not
// finished mark thread as joining
if (!td || (IsAsan() && !__asan_is_valid(td, sizeof(*td)))) {
@ -55,11 +54,10 @@ int cthread_join(cthread_t td, void **exitcode) {
rc = EINVAL;
} else {
if (~atomic_fetch_add(&td->state, cthread_joining) & cthread_finished) {
if (IsLinux() || IsOpenbsd()) {
while ((x = atomic_load(&td->tid))) {
// FUTEX_WAIT_PRIVATE makes it hang
futex((uint32_t *)&td->tid, FUTEX_WAIT, tid, 0, 0);
cthread_memory_wait32((uint32_t *)&td->tid, x, 0);
}
_spinlock(&td->tid);
}
if (exitcode) {
*exitcode = td->exitcode;

View file

@ -1,11 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_JOIN_H_
#define COSMOPOLITAN_LIBC_THREAD_JOIN_H_
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int cthread_join(cthread_t, void **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_JOIN_H_ */

View file

@ -16,7 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/thread/self.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/thread/thread.h"
STATIC_YOINK("_main_thread_ctor");
@ -24,5 +25,5 @@ STATIC_YOINK("_main_thread_ctor");
* Returns thread descriptor of the current thread.
*/
cthread_t(cthread_self)(void) {
return cthread_self();
return (cthread_t)__get_tls_inline();
}

View file

@ -1,22 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_SELF_H_
#define COSMOPOLITAN_LIBC_THREAD_SELF_H_
#include "libc/nexgen32e/threaded.h"
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const void *const _main_thread_ctor[];
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define cthread_self() \
({ \
YOINK(_main_thread_ctor); \
((cthread_t)__get_tls()); \
})
#else
cthread_t cthread_self(void);
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */

View file

@ -17,9 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/atomic.h"
#include "libc/thread/sem.h"
#include "libc/thread/wait.h"
#include "libc/thread/yield.h"
#include "libc/thread/thread.h"
STATIC_YOINK("_main_thread_ctor");

View file

@ -1,24 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_
#define COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview native semaphore for implementation details
*/
typedef union cthread_sem_t {
struct {
uint64_t count;
} linux;
} cthread_sem_t;
int cthread_sem_init(cthread_sem_t *, int);
int cthread_sem_destroy(cthread_sem_t *);
int cthread_sem_wait(cthread_sem_t *, int, const struct timespec *);
int cthread_sem_signal(cthread_sem_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */

80
libc/thread/thread.h Normal file
View file

@ -0,0 +1,80 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_THREAD_H_
#define COSMOPOLITAN_LIBC_THREAD_THREAD_H_
#include "libc/calls/struct/timespec.h"
#include "libc/runtime/runtime.h"
#define CTHREAD_CREATE_DETACHED 1
#define CTHREAD_CREATE_JOINABLE 0
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
enum cthread_state {
cthread_started = 0,
cthread_joining = 1,
cthread_finished = 2,
cthread_detached = 4,
cthread_main = 127,
};
struct cthread_descriptor_t {
struct cthread_descriptor_t *self; /* 0x00 */
void *(*func)(void *); /* 0x08 */
int32_t __pad0; /* 0x10 */
int32_t state; /* 0x14 */
void *arg; /* 0x18 */
void *pthread_ret_ptr; /* 0x20 */
int64_t __pad1; /* 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;
};
typedef struct cthread_descriptor_t *cthread_t;
typedef union cthread_sem_t {
struct {
uint64_t count;
} linux;
} cthread_sem_t;
typedef struct cthread_attr_t {
size_t stacksize, guardsize;
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);
size_t thread_attr_getstacksize(const cthread_attr_t *);
int cthread_attr_setguardsize(cthread_attr_t *, size_t);
size_t cthread_attr_getguardsize(const cthread_attr_t *);
int cthread_attr_setdetachstate(cthread_attr_t *, int);
int cthread_attr_getdetachstate(const cthread_attr_t *);
int cthread_sem_init(cthread_sem_t *, int);
int cthread_sem_destroy(cthread_sem_t *);
int cthread_sem_wait(cthread_sem_t *, int, const struct timespec *);
int cthread_sem_signal(cthread_sem_t *);
int cthread_memory_wait32(uint32_t *, uint32_t, const struct timespec *);
int cthread_memory_wake32(uint32_t *, int);
void cthread_zombies_add(cthread_t);
void cthread_zombies_reap(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_THREAD_H_ */

View file

@ -19,12 +19,33 @@
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/futex.h"
#include "libc/thread/freebsd.internal.h"
#include "libc/thread/thread.h"
int cthread_memory_wait32(uint32_t* addr, uint32_t val,
const struct timespec* timeout) {
size_t size;
struct _umtx_time *put, ut;
if (IsLinux() || IsOpenbsd()) {
return futex(addr, FUTEX_WAIT, val, timeout, 0);
#if 0
} else if (IsFreebsd()) {
if (!timeout) {
put = 0;
size = 0;
} else {
ut._flags = 0;
ut._clockid = CLOCK_REALTIME;
ut._timeout = *timeout;
put = &ut;
size = sizeof(ut);
}
return _umtx_op(addr, UMTX_OP_MUTEX_WAIT, 0, &size, put);
#endif
} else {
unsigned tries;
for (tries = 1; atomic_load(addr) == val; ++tries) {
@ -41,6 +62,10 @@ int cthread_memory_wait32(uint32_t* addr, uint32_t val,
int cthread_memory_wake32(uint32_t* addr, int n) {
if (IsLinux() || IsOpenbsd()) {
return futex(addr, FUTEX_WAKE, n, 0, 0);
#if 0
} else if (IsFreebsd()) {
return _umtx_op(addr, UMTX_OP_MUTEX_WAKE, n, 0, 0);
#endif
}
return -1;
}

View file

@ -1,16 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_WAIT_H_
#define COSMOPOLITAN_LIBC_THREAD_WAIT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview wait on memory
*/
struct timespec;
int cthread_memory_wait32(uint32_t*, uint32_t, const struct timespec*);
int cthread_memory_wake32(uint32_t*, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_WAIT_H_ */

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/thread/yield.h"
#include "libc/thread/thread.h"
/**
* Asks operating system to handoff remaining time slice.

View file

@ -1,14 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_YIELD_H_
#define COSMOPOLITAN_LIBC_THREAD_YIELD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview yield thread to OS scheduler
*/
int cthread_yield(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_YIELD_H_ */

View file

@ -19,7 +19,7 @@
#include "libc/bits/atomic.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/zombie.h"
#include "libc/thread/thread.h"
static struct Zombie {
struct Zombie *next;

View file

@ -1,12 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_
#define COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_
#include "libc/thread/descriptor.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void cthread_zombies_add(cthread_t);
void cthread_zombies_reap(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_ZOMBIE_H_ */