cosmopolitan/libc/thread/tls.h
Justine Tunney 98c5847727
Fix fork waiter leak in nsync
This change fixes a bug where nsync waiter objects would leak. It'd mean
that long-running programs like runitd would run out of file descriptors
on NetBSD where waiter objects have ksem file descriptors. On other OSes
this bug is mostly harmless since the worst that can happen with a futex
is to leak a little bit of ram. The bug was caused because tib_nsync was
sneaking back in after the finalization code had cleared it. This change
refactors the thread exiting code to handle nsync teardown appropriately
and in making this change I found another issue, which is that user code
which is buggy, and tries to exit without joining joinable threads which
haven't been detached, would result in a deadlock. That doesn't sound so
bad, except the main thread is a joinable thread. So this deadlock would
be triggered in ways that put libc at fault. So we now auto-join threads
and libc will log a warning to --strace when that happens for any thread
2024-12-31 01:30:13 -08:00

94 lines
2.7 KiB
C

#ifndef COSMOPOLITAN_LIBC_THREAD_TLS_H_
#define COSMOPOLITAN_LIBC_THREAD_TLS_H_
#define TLS_ALIGNMENT 64
#define TIB_FLAG_VFORKED 1
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct CosmoFtrace { /* 16 */
char ft_once; /* 0 */
char ft_noreentry; /* 1 */
int ft_skew; /* 4 */
int64_t ft_lastaddr; /* 8 */
};
/* cosmopolitan thread information block (1024 bytes) */
/* NOTE: update aarch64 libc/errno.h if sizeof changes */
/* NOTE: update aarch64 libc/proc/vfork.S if sizeof changes */
/* NOTE: update aarch64 libc/nexgen32e/gc.S if sizeof changes */
struct CosmoTib {
struct CosmoTib *tib_self; /* 0x00 */
struct CosmoFtrace tib_ftracer; /* 0x08 */
void *tib_garbages; /* 0x18 */
_Atomic(int32_t) tib_ptid; /* 0x20 transitions 0 → tid */
intptr_t tib_pthread; /* 0x28 */
struct CosmoTib *tib_self2; /* 0x30 */
_Atomic(int32_t) tib_ctid; /* 0x38 transitions -1 → tid → 0 */
int32_t tib_errno; /* 0x3c */
uint64_t tib_flags; /* 0x40 */
int tib_ftrace; /* inherited */
int tib_strace; /* inherited */
_Atomic(uint64_t) tib_sigmask; /* inherited */
_Atomic(uint64_t) tib_sigpending;
_Atomic(uint64_t) tib_syshand; /* win32=kThread, xnusilicon=pthread_t */
char *tib_sigstack_addr;
uint32_t tib_sigstack_size;
uint32_t tib_sigstack_flags;
void *tib_nsync;
void *tib_atexit;
_Atomic(void *) tib_keys[46];
void *tib_locks[64];
} __attribute__((__aligned__(64)));
extern char __tls_morphed;
extern unsigned __tls_index;
char *_mktls(struct CosmoTib **) libcesque;
void __bootstrap_tls(struct CosmoTib *, char *) libcesque;
#ifdef __x86_64__
extern char __tls_enabled;
#define __tls_enabled_set(x) __tls_enabled = x
#elif defined(__aarch64__)
#define __tls_enabled true
#define __tls_enabled_set(x) (void)0
#else
#error "unsupported architecture"
#endif
void __set_tls(struct CosmoTib *) libcesque;
/**
* Returns location of thread information block.
*
* This can't be used in privileged functions.
*/
forceinline pureconst struct CosmoTib *__get_tls(void) {
#ifdef __chibicc__
return 0;
#elif __x86_64__
struct CosmoTib *__tib;
__asm__("mov\t%%gs:0x30,%0" : "=r"(__tib));
return __tib;
#elif defined(__aarch64__)
register struct CosmoTib *__tls __asm__("x28");
return __tls - 1;
#endif
}
struct CosmoTib *__get_tls_privileged(void) dontthrow pureconst;
struct CosmoTib *__get_tls_win32(void) dontthrow;
void __set_tls_win32(void *) libcesque;
#ifdef __x86_64__
#define __adj_tls(tib) (tib)
#elif defined(__aarch64__)
#define __adj_tls(tib) ((struct CosmoTib *)(tib) + 1)
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_THREAD_TLS_H_ */