mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 23:08:31 +00:00
Improve lock hierarchy
- NetBSD no longer needs a spin lock to create semaphores - Windows fork() now locks process manager in correct order
This commit is contained in:
parent
7ba9a73840
commit
d3a13e8d70
14 changed files with 73 additions and 71 deletions
|
@ -22,8 +22,10 @@
|
|||
/**
|
||||
* Destroys mutex.
|
||||
*
|
||||
* Destroying a mutex that's currently locked or being waited upon, will
|
||||
* result in undefined behavior.
|
||||
*
|
||||
* @return 0 on success, or error number on failure
|
||||
* @raise EINVAL if mutex is locked in our implementation
|
||||
*/
|
||||
errno_t pthread_mutex_destroy(pthread_mutex_t *mutex) {
|
||||
memset(mutex, -1, sizeof(*mutex));
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/enum/processaccess.h"
|
||||
|
@ -109,10 +109,14 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
|
||||
// give child to libc/proc/proc.c worker thread in parent
|
||||
int64_t handle;
|
||||
unassert(DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess,
|
||||
&handle, 0, false, kNtDuplicateSameAccess));
|
||||
unassert(!(handle & 0xFFFFFFFFFF000000));
|
||||
TerminateThisProcess(0x23000000u | handle);
|
||||
if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, &handle,
|
||||
0, false, kNtDuplicateSameAccess)) {
|
||||
unassert(!(handle & 0xFFFFFFFFFF000000));
|
||||
TerminateThisProcess(0x23000000u | handle);
|
||||
} else {
|
||||
kprintf("DuplicateHandle failed w/ %d\n", GetLastError());
|
||||
TerminateThisProcess(ECHILD);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -473,9 +473,8 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
// reset core runtime services
|
||||
__proc_wipe();
|
||||
WipeKeystrokes();
|
||||
if (_weaken(__itimer_wipe)) {
|
||||
if (_weaken(__itimer_wipe))
|
||||
_weaken(__itimer_wipe)();
|
||||
}
|
||||
// notify pthread join
|
||||
atomic_store_explicit(&_pthread_static.ptid, GetCurrentThreadId(),
|
||||
memory_order_release);
|
||||
|
|
|
@ -54,6 +54,8 @@ extern pthread_mutex_t _pthread_lock_obj;
|
|||
static void _onfork_prepare(void) {
|
||||
if (_weaken(_pthread_onfork_prepare))
|
||||
_weaken(_pthread_onfork_prepare)();
|
||||
if (IsWindows())
|
||||
__proc_lock();
|
||||
_pthread_lock();
|
||||
__maps_lock();
|
||||
__fds_lock();
|
||||
|
@ -66,11 +68,15 @@ static void _onfork_parent(void) {
|
|||
__fds_unlock();
|
||||
__maps_unlock();
|
||||
_pthread_unlock();
|
||||
if (IsWindows())
|
||||
__proc_unlock();
|
||||
if (_weaken(_pthread_onfork_parent))
|
||||
_weaken(_pthread_onfork_parent)();
|
||||
}
|
||||
|
||||
static void _onfork_child(void) {
|
||||
if (IsWindows())
|
||||
__proc_wipe();
|
||||
__fds_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
_rand64_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
_pthread_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
|
@ -87,8 +93,6 @@ int _fork(uint32_t dwCreationFlags) {
|
|||
int ax, dx, tid, parent;
|
||||
parent = __pid;
|
||||
BLOCK_SIGNALS;
|
||||
if (IsWindows())
|
||||
__proc_lock();
|
||||
if (__threaded)
|
||||
_onfork_prepare();
|
||||
started = timespec_real();
|
||||
|
@ -149,8 +153,6 @@ int _fork(uint32_t dwCreationFlags) {
|
|||
// this is the parent process
|
||||
if (__threaded)
|
||||
_onfork_parent();
|
||||
if (IsWindows())
|
||||
__proc_unlock();
|
||||
STRACE("fork() → %d% m (took %ld us)", ax, micros);
|
||||
}
|
||||
ALLOW_SIGNALS;
|
||||
|
|
|
@ -59,9 +59,8 @@ textwindows int sys_kill_nt(int pid, int sig) {
|
|||
struct Dll *e;
|
||||
BLOCK_SIGNALS;
|
||||
__proc_lock();
|
||||
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e)) {
|
||||
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e))
|
||||
TerminateProcess(PROC_CONTAINER(e)->handle, sig);
|
||||
}
|
||||
__proc_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "libc/intrin/strace.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/leaks.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/enum/processaccess.h"
|
||||
#include "libc/nt/enum/processcreationflags.h"
|
||||
|
@ -45,12 +44,16 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/proc/proc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sicode.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "third_party/nsync/mu.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
/**
|
||||
|
@ -273,27 +276,21 @@ textwindows void __proc_wipe(void) {
|
|||
textwindows struct Proc *__proc_new(void) {
|
||||
struct Dll *e;
|
||||
struct Proc *proc = 0;
|
||||
// fork() + wait() don't depend on malloc() so neither shall we
|
||||
if (__proc.allocated < ARRAYLEN(__proc.pool)) {
|
||||
proc = __proc.pool + __proc.allocated++;
|
||||
} else {
|
||||
if ((e = dll_first(__proc.free))) {
|
||||
proc = PROC_CONTAINER(e);
|
||||
dll_remove(&__proc.free, &proc->elem);
|
||||
}
|
||||
if (!proc) {
|
||||
if (_weaken(malloc)) {
|
||||
proc = may_leak(_weaken(malloc)(sizeof(struct Proc)));
|
||||
} else {
|
||||
enomem();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ((e = dll_first(__proc.free))) {
|
||||
proc = PROC_CONTAINER(e);
|
||||
dll_remove(&__proc.free, &proc->elem);
|
||||
}
|
||||
if (proc) {
|
||||
bzero(proc, sizeof(*proc));
|
||||
dll_init(&proc->elem);
|
||||
} else {
|
||||
proc = mmap(0, sizeof(struct Proc), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (proc == MAP_FAILED) {
|
||||
enomem();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dll_init(&proc->elem);
|
||||
return proc;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ struct Procs {
|
|||
struct Dll *free;
|
||||
struct Dll *undead;
|
||||
struct Dll *zombies;
|
||||
struct Proc pool[8];
|
||||
unsigned allocated;
|
||||
struct rusage ruchlds;
|
||||
};
|
||||
|
|
|
@ -117,18 +117,21 @@ errno_t pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
|||
if (MUTEX_PSHARED(muword) != PTHREAD_PROCESS_SHARED)
|
||||
return EINVAL;
|
||||
|
||||
errno_t err;
|
||||
BEGIN_CANCELATION_POINT;
|
||||
#if PTHREAD_USE_NSYNC
|
||||
// favor *NSYNC if this is a process private condition variable
|
||||
// if using Mike Burrows' code isn't possible, use a naive impl
|
||||
if (!cond->_pshared)
|
||||
return nsync_cv_wait_with_deadline(
|
||||
if (!cond->_pshared) {
|
||||
err = nsync_cv_wait_with_deadline(
|
||||
(nsync_cv *)cond, (nsync_mu *)mutex,
|
||||
abstime ? *abstime : nsync_time_no_deadline, 0);
|
||||
#endif
|
||||
|
||||
errno_t err;
|
||||
BEGIN_CANCELATION_POINT;
|
||||
} else {
|
||||
err = pthread_cond_timedwait_impl(cond, mutex, abstime);
|
||||
}
|
||||
#else
|
||||
err = pthread_cond_timedwait_impl(cond, mutex, abstime);
|
||||
#endif
|
||||
END_CANCELATION_POINT;
|
||||
return err;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue