mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
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:
parent
5ea618f0af
commit
c260345e06
35 changed files with 369 additions and 258 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
102
libc/intrin/pthread.h
Normal 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_ */
|
51
libc/intrin/pthread_mutex_lock.c
Normal file
51
libc/intrin/pthread_mutex_lock.c
Normal 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;
|
||||
}
|
43
libc/intrin/pthread_mutex_trylock.c
Normal file
43
libc/intrin/pthread_mutex_trylock.c
Normal 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;
|
||||
}
|
46
libc/intrin/pthread_mutex_unlock.c
Normal file
46
libc/intrin/pthread_mutex_unlock.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
43
test/libc/intrin/pthread_mutex_lock_test.c
Normal file
43
test/libc/intrin/pthread_mutex_lock_test.c
Normal 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)));
|
||||
}
|
|
@ -36,6 +36,7 @@ TEST_LIBC_INTRIN_DIRECTDEPS = \
|
|||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue