Skip to content

Commit

Permalink
Further optimize poll() on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
jart committed Sep 23, 2024
1 parent 556a294 commit 518eaba
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 64 deletions.
2 changes: 1 addition & 1 deletion libc/calls/park.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ textwindows static int _park_thread(uint32_t msdelay, sigset_t waitmask,
CloseHandle(sigev);

// recursion is now safe
if (ws == -1)
if (ws == -1u)
return __winerr();
int handler_was_called = 0;
if (sig)
Expand Down
44 changes: 33 additions & 11 deletions libc/calls/poll-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
Expand All @@ -25,6 +26,7 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/fds.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/filetype.h"
Expand All @@ -41,6 +43,7 @@
#include "libc/sock/internal.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#ifdef __x86_64__
Expand Down Expand Up @@ -84,7 +87,7 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds,
struct PosixThread *pt;
int i, rc, ev, kind, gotsocks;
struct sys_pollfd_nt sockfds[64];
uint32_t cm, fi, wi, sn, pn, avail, waitfor, already_slept;
uint32_t cm, fi, sn, pn, avail, waitfor, already_slept;

// ensure revents is cleared
for (i = 0; i < nfds; ++i)
Expand Down Expand Up @@ -228,22 +231,36 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds,
// this ensures low latency for apps like emacs which with no sock
// here we shall actually report that something can be written too
if (!already_slept) {
if (__sigcheck(waitmask, false))
return -1;
intptr_t sigev;
if (!(sigev = CreateEvent(0, 0, 0, 0)))
return __winerr();
filehands[pn] = sigev;
pt = _pthread_self();
filehands[pn] = pt->pt_event = CreateEvent(0, 0, 0, 0);
pt->pt_event = sigev;
pt->pt_blkmask = waitmask;
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release);
wi = WaitForMultipleObjects(pn + 1, filehands, 0, waitfor);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
int sig = 0;
uint32_t wi = pn;
if (!_is_canceled() &&
!(_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))))
wi = WaitForMultipleObjects(pn + 1, filehands, 0, waitfor);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
CloseHandle(filehands[pn]);
if (wi == -1u) {
CloseHandle(sigev);
if (wi == -1u)
// win32 wait failure
return __winerr();
} else if (wi == pn) {
if (wi == pn) {
// our signal event was signalled
if (__sigcheck(waitmask, false))
int handler_was_called = 0;
if (sig)
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1)
return -1;
if (handler_was_called)
return eintr();
} else if ((wi ^ kNtWaitAbandoned) < pn) {
// this is possibly because a process or thread was killed
fds[fileindices[wi ^ kNtWaitAbandoned]].revents = POLLERR_;
Expand Down Expand Up @@ -287,8 +304,6 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds,
} else {
// should only be possible on kNtWaitTimeout or semaphore abandoned
// keep looping for events and we'll catch timeout when appropriate
if (__sigcheck(waitmask, false))
return -1;
}
}

Expand All @@ -306,6 +321,13 @@ textwindows static int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
uint32_t waitms;
int i, n, rc, got = 0;

// we normally don't check for signals until we decide to wait, since
// it's nice to have functions like write() be unlikely to EINTR, but
// ppoll is a function where users are surely thinking about signals,
// since ppoll actually allows them to block signals everywhere else.
if (__sigcheck(waitmask, false))
return -1;

// fast path
if (nfds <= 63)
return sys_poll_nt_actual(fds, nfds, deadline, waitmask);
Expand Down
6 changes: 3 additions & 3 deletions libc/calls/pselect.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
END_CANCELATION_POINT;

STRACE("pselect(%d, %s → [%s], %s → [%s], %s → [%s], %s, %s) → %d% m", nfds,
DescribeFdSet(rc, nfds, old_readfds_ptr),
DescribeFdSet(0, nfds, old_readfds_ptr),
DescribeFdSet(rc, nfds, readfds),
DescribeFdSet(rc, nfds, old_writefds_ptr),
DescribeFdSet(0, nfds, old_writefds_ptr),
DescribeFdSet(rc, nfds, writefds),
DescribeFdSet(rc, nfds, old_exceptfds_ptr),
DescribeFdSet(0, nfds, old_exceptfds_ptr),
DescribeFdSet(rc, nfds, exceptfds), //
DescribeTimespec(0, timeout), //
DescribeSigset(0, sigmask), rc);
Expand Down
2 changes: 2 additions & 0 deletions libc/intrin/describefdset.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const char *_DescribeFdSet(char buf[N], ssize_t rc, int nfds, fd_set *fds) {

if (!fds)
return "NULL";
if (rc == -1)
return "n/a";
if (kisdangerous(fds)) {
ksnprintf(buf, N, "%p", fds);
return buf;
Expand Down
13 changes: 5 additions & 8 deletions libc/proc/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ textwindows int __proc_harvest(struct Proc *pr, bool iswait4) {
pr->handle = status & 0x00FFFFFF;
} else {
// handle child _Exit()
if (status == 0xc9af3d51u) {
if (status == 0xc9af3d51u)
status = kNtStillActive;
}
pr->wstatus = status;
if (!iswait4 && !pr->waiters && !__proc.waiters &&
(__sighandrvas[SIGCHLD] == (uintptr_t)SIG_IGN ||
(__sighandflags[SIGCHLD] & SA_NOCLDWAIT))) {
// perform automatic zombie reaping
STRACE("automatically reaping zombie");
dll_remove(&__proc.list, &pr->elem);
dll_make_first(&__proc.free, &pr->elem);
CloseHandle(pr->handle);
Expand Down Expand Up @@ -192,9 +192,8 @@ static textwindows dontinstrument uint32_t __proc_worker(void *arg) {
continue;
if (j == i)
continue;
if (!--objects[j]->waiters && objects[j]->status == PROC_UNDEAD) {
if (!--objects[j]->waiters && objects[j]->status == PROC_UNDEAD)
__proc_free(objects[j]);
}
}

// check if we need to churn due to >64 processes
Expand All @@ -219,9 +218,8 @@ static textwindows dontinstrument uint32_t __proc_worker(void *arg) {
case PROC_ZOMBIE:
break;
case PROC_UNDEAD:
if (!objects[i]->waiters) {
if (!objects[i]->waiters)
__proc_free(objects[i]);
}
break;
default:
__builtin_unreachable();
Expand All @@ -233,9 +231,8 @@ static textwindows dontinstrument uint32_t __proc_worker(void *arg) {
// 1. wait4() is being used
// 2. SIGCHLD has SIG_IGN handler
// 3. SIGCHLD has SA_NOCLDWAIT flag
if (sic) {
if (sic)
__sig_generate(SIGCHLD, sic);
}
}
return 0;
}
Expand Down
41 changes: 0 additions & 41 deletions test/libc/calls/fchmod_test.c

This file was deleted.

0 comments on commit 518eaba

Please sign in to comment.