Make more Windows socket fixes and improvements

This change makes send() / sendto() always block on Windows. It's needed
because poll(POLLOUT) doesn't guarantee a socket is immediately writable
on Windows, and it caused rsync to fail because it made that assumption.
The only exception is when a SO_SNDTIMEO is specified which will EAGAIN.

Tests are added confirming MSG_WAITALL and MSG_NOSIGNAL work as expected
on all our supported OSes. Most of the platform-specific MSG_FOO magnums
have been deleted, with the exception of MSG_FASTOPEN. Your --strace log
will now show MSG_FOO flags as symbols rather than numbers.

I've also removed cv_wait_example_test because it's 0.3% flaky with Qemu
under system load since it depends on a process being readily scheduled.
This commit is contained in:
Justine Tunney 2024-09-18 19:54:56 -07:00
parent ce2fbf9325
commit 87a6669900
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
41 changed files with 584 additions and 184 deletions

View file

@ -17,15 +17,17 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/intrin/fds.h"
#include "libc/nt/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/vga/vga.internal.h"
#ifdef __x86_64__
#define _MSG_OOB 1
@ -33,6 +35,8 @@
#define _MSG_WAITALL 8
#define _MSG_DONTWAIT 64
__msabi extern typeof(__sys_ioctlsocket_nt) *const __imp_ioctlsocket;
struct RecvArgs {
const struct iovec *iov;
size_t iovlen;
@ -54,13 +58,24 @@ textwindows ssize_t sys_recv_nt(int fd, const struct iovec *iov, size_t iovlen,
return einval();
ssize_t rc;
struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block();
bool nonblock = !(flags & _MSG_WAITALL) &&
((f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT));
flags &= ~_MSG_DONTWAIT;
rc = __winsock_block(f->handle, flags, nonblock, f->rcvtimeo, m,
sys_recv_nt_start, &(struct RecvArgs){iov, iovlen});
__sig_unblock(m);
sigset_t waitmask = __sig_block();
// "Be aware that if the underlying transport provider does not
// support MSG_WAITALL, or if the socket is in a non-blocking mode,
// then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL
// is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then
// this call will fail with WSAEOPNOTSUPP."
// —Quoth MSDN § WSARecv
if (flags & _MSG_WAITALL)
__imp_ioctlsocket(f->handle, FIONBIO, (uint32_t[]){0});
rc = __winsock_block(f->handle, flags & ~_MSG_DONTWAIT,
(f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT),
f->rcvtimeo, waitmask, sys_recv_nt_start,
&(struct RecvArgs){iov, iovlen});
__sig_unblock(waitmask);
return rc;
}