Skip to content

Commit d3a13e8

Browse files
committed
Improve lock hierarchy
- NetBSD no longer needs a spin lock to create semaphores - Windows fork() now locks process manager in correct order
1 parent 7ba9a73 commit d3a13e8

File tree

14 files changed

+73
-71
lines changed

14 files changed

+73
-71
lines changed

libc/intrin/pthread_mutex_destroy.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
/**
2323
* Destroys mutex.
2424
*
25+
* Destroying a mutex that's currently locked or being waited upon, will
26+
* result in undefined behavior.
27+
*
2528
* @return 0 on success, or error number on failure
26-
* @raise EINVAL if mutex is locked in our implementation
2729
*/
2830
errno_t pthread_mutex_destroy(pthread_mutex_t *mutex) {
2931
memset(mutex, -1, sizeof(*mutex));

libc/proc/execve-nt.greg.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/assert.h"
2020
#include "libc/calls/internal.h"
21-
#include "libc/intrin/fds.h"
2221
#include "libc/calls/struct/sigset.internal.h"
2322
#include "libc/calls/syscall-nt.internal.h"
2423
#include "libc/errno.h"
2524
#include "libc/fmt/itoa.h"
25+
#include "libc/intrin/fds.h"
2626
#include "libc/intrin/kprintf.h"
2727
#include "libc/mem/mem.h"
2828
#include "libc/nt/enum/processaccess.h"
@@ -109,10 +109,14 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
109109

110110
// give child to libc/proc/proc.c worker thread in parent
111111
int64_t handle;
112-
unassert(DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess,
113-
&handle, 0, false, kNtDuplicateSameAccess));
114-
unassert(!(handle & 0xFFFFFFFFFF000000));
115-
TerminateThisProcess(0x23000000u | handle);
112+
if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, &handle,
113+
0, false, kNtDuplicateSameAccess)) {
114+
unassert(!(handle & 0xFFFFFFFFFF000000));
115+
TerminateThisProcess(0x23000000u | handle);
116+
} else {
117+
kprintf("DuplicateHandle failed w/ %d\n", GetLastError());
118+
TerminateThisProcess(ECHILD);
119+
}
116120
}
117121

118122
#endif /* __x86_64__ */

libc/proc/fork-nt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,9 +473,8 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
473473
// reset core runtime services
474474
__proc_wipe();
475475
WipeKeystrokes();
476-
if (_weaken(__itimer_wipe)) {
476+
if (_weaken(__itimer_wipe))
477477
_weaken(__itimer_wipe)();
478-
}
479478
// notify pthread join
480479
atomic_store_explicit(&_pthread_static.ptid, GetCurrentThreadId(),
481480
memory_order_release);

libc/proc/fork.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ extern pthread_mutex_t _pthread_lock_obj;
5454
static void _onfork_prepare(void) {
5555
if (_weaken(_pthread_onfork_prepare))
5656
_weaken(_pthread_onfork_prepare)();
57+
if (IsWindows())
58+
__proc_lock();
5759
_pthread_lock();
5860
__maps_lock();
5961
__fds_lock();
@@ -66,11 +68,15 @@ static void _onfork_parent(void) {
6668
__fds_unlock();
6769
__maps_unlock();
6870
_pthread_unlock();
71+
if (IsWindows())
72+
__proc_unlock();
6973
if (_weaken(_pthread_onfork_parent))
7074
_weaken(_pthread_onfork_parent)();
7175
}
7276

7377
static void _onfork_child(void) {
78+
if (IsWindows())
79+
__proc_wipe();
7480
__fds_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
7581
_rand64_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
7682
_pthread_lock_obj = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -87,8 +93,6 @@ int _fork(uint32_t dwCreationFlags) {
8793
int ax, dx, tid, parent;
8894
parent = __pid;
8995
BLOCK_SIGNALS;
90-
if (IsWindows())
91-
__proc_lock();
9296
if (__threaded)
9397
_onfork_prepare();
9498
started = timespec_real();
@@ -149,8 +153,6 @@ int _fork(uint32_t dwCreationFlags) {
149153
// this is the parent process
150154
if (__threaded)
151155
_onfork_parent();
152-
if (IsWindows())
153-
__proc_unlock();
154156
STRACE("fork() → %d% m (took %ld us)", ax, micros);
155157
}
156158
ALLOW_SIGNALS;

libc/proc/kill-nt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ textwindows int sys_kill_nt(int pid, int sig) {
5959
struct Dll *e;
6060
BLOCK_SIGNALS;
6161
__proc_lock();
62-
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e)) {
62+
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e))
6363
TerminateProcess(PROC_CONTAINER(e)->handle, sig);
64-
}
6564
__proc_unlock();
6665
ALLOW_SIGNALS;
6766
}

libc/proc/proc.c

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include "libc/intrin/strace.h"
3131
#include "libc/intrin/weaken.h"
3232
#include "libc/mem/leaks.h"
33-
#include "libc/mem/mem.h"
3433
#include "libc/nt/accounting.h"
3534
#include "libc/nt/enum/processaccess.h"
3635
#include "libc/nt/enum/processcreationflags.h"
@@ -45,12 +44,16 @@
4544
#include "libc/nt/synchronization.h"
4645
#include "libc/nt/thread.h"
4746
#include "libc/proc/proc.internal.h"
47+
#include "libc/runtime/runtime.h"
4848
#include "libc/str/str.h"
49+
#include "libc/sysv/consts/map.h"
50+
#include "libc/sysv/consts/prot.h"
4951
#include "libc/sysv/consts/sa.h"
5052
#include "libc/sysv/consts/sicode.h"
5153
#include "libc/sysv/consts/sig.h"
5254
#include "libc/sysv/errfuns.h"
5355
#include "libc/thread/tls.h"
56+
#include "third_party/nsync/mu.h"
5457
#ifdef __x86_64__
5558

5659
/**
@@ -273,27 +276,21 @@ textwindows void __proc_wipe(void) {
273276
textwindows struct Proc *__proc_new(void) {
274277
struct Dll *e;
275278
struct Proc *proc = 0;
276-
// fork() + wait() don't depend on malloc() so neither shall we
277-
if (__proc.allocated < ARRAYLEN(__proc.pool)) {
278-
proc = __proc.pool + __proc.allocated++;
279-
} else {
280-
if ((e = dll_first(__proc.free))) {
281-
proc = PROC_CONTAINER(e);
282-
dll_remove(&__proc.free, &proc->elem);
283-
}
284-
if (!proc) {
285-
if (_weaken(malloc)) {
286-
proc = may_leak(_weaken(malloc)(sizeof(struct Proc)));
287-
} else {
288-
enomem();
289-
return 0;
290-
}
291-
}
279+
if ((e = dll_first(__proc.free))) {
280+
proc = PROC_CONTAINER(e);
281+
dll_remove(&__proc.free, &proc->elem);
292282
}
293283
if (proc) {
294284
bzero(proc, sizeof(*proc));
295-
dll_init(&proc->elem);
285+
} else {
286+
proc = mmap(0, sizeof(struct Proc), PROT_READ | PROT_WRITE,
287+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
288+
if (proc == MAP_FAILED) {
289+
enomem();
290+
return 0;
291+
}
296292
}
293+
dll_init(&proc->elem);
297294
return proc;
298295
}
299296

libc/proc/proc.internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ struct Procs {
3636
struct Dll *free;
3737
struct Dll *undead;
3838
struct Dll *zombies;
39-
struct Proc pool[8];
4039
unsigned allocated;
4140
struct rusage ruchlds;
4241
};

libc/thread/pthread_cond_timedwait.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,18 +117,21 @@ errno_t pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
117117
if (MUTEX_PSHARED(muword) != PTHREAD_PROCESS_SHARED)
118118
return EINVAL;
119119

120+
errno_t err;
121+
BEGIN_CANCELATION_POINT;
120122
#if PTHREAD_USE_NSYNC
121123
// favor *NSYNC if this is a process private condition variable
122124
// if using Mike Burrows' code isn't possible, use a naive impl
123-
if (!cond->_pshared)
124-
return nsync_cv_wait_with_deadline(
125+
if (!cond->_pshared) {
126+
err = nsync_cv_wait_with_deadline(
125127
(nsync_cv *)cond, (nsync_mu *)mutex,
126128
abstime ? *abstime : nsync_time_no_deadline, 0);
127-
#endif
128-
129-
errno_t err;
130-
BEGIN_CANCELATION_POINT;
129+
} else {
130+
err = pthread_cond_timedwait_impl(cond, mutex, abstime);
131+
}
132+
#else
131133
err = pthread_cond_timedwait_impl(cond, mutex, abstime);
134+
#endif
132135
END_CANCELATION_POINT;
133136
return err;
134137
}

test/libc/stdio/popen_test.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void SetUpOnce(void) {
4545

4646
void CheckForFdLeaks(void) {
4747
int rc, i, l = 0, e = errno;
48-
for (i = 3; i < 16; ++i) {
48+
for (i = 3; i < 50; ++i) {
4949
rc = fcntl(i, F_GETFL);
5050
if (rc == -1) {
5151
ASSERT_EQ(EBADF, errno);
@@ -149,7 +149,11 @@ void *Worker(void *arg) {
149149
ASSERT_NE(NULL, (f = popen(cmd, "r")));
150150
EXPECT_STREQ(arg1, fgets(buf, sizeof(buf), f));
151151
EXPECT_STREQ(arg2, fgets(buf, sizeof(buf), f));
152-
ASSERT_EQ(0, pclose(f));
152+
if (IsWindows())
153+
// todo(jart): why does it flake with echild?
154+
pclose(f);
155+
else
156+
ASSERT_EQ(0, pclose(f));
153157
free(arg2);
154158
free(arg1);
155159
free(cmd);
@@ -158,10 +162,6 @@ void *Worker(void *arg) {
158162
}
159163

160164
TEST(popen, torture) {
161-
if (IsWindows()) {
162-
// TODO: Why does pclose() return kNtSignalAccessViolationa?!
163-
return;
164-
}
165165
int i, n = 4;
166166
pthread_t *t = gc(malloc(sizeof(pthread_t) * n));
167167
testlib_extract("/zip/echo", "echo", 0755);

test/libcxx/openmp_test.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,9 @@ void check_gemm_works(void) {
429429
is_self_testing = false;
430430
}
431431

432-
long m = 2333 / 3;
433-
long k = 577 / 3;
434-
long n = 713 / 3;
432+
long m = 2333 / 10;
433+
long k = 577 / 10;
434+
long n = 713 / 10;
435435

436436
void check_sgemm(void) {
437437
float *A = new float[m * k];

0 commit comments

Comments
 (0)