Skip to content

Commit

Permalink
Improve threading and i/o routines
Browse files Browse the repository at this point in the history
- On Windows connect() can now be interrupted by a signal; connect() w/
  O_NONBLOCK will now raise EINPROGRESS; and connect() with SO_SNDTIMEO
  will raise ETIMEDOUT after the interval has elapsed.

- We now get the AcceptEx(), ConnectEx(), and TransmitFile() functions
  from the WIN32 API the officially blessed way, using WSAIoctl().

- Do nothing on Windows when fsync() is called on a directory handle.
  This was raising EACCES earlier becaues GENERIC_WRITE is required on
  the handle. It's possible to FlushFileBuffers() a directory handle if
  it's opened with write access but MSDN doesn't document what it does.
  If you have any idea, please let us know!

- Prefer manual reset event objects for read() and write() on Windows.

- Do some code cleanup on our dlmalloc customizations.

- Fix errno type error in Windows blocking routines.

- Make the futex polyfill simpler and faster.
  • Loading branch information
jart committed Oct 13, 2023
1 parent f734331 commit 49b0eaa
Show file tree
Hide file tree
Showing 43 changed files with 528 additions and 425 deletions.
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,6 @@ COSMOPOLITAN_OBJECTS = \
LIBC_SOCK \
LIBC_NT_WS2_32 \
LIBC_NT_IPHLPAPI \
LIBC_NT_MSWSOCK \
LIBC_X \
THIRD_PARTY_GETOPT \
LIBC_LOG \
Expand Down
9 changes: 9 additions & 0 deletions libc/calls/fdatasync-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,24 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__

textwindows int sys_fdatasync_nt(int fd, bool fake) {
struct NtByHandleFileInformation wst;
if (!__isfdopen(fd)) return ebadf();
if (!__isfdkind(fd, kFdFile)) return einval();
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypeDisk) return einval();
if (!GetFileInformationByHandle(g_fds.p[fd].handle, &wst)) return __winerr();
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
// Flushing a directory handle is possible, but it needs
// kNtGenericWrite access, and MSDN doesn't document it.
return 0;
}
if (_check_cancel() == -1) return -1;
if (_check_signal(false) == -1) return -1;
if (fake) return 0;
Expand Down
5 changes: 3 additions & 2 deletions libc/calls/readwrite-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/stdio/sysparam.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
Expand Down Expand Up @@ -67,10 +68,10 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
bool32 ok;
uint64_t m;
uint32_t exchanged;
int olderror = errno;
bool eagained = false;
bool eintered = false;
bool canceled = false;
bool olderror = errno;
struct PosixThread *pt;
struct Fd *f = g_fds.p + fd;

Expand Down Expand Up @@ -124,7 +125,7 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
// can only be returned by a single system call in a thread's life
// another thing we do is check if any pending signals exist, then
// running as many of them as possible before entering a wait call
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0),
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 1, 0, 0),
.Pointer = offset};
struct ReadwriteResources rwc = {handle, &overlap};
pthread_cleanup_push(UnwindReadwrite, &rwc);
Expand Down
1 change: 1 addition & 0 deletions libc/calls/releasefd.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
void __releasefd(int fd) {
int f1, f2;
if (!(0 <= fd && fd < g_fds.n)) return;
g_fds.p[fd].kind = kFdEmpty;
bzero(g_fds.p + fd, sizeof(*g_fds.p));
f1 = atomic_load_explicit(&g_fds.f, memory_order_relaxed);
do {
Expand Down
10 changes: 6 additions & 4 deletions libc/calls/struct/fd.internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ COSMOPOLITAN_C_START_

struct Fd {
char kind;
bool isbound;
unsigned flags;
unsigned mode;
int64_t handle;
int64_t pointer;
long handle;
long pointer;
int family;
int type;
int protocol;
uint32_t rcvtimeo;
uint32_t sndtimeo;
unsigned rcvtimeo; /* millis; 0 means wait forever */
unsigned sndtimeo; /* millis; 0 means wait forever */
void *connect_op;
};

struct Fds {
Expand Down
3 changes: 3 additions & 0 deletions libc/intrin/pthread_yield.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/nexgen32e/yield.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/thread/thread.h"
Expand All @@ -30,6 +31,8 @@
int pthread_yield(void) {
if (IsXnuSilicon()) {
__syslib->__pthread_yield_np();
} else if (IsOpenbsd()) {
spin_yield(); // sched_yield() is punishingly slow on OpenBSD
} else {
sched_yield();
}
Expand Down
2 changes: 1 addition & 1 deletion libc/intrin/ulock.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
int sys_ulock_wait(uint32_t operation, void *addr, uint64_t value,
uint32_t timeout_micros) asm("sys_futex_cp");

// returns -1 w/ errno
// returns number of other waiters, or -1 w/ errno
int ulock_wait(uint32_t operation, void *addr, uint64_t value,
uint32_t timeout_micros) {
int rc;
Expand Down
18 changes: 0 additions & 18 deletions libc/nt/MsWSock/AcceptEx.S

This file was deleted.

18 changes: 0 additions & 18 deletions libc/nt/MsWSock/DisconnectEx.S

This file was deleted.

18 changes: 0 additions & 18 deletions libc/nt/MsWSock/GetAcceptExSockaddrs.S

This file was deleted.

18 changes: 0 additions & 18 deletions libc/nt/MsWSock/TransmitFile.S

This file was deleted.

18 changes: 0 additions & 18 deletions libc/nt/MsWSock/WSARecvEx.S

This file was deleted.

8 changes: 4 additions & 4 deletions libc/nt/iocp.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ typedef void (*NtOverlappedCompletionRoutine)(

int64_t CreateIoCompletionPort(int64_t FileHandleOrNeg1,
int64_t opt_ExistingCompletionPortOrZero,
void *StatePointer,
uint64_t CompletionKey,
uint32_t NumberOfConcurrentThreads);

bool32 GetQueuedCompletionStatus(int64_t CompletionPort,
uint32_t *lpNumberOfBytesTransferred,
void *StatePointerPointer,
struct NtOverlapped **lpOverlapped,
uint64_t *out_lpCompletionKey,
struct NtOverlapped **out_lpOverlapped,
uint32_t dwMilliseconds);

bool32 GetQueuedCompletionStatusEx(
Expand All @@ -56,7 +56,7 @@ bool32 GetQueuedCompletionStatusEx(

bool32 PostQueuedCompletionStatus(int64_t CompletionPort,
uint32_t dwNumberOfBytesTransferred,
uint32_t *dwCompletionKey,
uint64_t dwCompletionKey,
struct NtOverlapped *opt_lpOverlapped);

bool32 SetFileCompletionNotificationModes(int64_t FileHandle,
Expand Down
10 changes: 1 addition & 9 deletions libc/nt/master.sh
Original file line number Diff line number Diff line change
Expand Up @@ -483,15 +483,6 @@ imp 'GetSaveFileName' GetSaveFileNameW comdlg32 1
imp 'PrintDlg' PrintDlgW comdlg32 1
imp 'ReplaceText' ReplaceTextW comdlg32 1

# MSWSOCK.DLL
#
# Name Actual DLL Arity
imp 'AcceptEx' AcceptEx MsWSock 8
imp 'DisconnectEx' DisconnectEx MsWSock 4
imp 'GetAcceptExSockaddrs' GetAcceptExSockaddrs MsWSock 8
imp 'TransmitFile' TransmitFile MsWSock 7
imp 'WSARecvEx' WSARecvEx MsWSock 4

# WS2_32.DLL
#
# Name Actual DLL Arity
Expand All @@ -516,6 +507,7 @@ imp '' setsockopt ws2_32 5
imp '' shutdown ws2_32 2
imp '' socket ws2_32 3
imp '' socket ws2_32 3
imp '' socket ws2_32 3
imp 'FreeAddrInfo' FreeAddrInfoW ws2_32 1
imp 'FreeAddrInfoEx' FreeAddrInfoExW ws2_32 1
imp 'GetAddrInfo' GetAddrInfoW ws2_32 4
Expand Down
21 changes: 0 additions & 21 deletions libc/nt/nt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -221,27 +221,6 @@ $(LIBC_NT_IPHLPAPI_A).pkg: \

#───────────────────────────────────────────────────────────────────────────────

LIBC_NT_ARTIFACTS += LIBC_NT_MSWSOCK_A
LIBC_NT_MSWSOCK = $(LIBC_NT_MSWSOCK_A_DEPS) $(LIBC_NT_MSWSOCK_A)
LIBC_NT_MSWSOCK_A = o/$(MODE)/libc/nt/MsWSock.a
LIBC_NT_MSWSOCK_A_SRCS := $(wildcard libc/nt/MsWSock/*.S)
LIBC_NT_MSWSOCK_A_OBJS = $(LIBC_NT_MSWSOCK_A_SRCS:%.S=o/$(MODE)/%.o)
LIBC_NT_MSWSOCK_A_CHECKS = $(LIBC_NT_MSWSOCK_A).pkg
LIBC_NT_MSWSOCK_A_DIRECTDEPS = LIBC_NT_KERNEL32
LIBC_NT_MSWSOCK_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_NT_MSWSOCK_A_DIRECTDEPS),$($(x))))

$(LIBC_NT_MSWSOCK_A): \
libc/nt/MsWSock/ \
$(LIBC_NT_MSWSOCK_A).pkg \
$(LIBC_NT_MSWSOCK_A_OBJS)

$(LIBC_NT_MSWSOCK_A).pkg: \
$(LIBC_NT_MSWSOCK_A_OBJS) \
$(foreach x,$(LIBC_NT_MSWSOCK_A_DIRECTDEPS),$($(x)_A).pkg)

#───────────────────────────────────────────────────────────────────────────────

LIBC_NT_ARTIFACTS += LIBC_NT_IPHLPAPI_A
LIBC_NT_IPHLPAPI = $(LIBC_NT_IPHLPAPI_A_DEPS) $(LIBC_NT_IPHLPAPI_A)
LIBC_NT_IPHLPAPI_A = o/$(MODE)/libc/nt/iphlpapi.a
Expand Down
2 changes: 1 addition & 1 deletion libc/nt/struct/overlappedentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
COSMOPOLITAN_C_START_

struct NtOverlappedEntry {
uint32_t *lpCompletionKey;
uint64_t lpCompletionKey;
struct NtOverlapped *lpOverlapped;
uint32_t *Internal;
uint32_t dwNumberOfBytesTransferred;
Expand Down
20 changes: 1 addition & 19 deletions libc/nt/winsock.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ int WSACleanup(void);
int WSAGetLastError(void) nosideeffect;
void WSASetLastError(int);

int64_t __sys_socket_nt(int, int, int);
int __sys_bind_nt(uint64_t, const void *, int);
int __sys_closesocket_nt(uint64_t);
int __sys_getpeername_nt(uint64_t, void *, uint32_t *);
Expand Down Expand Up @@ -342,12 +343,6 @@ int64_t WSAAccept(uint64_t s, struct sockaddr *out_addr,
const NtConditionProc opt_lpfnCondition,
const uint32_t *opt_dwCallbackData) paramsnonnull((2)) __wur;

bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
uint32_t dwReceiveDataLength, uint32_t dwLocalAddressLength,
uint32_t dwRemoteAddressLength, uint32_t *out_lpdwBytesReceived,
struct NtOverlapped *inout_lpOverlapped);

int WSASend(uint64_t s, const struct NtIovec *lpBuffers, uint32_t dwBufferCount,
uint32_t *opt_out_lpNumberOfBytesSent, uint32_t dwFlags,
struct NtOverlapped *opt_inout_lpOverlapped,
Expand Down Expand Up @@ -494,19 +489,6 @@ int /* success==0 */ WSAGetServiceClassNameByClassId(
const struct NtGuid *lpServiceClassId, char16_t *out_lpszServiceClassName,
uint32_t *inout_lpdwBufferLength) paramsnonnull();

bool32 TransmitFile(int64_t hSocket, int64_t hFile,
uint32_t opt_nNumberOfBytesToWrite,
uint32_t opt_nNumberOfBytesPerSend,
struct NtOverlapped *opt_inout_lpOverlapped,
const struct NtTransmitFileBuffers *opt_lpTransmitBuffers,
uint32_t dwReserved);

bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
uint32_t dwReceiveDataLength, uint32_t dwLocalAddressLength,
uint32_t dwRemoteAddressLength, uint32_t *out_lpdwBytesReceived,
struct NtOverlapped *inout_lpOverlapped);

void GetAcceptExSockaddrs(
const void *lpOutputBuffer /*[recvsize+addrsize+addrlen]*/,
uint32_t dwReceiveDataLength, uint32_t dwLocalAddressLength,
Expand Down
5 changes: 0 additions & 5 deletions libc/runtime/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/ulock.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
Expand Down Expand Up @@ -667,7 +666,6 @@ errno_t clone(void *func, void *stk, size_t stksz, int flags, void *arg,
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) !=
(CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
CLONE_SIGHAND | CLONE_SYSVSEM)) {
STRACE("cosmo clone() is picky about flags, see clone.c");
rc = EINVAL;
} else if (IsXnu()) {
#ifdef __x86_64__
Expand Down Expand Up @@ -695,8 +693,5 @@ errno_t clone(void *func, void *stk, size_t stksz, int flags, void *arg,
rc = EAGAIN;
}

STRACE("clone(%t, %p, %'zu, %#x, %p, %p, %p, %p) → %s", func, stk, stksz,
flags, arg, ptid, tls, ctid, DescribeErrno(rc));

return rc;
}
Loading

0 comments on commit 49b0eaa

Please sign in to comment.