mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Further optimize poll() on Windows
This commit is contained in:
parent
556a294363
commit
518eabadf5
6 changed files with 44 additions and 64 deletions
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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__
|
||||
|
@ -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)
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUpOnce(void) {
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
}
|
||||
|
||||
uint32_t GetMode(int fd) {
|
||||
struct stat st;
|
||||
ASSERT_SYS(0, 0, fstat(fd, &st));
|
||||
return st.st_mode & 0777;
|
||||
}
|
||||
|
||||
TEST(fchmod, canChangeReadOnlyBit) {
|
||||
ASSERT_SYS(0, 3, creat("foo", 0600));
|
||||
ASSERT_EQ(0600, GetMode(3));
|
||||
ASSERT_SYS(0, 0, fchmod(3, 0400));
|
||||
ASSERT_EQ(0400, GetMode(3));
|
||||
ASSERT_SYS(0, 0, fchmod(3, 0600));
|
||||
ASSERT_EQ(0600, GetMode(3));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
Loading…
Reference in a new issue