mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 15:03:34 +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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
|
|
||||||
unsigned __sighandrvas[NSIG];
|
unsigned __sighandrvas[NSIG];
|
||||||
unsigned __sighandflags[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/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
_Alignas(64) static int poll_lock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polls on the New Technology.
|
* 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
|
// do the planning
|
||||||
// we need to read static variables
|
// we need to read static variables
|
||||||
// we might need to spawn threads and open pipes
|
// we might need to spawn threads and open pipes
|
||||||
_spinlock(&poll_lock);
|
|
||||||
__fds_lock();
|
__fds_lock();
|
||||||
for (gotinvals = failed = sn = pn = i = 0; i < nfds; ++i) {
|
for (gotinvals = failed = sn = pn = i = 0; i < nfds; ++i) {
|
||||||
if (fds[i].fd < 0) continue;
|
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();
|
__fds_unlock();
|
||||||
_spunlock(&poll_lock);
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
// failed to create a polling solution
|
// failed to create a polling solution
|
||||||
return failed;
|
return failed;
|
||||||
|
|
|
@ -23,11 +23,9 @@ struct Signals {
|
||||||
struct Signal mem[__SIG_QUEUE_LENGTH];
|
struct Signal mem[__SIG_QUEUE_LENGTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct Signals __sig; // TODO(jart): Need TLS
|
|
||||||
extern long __sig_count;
|
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_check(bool) hidden;
|
||||||
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
|
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
|
||||||
int __sig_add(int, int) hidden;
|
int __sig_add(int, int) hidden;
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
|
||||||
#define 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)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
hidden extern int __vforked;
|
hidden extern int __vforked;
|
||||||
hidden extern int __fds_lock_obj;
|
|
||||||
hidden extern int __sig_lock_obj;
|
|
||||||
hidden extern bool __time_critical;
|
hidden extern bool __time_critical;
|
||||||
hidden extern unsigned __sighandrvas[NSIG];
|
hidden extern unsigned __sighandrvas[NSIG];
|
||||||
hidden extern unsigned __sighandflags[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;
|
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||||
|
|
||||||
void __fds_lock(void);
|
#define __fds_lock() pthread_mutex_lock(&__fds_lock_obj)
|
||||||
#define __fds_unlock() _spunlock(&__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_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/intrin/lockcmpxchg.h"
|
#include "libc/intrin/lockcmpxchg.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
|
@ -169,7 +170,7 @@ struct ReportOriginHeap {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __asan_noreentry;
|
static int __asan_noreentry;
|
||||||
_Alignas(64) static int __asan_lock;
|
static pthread_mutex_t __asan_lock;
|
||||||
static struct AsanMorgue __asan_morgue;
|
static struct AsanMorgue __asan_morgue;
|
||||||
|
|
||||||
#define __asan_unreachable() \
|
#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) {
|
void *__asan_morgue_add(void *p) {
|
||||||
int i;
|
int i;
|
||||||
void *r;
|
void *r;
|
||||||
_spinlock_cooperative(&__asan_lock);
|
pthread_mutex_lock(&__asan_lock);
|
||||||
i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1);
|
i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1);
|
||||||
r = __asan_morgue.p[i];
|
r = __asan_morgue.p[i];
|
||||||
__asan_morgue.p[i] = p;
|
__asan_morgue.p[i] = p;
|
||||||
_spunlock(&__asan_lock);
|
pthread_mutex_unlock(&__asan_lock);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __asan_morgue_flush(void) {
|
static void __asan_morgue_flush(void) {
|
||||||
int i;
|
int i;
|
||||||
void *p;
|
void *p;
|
||||||
_spinlock_cooperative(&__asan_lock);
|
pthread_mutex_lock(&__asan_lock);
|
||||||
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
||||||
if (__asan_morgue.p[i] && weaken(dlfree)) {
|
if (__asan_morgue.p[i] && weaken(dlfree)) {
|
||||||
weaken(dlfree)(__asan_morgue.p[i]);
|
weaken(dlfree)(__asan_morgue.p[i]);
|
||||||
}
|
}
|
||||||
__asan_morgue.p[i] = 0;
|
__asan_morgue.p[i] = 0;
|
||||||
}
|
}
|
||||||
_spunlock(&__asan_lock);
|
pthread_mutex_unlock(&__asan_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t __asan_user_size(size_t n) {
|
static size_t __asan_user_size(size_t n) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
|
|
||||||
STATIC_YOINK("__cxa_finalize");
|
STATIC_YOINK("__cxa_finalize");
|
||||||
|
|
||||||
static int __cxa_lock;
|
static pthread_mutex_t __cxa_lock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds global destructor.
|
* Adds global destructor.
|
||||||
|
@ -50,7 +51,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
||||||
_spinlock(&__cxa_lock);
|
pthread_mutex_lock(&__cxa_lock);
|
||||||
b = __cxa_blocks.p;
|
b = __cxa_blocks.p;
|
||||||
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
|
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
|
||||||
if (!~b->mask) {
|
if (!~b->mask) {
|
||||||
|
@ -59,7 +60,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
b2->next = b;
|
b2->next = b;
|
||||||
__cxa_blocks.p = b = b2;
|
__cxa_blocks.p = b = b2;
|
||||||
} else {
|
} else {
|
||||||
_spunlock(&__cxa_lock);
|
pthread_mutex_unlock(&__cxa_lock);
|
||||||
return enomem();
|
return enomem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +70,6 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
b->p[i].fp = fp;
|
b->p[i].fp = fp;
|
||||||
b->p[i].arg = arg;
|
b->p[i].arg = arg;
|
||||||
b->p[i].pred = pred;
|
b->p[i].pred = pred;
|
||||||
_spunlock(&__cxa_lock);
|
pthread_mutex_unlock(&__cxa_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/bits/pushpop.h"
|
#include "libc/bits/pushpop.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
@ -26,11 +27,7 @@
|
||||||
STATIC_YOINK("_init_g_fds");
|
STATIC_YOINK("_init_g_fds");
|
||||||
|
|
||||||
struct Fds g_fds;
|
struct Fds g_fds;
|
||||||
_Alignas(64) int __fds_lock_obj;
|
pthread_mutex_t __fds_lock_obj;
|
||||||
|
|
||||||
void __fds_lock(void) {
|
|
||||||
_spinlock(&__fds_lock_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
textstartup void InitializeFileDescriptors(void) {
|
textstartup void InitializeFileDescriptors(void) {
|
||||||
struct Fds *fds;
|
struct Fds *fds;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│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 │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ 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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/calls/state.internal.h"
|
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
|
|
||||||
void __sig_lock(void) {
|
int pthread_cancel(pthread_t thread) {
|
||||||
_spinlock(&__sig_lock_obj);
|
return ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __sig_unlock(void) {
|
void *__tls_get_addr(size_t v[2]) {
|
||||||
_spunlock(&__sig_lock_obj);
|
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 -*-│
|
/*-*- 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│
|
│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 │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -18,14 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/atomic.h"
|
#include "libc/bits/atomic.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/intrin/pthread.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;
|
|
||||||
|
|
||||||
int pthread_once(pthread_once_t *once, void init(void)) {
|
int pthread_once(pthread_once_t *once, void init(void)) {
|
||||||
int x;
|
int x;
|
||||||
|
@ -53,25 +46,3 @@ int pthread_once(pthread_once_t *once, void init(void)) {
|
||||||
}
|
}
|
||||||
return 0;
|
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_
|
#ifndef LIBC_ISYSTEM_PTHREAD_H_
|
||||||
#define LIBC_ISYSTEM_PTHREAD_H_
|
#define LIBC_ISYSTEM_PTHREAD_H_
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/runtime/pthread.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 *);
|
|
||||||
|
|
||||||
#endif /* LIBC_ISYSTEM_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
|
* 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.
|
* 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,
|
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||||
const char *fmt, va_list va) {
|
const char *fmt, va_list va) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/midpoint.h"
|
#include "libc/bits/midpoint.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/version.h"
|
#include "libc/nt/version.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
|
@ -30,6 +31,9 @@ COSMOPOLITAN_C_START_
|
||||||
#define _kMem(NORMAL, WIN7) \
|
#define _kMem(NORMAL, WIN7) \
|
||||||
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
|
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
|
||||||
|
|
||||||
|
#define __mmi_lock() pthread_mutex_lock(&_mmi.lock)
|
||||||
|
#define __mmi_unlock() pthread_mutex_unlock(&_mmi.lock)
|
||||||
|
|
||||||
struct MemoryInterval {
|
struct MemoryInterval {
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
@ -46,7 +50,7 @@ struct MemoryIntervals {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
struct MemoryInterval *p;
|
struct MemoryInterval *p;
|
||||||
struct MemoryInterval s[OPEN_MAX];
|
struct MemoryInterval s[OPEN_MAX];
|
||||||
_Alignas(64) int lock;
|
pthread_mutex_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern hidden struct MemoryIntervals _mmi;
|
extern hidden struct MemoryIntervals _mmi;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "libc/intrin/asancodes.h"
|
#include "libc/intrin/asancodes.h"
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/backtrace.internal.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 (p != MAP_FAILED) {
|
||||||
if (needguard) {
|
if (needguard) {
|
||||||
if (IsWindows()) _spunlock(&_mmi.lock);
|
|
||||||
mprotect(p, PAGESIZE, PROT_NONE);
|
mprotect(p, PAGESIZE, PROT_NONE);
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
__repstosb((void *)(((intptr_t)p >> 3) + 0x7fff8000),
|
__repstosb((void *)(((intptr_t)p >> 3) + 0x7fff8000),
|
||||||
kAsanStackOverflow, PAGESIZE / 8);
|
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) {
|
int64_t off) {
|
||||||
void *res;
|
void *res;
|
||||||
size_t toto;
|
size_t toto;
|
||||||
_spinlock(&_mmi.lock);
|
__mmi_lock();
|
||||||
res = Mmap(addr, size, prot, flags, fd, off);
|
res = Mmap(addr, size, prot, flags, fd, off);
|
||||||
#if SYSDEBUG
|
#if SYSDEBUG
|
||||||
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
|
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
|
||||||
#endif
|
#endif
|
||||||
_spunlock(&_mmi.lock);
|
__mmi_unlock();
|
||||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m (%'zu bytes total)", addr,
|
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m (%'zu bytes total)", addr,
|
||||||
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res,
|
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res,
|
||||||
toto);
|
toto);
|
||||||
|
|
|
@ -29,7 +29,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
uint32_t op;
|
uint32_t op;
|
||||||
char *a, *b, *x, *y, *p;
|
char *a, *b, *x, *y, *p;
|
||||||
_spinlock(&_mmi.lock);
|
__mmi_lock();
|
||||||
p = addr;
|
p = addr;
|
||||||
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
|
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
|
||||||
if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) {
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
char *a, *b, *x, *y;
|
char *a, *b, *x, *y;
|
||||||
_spinlock(&_mmi.lock);
|
__mmi_lock();
|
||||||
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
|
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
|
||||||
x = ADDR(_mmi.p[i].x);
|
x = ADDR(_mmi.p[i].x);
|
||||||
y = x + _mmi.p[i].size;
|
y = x + _mmi.p[i].size;
|
||||||
|
@ -48,6 +48,6 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_spunlock(&_mmi.lock);
|
__mmi_unlock();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,12 +164,12 @@ static noasan int Munmap(char *p, size_t n) {
|
||||||
noasan int munmap(void *p, size_t n) {
|
noasan int munmap(void *p, size_t n) {
|
||||||
int rc;
|
int rc;
|
||||||
size_t toto;
|
size_t toto;
|
||||||
_spinlock(&_mmi.lock);
|
__mmi_lock();
|
||||||
rc = Munmap(p, n);
|
rc = Munmap(p, n);
|
||||||
#if SYSDEBUG
|
#if SYSDEBUG
|
||||||
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
|
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
|
||||||
#endif
|
#endif
|
||||||
_spunlock(&_mmi.lock);
|
__mmi_unlock();
|
||||||
STRACE("munmap(%.12p, %'zu) → %d% m (%'zu bytes total)", p, n, rc, toto);
|
STRACE("munmap(%.12p, %'zu) → %d% m (%'zu bytes total)", p, n, rc, toto);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
* Prints memory mappings to stderr.
|
* Prints memory mappings to stderr.
|
||||||
*/
|
*/
|
||||||
void __print_maps(void) {
|
void __print_maps(void) {
|
||||||
_spinlock(&_mmi.lock);
|
__mmi_lock();
|
||||||
PrintMemoryIntervals(2, &_mmi);
|
PrintMemoryIntervals(2, &_mmi);
|
||||||
_spunlock(&_mmi.lock);
|
__mmi_unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
|
#ifndef COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
|
||||||
#define COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
|
#define COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
@ -10,7 +11,7 @@ struct StdioFlushHandles {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StdioFlush {
|
struct StdioFlush {
|
||||||
int lock;
|
pthread_mutex_t lock;
|
||||||
struct StdioFlushHandles handles;
|
struct StdioFlushHandles handles;
|
||||||
FILE *handles_initmem[8];
|
FILE *handles_initmem[8];
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "libc/bits/pushpop.h"
|
#include "libc/bits/pushpop.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -40,7 +41,7 @@ int fflush_unlocked(FILE *f) {
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
if (!f) {
|
if (!f) {
|
||||||
_spinlock(&__fflush.lock);
|
pthread_mutex_lock(&__fflush.lock);
|
||||||
for (i = __fflush.handles.i; i; --i) {
|
for (i = __fflush.handles.i; i; --i) {
|
||||||
if ((f = __fflush.handles.p[i - 1])) {
|
if ((f = __fflush.handles.p[i - 1])) {
|
||||||
if (fflush(f) == -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) {
|
} else if (f->fd != -1) {
|
||||||
if (__fflush_impl(f) == -1) {
|
if (__fflush_impl(f) == -1) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
@ -63,7 +64,7 @@ textstartup int __fflush_register(FILE *f) {
|
||||||
int rc;
|
int rc;
|
||||||
size_t i;
|
size_t i;
|
||||||
struct StdioFlush *sf;
|
struct StdioFlush *sf;
|
||||||
_spinlock(&__fflush.lock);
|
pthread_mutex_lock(&__fflush.lock);
|
||||||
sf = &__fflush;
|
sf = &__fflush;
|
||||||
if (!sf->handles.p) {
|
if (!sf->handles.p) {
|
||||||
sf->handles.p = sf->handles_initmem;
|
sf->handles.p = sf->handles_initmem;
|
||||||
|
@ -73,19 +74,19 @@ textstartup int __fflush_register(FILE *f) {
|
||||||
for (i = sf->handles.i; i; --i) {
|
for (i = sf->handles.i; i; --i) {
|
||||||
if (!sf->handles.p[i - 1]) {
|
if (!sf->handles.p[i - 1]) {
|
||||||
sf->handles.p[i - 1] = f;
|
sf->handles.p[i - 1] = f;
|
||||||
_spunlock(&__fflush.lock);
|
pthread_mutex_unlock(&__fflush.lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = append(&sf->handles, &f);
|
rc = append(&sf->handles, &f);
|
||||||
_spunlock(&__fflush.lock);
|
pthread_mutex_unlock(&__fflush.lock);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __fflush_unregister(FILE *f) {
|
void __fflush_unregister(FILE *f) {
|
||||||
size_t i;
|
size_t i;
|
||||||
struct StdioFlush *sf;
|
struct StdioFlush *sf;
|
||||||
_spinlock(&__fflush.lock);
|
pthread_mutex_lock(&__fflush.lock);
|
||||||
sf = &__fflush;
|
sf = &__fflush;
|
||||||
sf = pushpop(sf);
|
sf = pushpop(sf);
|
||||||
for (i = sf->handles.i; i; --i) {
|
for (i = sf->handles.i; i; --i) {
|
||||||
|
@ -94,5 +95,5 @@ void __fflush_unregister(FILE *f) {
|
||||||
break;
|
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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acquires reentrant lock on stdio object, blocking if needed.
|
* Acquires reentrant lock on stdio object, blocking if needed.
|
||||||
*/
|
*/
|
||||||
void flockfile(FILE *f) {
|
void flockfile(FILE *f) {
|
||||||
int me, owner;
|
pthread_mutex_lock(&f->lock);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/stdio/fflush.internal.h"
|
#include "libc/stdio/fflush.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
void _flushlbf(void) {
|
void _flushlbf(void) {
|
||||||
int i;
|
int i;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
_spinlock(&__fflush.lock);
|
pthread_mutex_lock(&__fflush.lock);
|
||||||
for (i = 0; i < __fflush.handles.i; ++i) {
|
for (i = 0; i < __fflush.handles.i; ++i) {
|
||||||
if ((f = __fflush.handles.p[i])) {
|
if ((f = __fflush.handles.p[i])) {
|
||||||
flockfile(f);
|
flockfile(f);
|
||||||
|
@ -38,5 +39,5 @@ void _flushlbf(void) {
|
||||||
funlockfile(f);
|
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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/intrin/lockcmpxchgp.h"
|
|
||||||
#include "libc/nexgen32e/threaded.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,15 +24,5 @@
|
||||||
* @return 0 on success, or non-zero if another thread owns the lock
|
* @return 0 on success, or non-zero if another thread owns the lock
|
||||||
*/
|
*/
|
||||||
int ftrylockfile(FILE *f) {
|
int ftrylockfile(FILE *f) {
|
||||||
int me, owner = 0;
|
return pthread_mutex_trylock(&f->lock);
|
||||||
if (__threaded) {
|
|
||||||
me = gettid();
|
|
||||||
if (!_lockcmpxchgp(&f->lock, &owner, me) && owner == me) {
|
|
||||||
owner = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!owner) {
|
|
||||||
++f->reent;
|
|
||||||
}
|
|
||||||
return owner;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,24 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/nexgen32e/threaded.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases lock on stdio object.
|
* Releases lock on stdio object.
|
||||||
*/
|
*/
|
||||||
void funlockfile(FILE *f) {
|
void funlockfile(FILE *f) {
|
||||||
int owner;
|
pthread_mutex_unlock(&f->lock);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_STDIO_STDIO_H_
|
#ifndef COSMOPOLITAN_LIBC_STDIO_STDIO_H_
|
||||||
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
|
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
|
||||||
#include "libc/fmt/pflink.h"
|
#include "libc/fmt/pflink.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/runtime/symbolic.h"
|
#include "libc/runtime/symbolic.h"
|
||||||
|
|
||||||
#define FILENAME_MAX PATH_MAX
|
#define FILENAME_MAX PATH_MAX
|
||||||
|
@ -24,9 +25,8 @@ typedef struct FILE {
|
||||||
uint32_t size; /* 0x20 */
|
uint32_t size; /* 0x20 */
|
||||||
uint32_t nofree; /* 0x24 */
|
uint32_t nofree; /* 0x24 */
|
||||||
int pid; /* 0x28 */
|
int pid; /* 0x28 */
|
||||||
int lock; /* 0x2c */
|
char *getln;
|
||||||
int reent; /* 0x30 */
|
pthread_mutex_t lock;
|
||||||
char *getln; /* 0x38 */
|
|
||||||
} FILE;
|
} FILE;
|
||||||
|
|
||||||
extern FILE *stdin;
|
extern FILE *stdin;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#define LOCALTIME_IMPLEMENTATION
|
#define LOCALTIME_IMPLEMENTATION
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/gc.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.
|
** POSIX-style TZ environment variable handling from Guy Harris.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_Alignas(64) static int locallock;
|
static pthread_mutex_t locallock;
|
||||||
|
|
||||||
static int lock(void) {
|
static int lock(void) {
|
||||||
_spinlock(&locallock);
|
pthread_mutex_lock(&locallock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unlock(void) {
|
static void unlock(void) {
|
||||||
_spunlock(&locallock);
|
pthread_mutex_unlock(&locallock);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TZ_ABBR_MAX_LEN
|
#ifndef TZ_ABBR_MAX_LEN
|
||||||
|
|
|
@ -23,7 +23,9 @@
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/cmpxchg.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/pthread.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -74,13 +76,10 @@ struct Zipos *__zipos_get(void) {
|
||||||
const char *progpath;
|
const char *progpath;
|
||||||
static struct Zipos zipos;
|
static struct Zipos zipos;
|
||||||
uint8_t *map, *base, *cdir;
|
uint8_t *map, *base, *cdir;
|
||||||
_Alignas(64) static int lock;
|
static pthread_mutex_t lock;
|
||||||
_spinlock(&lock);
|
pthread_mutex_lock(&lock);
|
||||||
if (!once) {
|
if (_cmpxchg(&once, false, true)) {
|
||||||
sigfillset(&neu);
|
sigfillset(&neu);
|
||||||
if (!IsWindows()) {
|
|
||||||
sys_sigprocmask(SIG_BLOCK, &neu, &old);
|
|
||||||
}
|
|
||||||
progpath = GetProgramExecutableName();
|
progpath = GetProgramExecutableName();
|
||||||
if ((fd = open(progpath, O_RDONLY)) != -1) {
|
if ((fd = open(progpath, O_RDONLY)) != -1) {
|
||||||
if ((size = getfiledescriptorsize(fd)) != SIZE_MAX &&
|
if ((size = getfiledescriptorsize(fd)) != SIZE_MAX &&
|
||||||
|
@ -104,16 +103,12 @@ struct Zipos *__zipos_get(void) {
|
||||||
} else {
|
} else {
|
||||||
STRACE("__zipos_get(%#s) → open failed %m", progpath);
|
STRACE("__zipos_get(%#s) → open failed %m", progpath);
|
||||||
}
|
}
|
||||||
if (!IsWindows()) {
|
|
||||||
sigprocmask(SIG_SETMASK, &old, 0);
|
|
||||||
}
|
|
||||||
once = true;
|
|
||||||
}
|
}
|
||||||
if (zipos.cdir) {
|
if (zipos.cdir) {
|
||||||
res = &zipos;
|
res = &zipos;
|
||||||
} else {
|
} else {
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
_spunlock(&lock);
|
pthread_mutex_unlock(&lock);
|
||||||
return res;
|
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_STUBS \
|
||||||
LIBC_SYSV \
|
LIBC_SYSV \
|
||||||
LIBC_TESTLIB \
|
LIBC_TESTLIB \
|
||||||
|
LIBC_THREAD \
|
||||||
LIBC_TINYMATH \
|
LIBC_TINYMATH \
|
||||||
LIBC_UNICODE \
|
LIBC_UNICODE \
|
||||||
LIBC_X \
|
LIBC_X \
|
||||||
|
|
|
@ -223,7 +223,6 @@ TEST(mmap, cow) {
|
||||||
char *p;
|
char *p;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
|
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)));
|
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
|
||||||
EXPECT_EQ(5, write(fd, "hello", 5));
|
EXPECT_EQ(5, write(fd, "hello", 5));
|
||||||
EXPECT_NE(-1, fdatasync(fd));
|
EXPECT_NE(-1, fdatasync(fd));
|
||||||
|
|
|
@ -37,7 +37,6 @@ TEST(cthread_create, testJoinDeadlock) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(cthread_create, testCreateReturnJoin) {
|
TEST(cthread_create, testCreateReturnJoin) {
|
||||||
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
|
|
||||||
void *exitcode;
|
void *exitcode;
|
||||||
cthread_t thread;
|
cthread_t thread;
|
||||||
ASSERT_EQ(0, cthread_create(&thread, 0, ReturnArg, ReturnArg));
|
ASSERT_EQ(0, cthread_create(&thread, 0, ReturnArg, ReturnArg));
|
||||||
|
@ -50,7 +49,6 @@ static void *ExitArg(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(cthread_create, testCreateExitJoin) {
|
TEST(cthread_create, testCreateExitJoin) {
|
||||||
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
|
|
||||||
void *exitcode;
|
void *exitcode;
|
||||||
cthread_t thread;
|
cthread_t thread;
|
||||||
ASSERT_EQ(0, cthread_create(&thread, 0, ExitArg, (void *)-31337));
|
ASSERT_EQ(0, cthread_create(&thread, 0, ExitArg, (void *)-31337));
|
||||||
|
@ -61,7 +59,6 @@ TEST(cthread_create, testCreateExitJoin) {
|
||||||
TEST(gcctls, size) {
|
TEST(gcctls, size) {
|
||||||
if (IsXnu()) return; // TODO(jart): codemorph
|
if (IsXnu()) return; // TODO(jart): codemorph
|
||||||
if (IsWindows()) return; // TODO(jart): codemorph
|
if (IsWindows()) return; // TODO(jart): codemorph
|
||||||
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
|
|
||||||
// schlep in .zip section too
|
// schlep in .zip section too
|
||||||
// make sure executable isn't too huge
|
// make sure executable isn't too huge
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -87,7 +84,6 @@ static void *TlsWorker(void *arg) {
|
||||||
TEST(gcctls, worksAndIsNonInheritable) {
|
TEST(gcctls, worksAndIsNonInheritable) {
|
||||||
if (IsXnu()) return; // TODO(jart): codemorph
|
if (IsXnu()) return; // TODO(jart): codemorph
|
||||||
if (IsWindows()) return; // TODO(jart): codemorph
|
if (IsWindows()) return; // TODO(jart): codemorph
|
||||||
if (IsOpenbsd()) return; // TODO(jart): we've getting flakes
|
|
||||||
void *exitcode;
|
void *exitcode;
|
||||||
cthread_t thread;
|
cthread_t thread;
|
||||||
ASSERT_EQ(tdata, 31337);
|
ASSERT_EQ(tdata, 31337);
|
||||||
|
|
|
@ -6496,14 +6496,14 @@ static int MemoryMonitor(void *arg) {
|
||||||
mi[2].x = (intptr_t)_edata >> 16;
|
mi[2].x = (intptr_t)_edata >> 16;
|
||||||
mi[2].size = _end - _edata;
|
mi[2].size = _end - _edata;
|
||||||
mi[2].flags = 0;
|
mi[2].flags = 0;
|
||||||
_spinlock(&_mmi.lock);
|
__mmi_lock();
|
||||||
if (_mmi.i == intervals - 3) {
|
if (_mmi.i == intervals - 3) {
|
||||||
memcpy(mi + 3, _mmi.p, _mmi.i * sizeof(*mi));
|
memcpy(mi + 3, _mmi.p, _mmi.i * sizeof(*mi));
|
||||||
ok = true;
|
ok = true;
|
||||||
} else {
|
} else {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
_spunlock(&_mmi.lock);
|
__mmi_unlock();
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
VERBOSEF("(memv) retrying due to contention on mmap table");
|
VERBOSEF("(memv) retrying due to contention on mmap table");
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in a new issue