mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-26 22:38:30 +00:00
Eliminate cyclic locks in runtime
This change introduces a new deadlock detector for Cosmo's POSIX threads implementation. Error check mutexes will now track a DAG of nested locks and report EDEADLK when a deadlock is theoretically possible. These will occur rarely, but it's important for production hardening your code. You don't even need to change your mutexes to use the POSIX error check mode because `cosmocc -mdbg` will enable error checking on mutexes by default globally. When cycles are found, an error message showing your demangled symbols describing the strongly connected component are printed and then the SIGTRAP is raised, which means you'll also get a backtrace if you're using ShowCrashReports() too. This new error checker is so low-level and so pure that it's able to verify the relationships of every libc runtime lock, including those locks upon which the mutex implementation depends.
This commit is contained in:
parent
26c051c297
commit
af7bd80430
141 changed files with 2094 additions and 1601 deletions
|
@ -8,11 +8,13 @@
|
|||
|
||||
#define PTHREAD_BARRIER_SERIAL_THREAD 31337
|
||||
|
||||
#define PTHREAD_MUTEX_NORMAL 0
|
||||
#define PTHREAD_MUTEX_RECURSIVE 1
|
||||
#define PTHREAD_MUTEX_ERRORCHECK 2
|
||||
#define PTHREAD_MUTEX_STALLED 0
|
||||
#define PTHREAD_MUTEX_ROBUST 1
|
||||
#define PTHREAD_MUTEX_DEFAULT 0
|
||||
#define PTHREAD_MUTEX_NORMAL 1
|
||||
#define PTHREAD_MUTEX_RECURSIVE 2
|
||||
#define PTHREAD_MUTEX_ERRORCHECK 3
|
||||
|
||||
#define PTHREAD_MUTEX_STALLED 0
|
||||
#define PTHREAD_MUTEX_ROBUST 2048
|
||||
|
||||
#define PTHREAD_PROCESS_PRIVATE 0
|
||||
#define PTHREAD_PROCESS_SHARED 4
|
||||
|
@ -43,12 +45,14 @@ COSMOPOLITAN_C_START_
|
|||
#define PTHREAD_ONCE_INIT {0}
|
||||
#define PTHREAD_COND_INITIALIZER {0}
|
||||
#define PTHREAD_RWLOCK_INITIALIZER {0}
|
||||
#define PTHREAD_MUTEX_INITIALIZER {0}
|
||||
|
||||
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {0, {}, PTHREAD_MUTEX_RECURSIVE}
|
||||
#define PTHREAD_MUTEX_INITIALIZER {0, PTHREAD_MUTEX_DEFAULT}
|
||||
#define PTHREAD_NORMAL_MUTEX_INITIALIZER_NP {0, PTHREAD_MUTEX_NORMAL}
|
||||
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {0, PTHREAD_MUTEX_RECURSIVE}
|
||||
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP {0, PTHREAD_MUTEX_ERRORCHECK}
|
||||
|
||||
#define PTHREAD_SIGNAL_SAFE_MUTEX_INITIALIZER_NP \
|
||||
{0, {}, PTHREAD_MUTEX_RECURSIVE | PTHREAD_PROCESS_SHARED}
|
||||
{0, PTHREAD_MUTEX_RECURSIVE | PTHREAD_PROCESS_SHARED}
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define _PTHREAD_ATOMIC(x) _Atomic(x)
|
||||
|
@ -72,14 +76,11 @@ typedef struct pthread_spinlock_s {
|
|||
} pthread_spinlock_t;
|
||||
|
||||
typedef struct pthread_mutex_s {
|
||||
uint32_t _nsync;
|
||||
union {
|
||||
int32_t _pid;
|
||||
_PTHREAD_ATOMIC(int32_t) _futex;
|
||||
};
|
||||
/* this cleverly overlaps with NSYNC struct Dll *waiters; */
|
||||
void *_edges;
|
||||
_PTHREAD_ATOMIC(uint64_t) _word;
|
||||
long _nsyncx[2];
|
||||
_PTHREAD_ATOMIC(int) _futex;
|
||||
int _pid;
|
||||
void *_nsync[2];
|
||||
} pthread_mutex_t;
|
||||
|
||||
typedef struct pthread_mutexattr_s {
|
||||
|
@ -92,18 +93,13 @@ typedef struct pthread_condattr_s {
|
|||
} pthread_condattr_t;
|
||||
|
||||
typedef struct pthread_cond_s {
|
||||
union {
|
||||
void *_align;
|
||||
struct {
|
||||
uint32_t _nsync;
|
||||
char _pshared;
|
||||
char _clock;
|
||||
char _footek;
|
||||
_PTHREAD_ATOMIC(char) _waited;
|
||||
};
|
||||
};
|
||||
char _pshared;
|
||||
char _clock;
|
||||
char _footek;
|
||||
_PTHREAD_ATOMIC(char) _waited;
|
||||
_PTHREAD_ATOMIC(uint32_t) _sequence;
|
||||
_PTHREAD_ATOMIC(uint32_t) _waiters;
|
||||
void *_nsync[2];
|
||||
} pthread_cond_t;
|
||||
|
||||
typedef struct pthread_rwlock_s {
|
||||
|
@ -156,20 +152,20 @@ int pthread_attr_getguardsize(const pthread_attr_t *, size_t *) libcesque params
|
|||
int pthread_attr_getinheritsched(const pthread_attr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_attr_getschedpolicy(const pthread_attr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_attr_getscope(const pthread_attr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_attr_getstack(const pthread_attr_t *, void **, size_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_getstacksize(const pthread_attr_t *, size_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_getsigaltstack_np(const pthread_attr_t *, void **, size_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_getsigaltstacksize_np(const pthread_attr_t *, size_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_getstack(const pthread_attr_t *, void **, size_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_getstacksize(const pthread_attr_t *, size_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_init(pthread_attr_t *) libcesque paramsnonnull();
|
||||
int pthread_attr_setdetachstate(pthread_attr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_attr_setguardsize(pthread_attr_t *, size_t) libcesque paramsnonnull();
|
||||
int pthread_attr_setinheritsched(pthread_attr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_attr_setschedpolicy(pthread_attr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_attr_setscope(pthread_attr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_attr_setstack(pthread_attr_t *, void *, size_t) libcesque paramsnonnull((1));
|
||||
int pthread_attr_setstacksize(pthread_attr_t *, size_t) libcesque paramsnonnull();
|
||||
int pthread_attr_setsigaltstack_np(pthread_attr_t *, void *, size_t) libcesque paramsnonnull((1));
|
||||
int pthread_attr_setsigaltstacksize_np(pthread_attr_t *, size_t);
|
||||
int pthread_attr_setstack(pthread_attr_t *, void *, size_t) libcesque paramsnonnull((1));
|
||||
int pthread_attr_setstacksize(pthread_attr_t *, size_t) libcesque paramsnonnull();
|
||||
int pthread_barrier_destroy(pthread_barrier_t *) libcesque paramsnonnull();
|
||||
int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *, unsigned) libcesque paramsnonnull((1));
|
||||
int pthread_barrier_wait(pthread_barrier_t *) libcesque paramsnonnull();
|
||||
|
@ -183,13 +179,15 @@ int pthread_cond_destroy(pthread_cond_t *) libcesque paramsnonnull();
|
|||
int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *) libcesque paramsnonnull((1));
|
||||
int pthread_cond_signal(pthread_cond_t *) libcesque paramsnonnull();
|
||||
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_init(pthread_condattr_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_destroy(pthread_condattr_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_setpshared(pthread_condattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_condattr_setclock(pthread_condattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_condattr_getclock(const pthread_condattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_condattr_init(pthread_condattr_t *) libcesque paramsnonnull();
|
||||
int pthread_condattr_setclock(pthread_condattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_condattr_setpshared(pthread_condattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *) dontthrow paramsnonnull((1));
|
||||
int pthread_decimate_np(void) libcesque;
|
||||
int pthread_delay_np(const void *, int) libcesque;
|
||||
int pthread_detach(pthread_t) libcesque;
|
||||
int pthread_equal(pthread_t, pthread_t) libcesque;
|
||||
int pthread_getattr_np(pthread_t, pthread_attr_t *) libcesque paramsnonnull();
|
||||
|
@ -205,15 +203,17 @@ int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *) libcesque
|
|||
int pthread_mutex_lock(pthread_mutex_t *) libcesque paramsnonnull();
|
||||
int pthread_mutex_trylock(pthread_mutex_t *) libcesque paramsnonnull();
|
||||
int pthread_mutex_unlock(pthread_mutex_t *) libcesque paramsnonnull();
|
||||
int pthread_mutex_wipe_np(pthread_mutex_t *) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t *) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_setrobust(const pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_mutexattr_settype(pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
||||
int pthread_once(pthread_once_t *, void (*)(void)) paramsnonnull();
|
||||
int pthread_orphan_np(void) libcesque;
|
||||
int pthread_decimate_np(void) libcesque;
|
||||
int pthread_rwlock_destroy(pthread_rwlock_t *) libcesque paramsnonnull();
|
||||
int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *) libcesque paramsnonnull((1));
|
||||
int pthread_rwlock_rdlock(pthread_rwlock_t *) libcesque paramsnonnull();
|
||||
|
@ -237,17 +237,16 @@ int pthread_spin_trylock(pthread_spinlock_t *) libcesque paramsnonnull();
|
|||
int pthread_spin_unlock(pthread_spinlock_t *) libcesque paramsnonnull();
|
||||
int pthread_testcancel_np(void) libcesque;
|
||||
int pthread_tryjoin_np(pthread_t, void **) libcesque;
|
||||
int pthread_delay_np(const void *, int) libcesque;
|
||||
int pthread_yield_np(void) libcesque;
|
||||
int pthread_yield(void) libcesque;
|
||||
int pthread_yield_np(void) libcesque;
|
||||
pthread_id_np_t pthread_getthreadid_np(void) libcesque;
|
||||
pthread_t pthread_self(void) libcesque pureconst;
|
||||
void *pthread_getspecific(pthread_key_t) libcesque;
|
||||
void pthread_cleanup_pop(struct _pthread_cleanup_buffer *, int) libcesque paramsnonnull();
|
||||
void pthread_cleanup_push(struct _pthread_cleanup_buffer *, void (*)(void *), void *) libcesque paramsnonnull((1));
|
||||
void pthread_exit(void *) libcesque wontreturn;
|
||||
void pthread_testcancel(void) libcesque;
|
||||
void pthread_pause_np(void) libcesque;
|
||||
void pthread_testcancel(void) libcesque;
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue