Make forking off threads reliable on Windows

This change makes posix_spawn_test no longer flaky on Windows, by (1)
fixing a race condition in wait(), and (2) removing a misguided vfork
implementation which was letting Windows bypass pthread_atfork().
This commit is contained in:
Justine Tunney 2023-07-30 08:55:01 -07:00
parent 2ebc5781a1
commit 58352df0a4
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
30 changed files with 230 additions and 187 deletions

View file

@ -67,7 +67,7 @@ textwindows int sys_accept_nt(struct Fd *fd, struct sockaddr_storage *addr,
if (!AcceptEx(fd->handle, handle, &buffer, 0, sizeof(buffer.local),
sizeof(buffer.remote), &bytes_received, &overlapped)) {
sockfd = (struct SockFd *)fd->extra;
if (__wsablock(fd, &overlapped, &completion_flags, true,
if (__wsablock(fd, &overlapped, &completion_flags, kSigOpRestartable,
sockfd->rcvtimeo) == -1) {
WSACloseEvent(overlapped.hEvent);
__sys_closesocket_nt(handle);

View file

@ -47,7 +47,8 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
} else {
errno = err;
sockfd = (struct SockFd *)fd->extra;
rc = __wsablock(fd, &overlapped, &flags, true, sockfd->rcvtimeo);
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
sockfd->rcvtimeo);
}
unassert(WSACloseEvent(overlapped.hEvent));
return rc;

View file

@ -46,7 +46,8 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
} else {
errno = err;
sockfd = (struct SockFd *)fd->extra;
rc = __wsablock(fd, &overlapped, &flags, true, sockfd->rcvtimeo);
rc = __wsablock(fd, &overlapped, &flags, kSigOpRestartable,
sockfd->rcvtimeo);
}
WSACloseEvent(overlapped.hEvent);
return rc;

View file

@ -41,7 +41,8 @@ textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
}
} else {
sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, true, sockfd->sndtimeo);
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
sockfd->sndtimeo);
}
WSACloseEvent(overlapped.hEvent);
return rc;

View file

@ -57,7 +57,7 @@ static textwindows int SendfileBlock(int64_t handle,
NTTRACE("WSAWaitForMultipleEvents failed %lm");
return __winsockerr();
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
if (_check_interrupts(true, g_fds.p)) return -1;
if (_check_interrupts(kSigOpRestartable, g_fds.p)) return -1;
#if _NTTRACE
POLLTRACE("WSAWaitForMultipleEvents...");
#endif

View file

@ -42,7 +42,8 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
}
} else {
sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, true, sockfd->sndtimeo);
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, kSigOpRestartable,
sockfd->sndtimeo);
}
WSACloseEvent(overlapped.hEvent);
return rc;

View file

@ -20,7 +20,7 @@ int sys_shutdown_nt(struct Fd *, int);
ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t);
ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
void *, uint32_t *);
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, bool, uint32_t);
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, int, uint32_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -37,8 +37,7 @@
#include "libc/sysv/errfuns.h"
textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
uint32_t *flags, bool restartable,
uint32_t timeout) {
uint32_t *flags, int sigops, uint32_t timeout) {
int e, rc;
uint32_t i, got;
if (WSAGetLastError() != kNtErrorIoPending) {
@ -51,7 +50,7 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
WSAGetLastError() == kNtErrorNotFound);
errno = e;
} else {
if (_check_interrupts(restartable, g_fds.p)) {
if (_check_interrupts(sigops, g_fds.p)) {
return -1;
}
}
@ -62,7 +61,7 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
NTTRACE("WSAWaitForMultipleEvents failed %lm");
return __winsockerr();
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
if (_check_interrupts(restartable, g_fds.p)) {
if (_check_interrupts(sigops, g_fds.p)) {
return -1;
}
if (timeout) {