Make locks more reliable

This change switches most of the core locks to be re-entrant, in order
to reduce the chance of deadlocking code that does, clever things with
asynchronous signal handlers. This change implements it it in pthreads
so we're one step closer to having a standardized threading primitives
This commit is contained in:
Justine Tunney 2022-06-11 01:59:26 -07:00
parent 5ea618f0af
commit c260345e06
35 changed files with 369 additions and 258 deletions

View file

@ -16,7 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pthread.h"
unsigned __sighandrvas[NSIG];
unsigned __sighandflags[NSIG];
_Alignas(64) int __sig_lock_obj;
pthread_mutex_t __sig_lock_obj;

View file

@ -43,8 +43,6 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
_Alignas(64) static int poll_lock;
/**
* Polls on the New Technology.
*
@ -67,7 +65,6 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
// do the planning
// we need to read static variables
// we might need to spawn threads and open pipes
_spinlock(&poll_lock);
__fds_lock();
for (gotinvals = failed = sn = pn = i = 0; i < nfds; ++i) {
if (fds[i].fd < 0) continue;
@ -115,7 +112,6 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
}
}
__fds_unlock();
_spunlock(&poll_lock);
if (failed) {
// failed to create a polling solution
return failed;

View file

@ -23,11 +23,9 @@ struct Signals {
struct Signal mem[__SIG_QUEUE_LENGTH];
};
extern struct Signals __sig; // TODO(jart): Need TLS
extern long __sig_count;
extern struct Signals __sig;
void __sig_lock(void) hidden;
void __sig_unlock(void) hidden;
bool __sig_check(bool) hidden;
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
int __sig_add(int, int) hidden;

View file

@ -1,19 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
#include "libc/intrin/spinlock.h"
#include "libc/intrin/pthread.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
hidden extern int __vforked;
hidden extern int __fds_lock_obj;
hidden extern int __sig_lock_obj;
hidden extern bool __time_critical;
hidden extern unsigned __sighandrvas[NSIG];
hidden extern unsigned __sighandflags[NSIG];
hidden extern pthread_mutex_t __sig_lock_obj;
hidden extern pthread_mutex_t __fds_lock_obj;
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
void __fds_lock(void);
#define __fds_unlock() _spunlock(&__fds_lock_obj)
#define __fds_lock() pthread_mutex_lock(&__fds_lock_obj)
#define __fds_unlock() pthread_mutex_unlock(&__fds_lock_obj)
#define __sig_lock() pthread_mutex_lock(&__sig_lock_obj)
#define __sig_unlock() pthread_mutex_unlock(&__sig_lock_obj)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -31,6 +31,7 @@
#include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
@ -169,7 +170,7 @@ struct ReportOriginHeap {
};
static int __asan_noreentry;
_Alignas(64) static int __asan_lock;
static pthread_mutex_t __asan_lock;
static struct AsanMorgue __asan_morgue;
#define __asan_unreachable() \
@ -852,25 +853,25 @@ dontdiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
void *__asan_morgue_add(void *p) {
int i;
void *r;
_spinlock_cooperative(&__asan_lock);
pthread_mutex_lock(&__asan_lock);
i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1);
r = __asan_morgue.p[i];
__asan_morgue.p[i] = p;
_spunlock(&__asan_lock);
pthread_mutex_unlock(&__asan_lock);
return r;
}
static void __asan_morgue_flush(void) {
int i;
void *p;
_spinlock_cooperative(&__asan_lock);
pthread_mutex_lock(&__asan_lock);
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
if (__asan_morgue.p[i] && weaken(dlfree)) {
weaken(dlfree)(__asan_morgue.p[i]);
}
__asan_morgue.p[i] = 0;
}
_spunlock(&__asan_lock);
pthread_mutex_unlock(&__asan_lock);
}
static size_t __asan_user_size(size_t n) {

View file

@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
@ -29,7 +30,7 @@
STATIC_YOINK("__cxa_finalize");
static int __cxa_lock;
static pthread_mutex_t __cxa_lock;
/**
* Adds global destructor.
@ -50,7 +51,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
unsigned i;
struct CxaAtexitBlock *b, *b2;
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
_spinlock(&__cxa_lock);
pthread_mutex_lock(&__cxa_lock);
b = __cxa_blocks.p;
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
if (!~b->mask) {
@ -59,7 +60,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
b2->next = b;
__cxa_blocks.p = b = b2;
} else {
_spunlock(&__cxa_lock);
pthread_mutex_unlock(&__cxa_lock);
return enomem();
}
}
@ -69,6 +70,6 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
b->p[i].fp = fp;
b->p[i].arg = arg;
b->p[i].pred = pred;
_spunlock(&__cxa_lock);
pthread_mutex_unlock(&__cxa_lock);
return 0;
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/pushpop.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
@ -26,11 +27,7 @@
STATIC_YOINK("_init_g_fds");
struct Fds g_fds;
_Alignas(64) int __fds_lock_obj;
void __fds_lock(void) {
_spinlock(&__fds_lock_obj);
}
pthread_mutex_t __fds_lock_obj;
textstartup void InitializeFileDescriptors(void) {
struct Fds *fds;

View file

@ -1,7 +1,7 @@
/*-*- 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
Copyright 2021 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,15 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/intrin/spinlock.h"
#include "libc/errno.h"
#include "libc/intrin/pthread.h"
void __sig_lock(void) {
_spinlock(&__sig_lock_obj);
int pthread_cancel(pthread_t thread) {
return ESRCH;
}
void __sig_unlock(void) {
_spunlock(&__sig_lock_obj);
void *__tls_get_addr(size_t v[2]) {
return NULL;
}

102
libc/intrin/pthread.h Normal file
View file

@ -0,0 +1,102 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define PTHREAD_ONCE_INIT 0
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_DEFAULT 0
#define PTHREAD_MUTEX_RECURSIVE 1
#define PTHREAD_MUTEX_ERRORCHECK 2
#define PTHREAD_MUTEX_STALLED 0
#define PTHREAD_MUTEX_ROBUST 1
/* clang-format off */
#define PTHREAD_MUTEX_INITIALIZER {0}
#define PTHREAD_RWLOCK_INITIALIZER {{{0}}}
#define PTHREAD_COND_INITIALIZER {{{0}}}
/* clang-format on */
typedef unsigned long *pthread_t;
typedef int pthread_once_t;
typedef struct {
int reent;
int owner;
int waits;
} pthread_mutex_t;
typedef struct {
unsigned __attr;
} pthread_mutexattr_t;
typedef struct {
unsigned __attr;
} pthread_condattr_t;
typedef struct {
unsigned __attr[2];
} pthread_rwlockattr_t;
typedef struct {
union {
int __i[9];
volatile int __vi[9];
unsigned __s[9];
} __u;
} pthread_attr_t;
typedef struct {
union {
int __i[12];
volatile int __vi[12];
void *__p[12];
} __u;
} pthread_cond_t;
typedef struct {
union {
int __i[8];
volatile int __vi[8];
void *__p[8];
} __u;
} pthread_rwlock_t;
wontreturn void pthread_exit(void *);
pureconst pthread_t pthread_self(void);
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *),
void *);
int pthread_detach(pthread_t);
int pthread_join(pthread_t, void **);
int pthread_equal(pthread_t, pthread_t);
int pthread_once(pthread_once_t *, void (*)(void));
int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_unlock(pthread_mutex_t *);
int pthread_mutex_trylock(pthread_mutex_t *);
int pthread_mutex_timedlock(pthread_mutex_t *, const struct timespec *);
int pthread_mutex_destroy(pthread_mutex_t *);
int pthread_mutex_consistent(pthread_mutex_t *);
int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
int pthread_cond_destroy(pthread_cond_t *);
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
int pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *,
const struct timespec *);
int pthread_cond_broadcast(pthread_cond_t *);
int pthread_cancel(pthread_t);
int pthread_cond_signal(pthread_cond_t *);
int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
int pthread_rwlock_destroy(pthread_rwlock_t *);
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_wrlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_unlock(pthread_rwlock_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ */

View file

@ -0,0 +1,51 @@
/*-*- 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/calls/calls.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/sysv/consts/futex.h"
/**
* Acquires mutex.
*/
int pthread_mutex_lock(pthread_mutex_t *mutex) {
int me, owner;
unsigned tries;
if (__threaded) {
for (tries = 0, me = gettid();;) {
owner = 0;
if (_lockcmpxchgp(&mutex->owner, &owner, me) || owner == me) {
break;
}
atomic_fetch_add(&mutex->waits, +1);
if (!IsLinux() || futex((void *)&mutex->owner, FUTEX_WAIT, owner, 0, 0)) {
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
atomic_fetch_add(&mutex->waits, -1);
}
}
++mutex->reent;
return 0;
}

View file

@ -0,0 +1,43 @@
/*-*- 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/calls.h"
#include "libc/errno.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h"
/**
* Tries to acquire mutex.
*/
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
int rc, me, owner = 0;
if (__threaded) {
me = gettid();
if (!_lockcmpxchgp(&mutex->owner, &owner, me) && owner == me) {
rc = 0;
++mutex->reent;
} else {
rc = EBUSY;
}
} else {
rc = 0;
++mutex->reent;
}
return rc;
}

View file

@ -0,0 +1,46 @@
/*-*- 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/assert.h"
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/sysv/consts/futex.h"
/**
* Releases mutex.
*/
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
int owner;
bool shouldunlock;
assert(mutex->reent > 0);
shouldunlock = --mutex->reent <= 0;
if (__threaded) {
assert(mutex->owner == gettid());
if (shouldunlock) {
atomic_store_explicit(&mutex->owner, 0, memory_order_relaxed);
if (IsLinux() &&
atomic_load_explicit(&mutex->waits, memory_order_acquire)) {
futex((void *)&mutex->owner, FUTEX_WAKE, 1, 0, 0);
}
}
}
return 0;
}

View file

@ -1,7 +1,7 @@
/*-*- 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 2021 Justine Alexandra Roberts Tunney
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
@ -18,14 +18,7 @@
*/
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/spinlock.h"
#include "libc/runtime/runtime.h"
typedef void *pthread_t;
typedef int pthread_once_t;
typedef int pthread_mutex_t;
#include "libc/intrin/pthread.h"
int pthread_once(pthread_once_t *once, void init(void)) {
int x;
@ -53,25 +46,3 @@ int pthread_once(pthread_once_t *once, void init(void)) {
}
return 0;
}
int pthread_mutex_lock(pthread_mutex_t *mutex) {
_spinlock(mutex);
return 0;
}
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
return _trylock(mutex);
}
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
_spunlock(mutex);
return 0;
}
int pthread_cancel(pthread_t thread) {
return ESRCH;
}
void *__tls_get_addr(size_t v[2]) {
return NULL;
}

View file

@ -1,99 +1,4 @@
#ifndef LIBC_ISYSTEM_PTHREAD_H_
#define LIBC_ISYSTEM_PTHREAD_H_
#include "libc/calls/calls.h"
#define PTHREAD_ONCE_INIT 0
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_DEFAULT 0
#define PTHREAD_MUTEX_RECURSIVE 1
#define PTHREAD_MUTEX_ERRORCHECK 2
#define PTHREAD_MUTEX_STALLED 0
#define PTHREAD_MUTEX_ROBUST 1
/* clang-format off */
#define PTHREAD_MUTEX_INITIALIZER {{{0}}}
#define PTHREAD_RWLOCK_INITIALIZER {{{0}}}
#define PTHREAD_COND_INITIALIZER {{{0}}}
/* clang-format on */
typedef unsigned long *pthread_t;
typedef int pthread_once_t;
typedef struct {
unsigned __attr;
} pthread_mutexattr_t;
typedef struct {
unsigned __attr;
} pthread_condattr_t;
typedef struct {
unsigned __attr[2];
} pthread_rwlockattr_t;
typedef struct {
union {
int __i[6];
volatile int __vi[6];
volatile void *volatile __p[6];
} __u;
} pthread_mutex_t;
typedef struct {
union {
int __i[9];
volatile int __vi[9];
unsigned __s[9];
} __u;
} pthread_attr_t;
typedef struct {
union {
int __i[12];
volatile int __vi[12];
void *__p[12];
} __u;
} pthread_cond_t;
typedef struct {
union {
int __i[8];
volatile int __vi[8];
void *__p[8];
} __u;
} pthread_rwlock_t;
wontreturn void pthread_exit(void *);
pureconst pthread_t pthread_self(void);
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *),
void *);
int pthread_detach(pthread_t);
int pthread_join(pthread_t, void **);
int pthread_equal(pthread_t, pthread_t);
int pthread_once(pthread_once_t *, void (*)(void));
int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_unlock(pthread_mutex_t *);
int pthread_mutex_trylock(pthread_mutex_t *);
int pthread_mutex_timedlock(pthread_mutex_t *, const struct timespec *);
int pthread_mutex_destroy(pthread_mutex_t *);
int pthread_mutex_consistent(pthread_mutex_t *);
int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
int pthread_cond_destroy(pthread_cond_t *);
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
int pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *,
const struct timespec *);
int pthread_cond_broadcast(pthread_cond_t *);
int pthread_cond_signal(pthread_cond_t *);
int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
int pthread_rwlock_destroy(pthread_rwlock_t *);
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_wrlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_unlock(pthread_rwlock_t *);
#include "libc/runtime/pthread.h"
#endif /* LIBC_ISYSTEM_PTHREAD_H_ */

View file

@ -78,6 +78,9 @@ static void vflogf_onfail(FILE *f) {
*
* In that case, the second log entry will always display the amount of
* time that it took to connect. This is great in forking applications.
*
* @asyncsignalsafe
* @threadsafe
*/
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
const char *fmt, va_list va) {

View file

@ -3,6 +3,7 @@
#include "libc/assert.h"
#include "libc/bits/midpoint.h"
#include "libc/dce.h"
#include "libc/intrin/pthread.h"
#include "libc/macros.internal.h"
#include "libc/nt/version.h"
#include "libc/runtime/stack.h"
@ -30,6 +31,9 @@ COSMOPOLITAN_C_START_
#define _kMem(NORMAL, WIN7) \
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
#define __mmi_lock() pthread_mutex_lock(&_mmi.lock)
#define __mmi_unlock() pthread_mutex_unlock(&_mmi.lock)
struct MemoryInterval {
int x;
int y;
@ -46,7 +50,7 @@ struct MemoryIntervals {
size_t i, n;
struct MemoryInterval *p;
struct MemoryInterval s[OPEN_MAX];
_Alignas(64) int lock;
pthread_mutex_t lock;
};
extern hidden struct MemoryIntervals _mmi;

View file

@ -31,6 +31,7 @@
#include "libc/intrin/asancodes.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
@ -404,13 +405,11 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
if (p != MAP_FAILED) {
if (needguard) {
if (IsWindows()) _spunlock(&_mmi.lock);
mprotect(p, PAGESIZE, PROT_NONE);
if (IsAsan()) {
__repstosb((void *)(((intptr_t)p >> 3) + 0x7fff8000),
kAsanStackOverflow, PAGESIZE / 8);
}
if (IsWindows()) _spinlock(&_mmi.lock);
}
}
@ -479,12 +478,12 @@ noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) {
void *res;
size_t toto;
_spinlock(&_mmi.lock);
__mmi_lock();
res = Mmap(addr, size, prot, flags, fd, off);
#if SYSDEBUG
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
#endif
_spunlock(&_mmi.lock);
__mmi_unlock();
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m (%'zu bytes total)", addr,
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res,
toto);

View file

@ -29,7 +29,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
unsigned i;
uint32_t op;
char *a, *b, *x, *y, *p;
_spinlock(&_mmi.lock);
__mmi_lock();
p = addr;
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) {
@ -58,6 +58,6 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
}
}
}
_spunlock(&_mmi.lock);
__mmi_unlock();
return rc;
}

View file

@ -31,7 +31,7 @@
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int i, rc = 0;
char *a, *b, *x, *y;
_spinlock(&_mmi.lock);
__mmi_lock();
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
x = ADDR(_mmi.p[i].x);
y = x + _mmi.p[i].size;
@ -48,6 +48,6 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
break;
}
}
_spunlock(&_mmi.lock);
__mmi_unlock();
return rc;
}

View file

@ -164,12 +164,12 @@ static noasan int Munmap(char *p, size_t n) {
noasan int munmap(void *p, size_t n) {
int rc;
size_t toto;
_spinlock(&_mmi.lock);
__mmi_lock();
rc = Munmap(p, n);
#if SYSDEBUG
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
#endif
_spunlock(&_mmi.lock);
__mmi_unlock();
STRACE("munmap(%.12p, %'zu) → %d% m (%'zu bytes total)", p, n, rc, toto);
return rc;
}

View file

@ -24,7 +24,7 @@
* Prints memory mappings to stderr.
*/
void __print_maps(void) {
_spinlock(&_mmi.lock);
__mmi_lock();
PrintMemoryIntervals(2, &_mmi);
_spunlock(&_mmi.lock);
__mmi_unlock();
}

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
#define COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
#include "libc/intrin/pthread.h"
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -10,7 +11,7 @@ struct StdioFlushHandles {
};
struct StdioFlush {
int lock;
pthread_mutex_t lock;
struct StdioFlushHandles handles;
FILE *handles_initmem[8];
};

View file

@ -21,6 +21,7 @@
#include "libc/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
@ -40,7 +41,7 @@ int fflush_unlocked(FILE *f) {
int rc = 0;
size_t i;
if (!f) {
_spinlock(&__fflush.lock);
pthread_mutex_lock(&__fflush.lock);
for (i = __fflush.handles.i; i; --i) {
if ((f = __fflush.handles.p[i - 1])) {
if (fflush(f) == -1) {
@ -48,7 +49,7 @@ int fflush_unlocked(FILE *f) {
}
}
}
_spunlock(&__fflush.lock);
pthread_mutex_unlock(&__fflush.lock);
} else if (f->fd != -1) {
if (__fflush_impl(f) == -1) {
rc = -1;
@ -63,7 +64,7 @@ textstartup int __fflush_register(FILE *f) {
int rc;
size_t i;
struct StdioFlush *sf;
_spinlock(&__fflush.lock);
pthread_mutex_lock(&__fflush.lock);
sf = &__fflush;
if (!sf->handles.p) {
sf->handles.p = sf->handles_initmem;
@ -73,19 +74,19 @@ textstartup int __fflush_register(FILE *f) {
for (i = sf->handles.i; i; --i) {
if (!sf->handles.p[i - 1]) {
sf->handles.p[i - 1] = f;
_spunlock(&__fflush.lock);
pthread_mutex_unlock(&__fflush.lock);
return 0;
}
}
rc = append(&sf->handles, &f);
_spunlock(&__fflush.lock);
pthread_mutex_unlock(&__fflush.lock);
return rc;
}
void __fflush_unregister(FILE *f) {
size_t i;
struct StdioFlush *sf;
_spinlock(&__fflush.lock);
pthread_mutex_lock(&__fflush.lock);
sf = &__fflush;
sf = pushpop(sf);
for (i = sf->handles.i; i; --i) {
@ -94,5 +95,5 @@ void __fflush_unregister(FILE *f) {
break;
}
}
_spunlock(&__fflush.lock);
pthread_mutex_unlock(&__fflush.lock);
}

View file

@ -16,30 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h"
/**
* Acquires reentrant lock on stdio object, blocking if needed.
*/
void flockfile(FILE *f) {
int me, owner;
unsigned tries;
if (__threaded) {
for (tries = 0, me = gettid();;) {
owner = 0;
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
break;
}
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
}
++f->reent;
pthread_mutex_lock(&f->lock);
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/stdio/fflush.internal.h"
#include "libc/stdio/stdio.h"
@ -28,7 +29,7 @@
void _flushlbf(void) {
int i;
FILE *f;
_spinlock(&__fflush.lock);
pthread_mutex_lock(&__fflush.lock);
for (i = 0; i < __fflush.handles.i; ++i) {
if ((f = __fflush.handles.p[i])) {
flockfile(f);
@ -38,5 +39,5 @@ void _flushlbf(void) {
funlockfile(f);
}
}
_spunlock(&__fflush.lock);
pthread_mutex_unlock(&__fflush.lock);
}

View file

@ -16,9 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h"
/**
@ -27,15 +24,5 @@
* @return 0 on success, or non-zero if another thread owns the lock
*/
int ftrylockfile(FILE *f) {
int me, owner = 0;
if (__threaded) {
me = gettid();
if (!_lockcmpxchgp(&f->lock, &owner, me) && owner == me) {
owner = 0;
}
}
if (!owner) {
++f->reent;
}
return owner;
return pthread_mutex_trylock(&f->lock);
}

View file

@ -16,24 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h"
/**
* Releases lock on stdio object.
*/
void funlockfile(FILE *f) {
int owner;
bool shouldunlock;
assert(f->reent > 0);
shouldunlock = --f->reent <= 0;
if (__threaded) {
assert(f->lock == gettid());
if (shouldunlock) {
owner = 0;
__atomic_store(&f->lock, &owner, __ATOMIC_RELAXED);
}
}
pthread_mutex_unlock(&f->lock);
}

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_STDIO_H_
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
#include "libc/fmt/pflink.h"
#include "libc/intrin/pthread.h"
#include "libc/runtime/symbolic.h"
#define FILENAME_MAX PATH_MAX
@ -24,9 +25,8 @@ typedef struct FILE {
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
int lock; /* 0x2c */
int reent; /* 0x30 */
char *getln; /* 0x38 */
char *getln;
pthread_mutex_t lock;
} FILE;
extern FILE *stdin;

View file

@ -4,6 +4,7 @@
#define LOCALTIME_IMPLEMENTATION
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
@ -42,15 +43,15 @@ STATIC_YOINK("usr/share/zoneinfo/UTC");
** POSIX-style TZ environment variable handling from Guy Harris.
*/
_Alignas(64) static int locallock;
static pthread_mutex_t locallock;
static int lock(void) {
_spinlock(&locallock);
pthread_mutex_lock(&locallock);
return 0;
}
static void unlock(void) {
_spunlock(&locallock);
pthread_mutex_unlock(&locallock);
}
#ifndef TZ_ABBR_MAX_LEN

View file

@ -23,7 +23,9 @@
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
@ -74,13 +76,10 @@ struct Zipos *__zipos_get(void) {
const char *progpath;
static struct Zipos zipos;
uint8_t *map, *base, *cdir;
_Alignas(64) static int lock;
_spinlock(&lock);
if (!once) {
static pthread_mutex_t lock;
pthread_mutex_lock(&lock);
if (_cmpxchg(&once, false, true)) {
sigfillset(&neu);
if (!IsWindows()) {
sys_sigprocmask(SIG_BLOCK, &neu, &old);
}
progpath = GetProgramExecutableName();
if ((fd = open(progpath, O_RDONLY)) != -1) {
if ((size = getfiledescriptorsize(fd)) != SIZE_MAX &&
@ -104,16 +103,12 @@ struct Zipos *__zipos_get(void) {
} else {
STRACE("__zipos_get(%#s) → open failed %m", progpath);
}
if (!IsWindows()) {
sigprocmask(SIG_SETMASK, &old, 0);
}
once = true;
}
if (zipos.cdir) {
res = &zipos;
} else {
res = 0;
}
_spunlock(&lock);
pthread_mutex_unlock(&lock);
return res;
}

View file

@ -0,0 +1,43 @@
/*-*- 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/intrin/pthread.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
static void *DoNothing(void *arg) {
return 0;
}
static void MakeSureThreadingModeIsEnabled(void) {
void *exitcode;
cthread_t thread;
ASSERT_EQ(0, cthread_create(&thread, 0, DoNothing, 0));
ASSERT_EQ(0, cthread_join(thread, 0));
}
void SetUp(void) {
MakeSureThreadingModeIsEnabled();
}
BENCH(pthread_mutex_lock, bench) {
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
EZBENCH2("pthread_mutex_lock", donothing,
(pthread_mutex_lock(&lock), pthread_mutex_unlock(&lock)));
}

View file

@ -36,6 +36,7 @@ TEST_LIBC_INTRIN_DIRECTDEPS = \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TESTLIB \
LIBC_THREAD \
LIBC_TINYMATH \
LIBC_UNICODE \
LIBC_X \

View file

@ -223,7 +223,6 @@ TEST(mmap, cow) {
char *p;
char path[PATH_MAX];
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
kprintf("path = %#s\n", path);
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
EXPECT_EQ(5, write(fd, "hello", 5));
EXPECT_NE(-1, fdatasync(fd));

View file

@ -37,7 +37,6 @@ TEST(cthread_create, testJoinDeadlock) {
}
TEST(cthread_create, testCreateReturnJoin) {
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
void *exitcode;
cthread_t thread;
ASSERT_EQ(0, cthread_create(&thread, 0, ReturnArg, ReturnArg));
@ -50,7 +49,6 @@ static void *ExitArg(void *arg) {
}
TEST(cthread_create, testCreateExitJoin) {
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
void *exitcode;
cthread_t thread;
ASSERT_EQ(0, cthread_create(&thread, 0, ExitArg, (void *)-31337));
@ -61,7 +59,6 @@ TEST(cthread_create, testCreateExitJoin) {
TEST(gcctls, size) {
if (IsXnu()) return; // TODO(jart): codemorph
if (IsWindows()) return; // TODO(jart): codemorph
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
// schlep in .zip section too
// make sure executable isn't too huge
size_t size;
@ -87,7 +84,6 @@ static void *TlsWorker(void *arg) {
TEST(gcctls, worksAndIsNonInheritable) {
if (IsXnu()) return; // TODO(jart): codemorph
if (IsWindows()) return; // TODO(jart): codemorph
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
void *exitcode;
cthread_t thread;
ASSERT_EQ(tdata, 31337);

View file

@ -6496,14 +6496,14 @@ static int MemoryMonitor(void *arg) {
mi[2].x = (intptr_t)_edata >> 16;
mi[2].size = _end - _edata;
mi[2].flags = 0;
_spinlock(&_mmi.lock);
__mmi_lock();
if (_mmi.i == intervals - 3) {
memcpy(mi + 3, _mmi.p, _mmi.i * sizeof(*mi));
ok = true;
} else {
ok = false;
}
_spunlock(&_mmi.lock);
__mmi_unlock();
if (!ok) {
VERBOSEF("(memv) retrying due to contention on mmap table");
continue;