From 949c398327e5a8a7474104391543560f3d7d8576 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sun, 15 Sep 2024 02:45:16 -0700 Subject: [PATCH] Clean up more code --- libc/calls/poll-nt.c | 9 +- libc/calls/read-nt.c | 135 ++++++++++++---------- libc/calls/readwrite-nt.c | 14 +-- libc/calls/sig.c | 13 +-- libc/calls/sigtimedwait-nt.c | 13 ++- libc/proc/wait4-nt.c | 10 +- libc/sock/winsockblock.c | 13 ++- libc/thread/posixthread.internal.h | 7 +- third_party/python/Modules/selectmodule.c | 1 - 9 files changed, 108 insertions(+), 107 deletions(-) diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index b63c25f98..339bea6ff 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -30,6 +30,7 @@ #include "libc/nt/enum/filetype.h" #include "libc/nt/enum/wait.h" #include "libc/nt/errors.h" +#include "libc/nt/events.h" #include "libc/nt/files.h" #include "libc/nt/ipc.h" #include "libc/nt/runtime.h" @@ -114,7 +115,7 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds, } } else if (kind == kFdFile || kind == kFdConsole) { // we can use WaitForMultipleObjects() for these fds - if (pn < ARRAYLEN(fileindices) - 1) { // last slot for semaphore + if (pn < ARRAYLEN(fileindices) - 1) { // last slot for signal event fileindices[pn] = i; filehands[pn] = g_fds.p[fds[i].fd].handle; ++pn; @@ -230,8 +231,8 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds, if (__sigcheck(waitmask, false)) return -1; pt = _pthread_self(); - filehands[pn] = pt->pt_semaphore = CreateSemaphore(0, 0, 1, 0); - atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, + filehands[pn] = pt->pt_event = CreateEvent(0, 0, 0, 0); + atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, memory_order_release); wi = WaitForMultipleObjects(pn + 1, filehands, 0, waitfor); atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); @@ -240,7 +241,7 @@ textwindows static int sys_poll_nt_actual(struct pollfd *fds, uint64_t nfds, // win32 wait failure return __winerr(); } else if (wi == pn) { - // our semaphore was signalled + // our signal event was signalled if (__sigcheck(waitmask, false)) return -1; } else if ((wi ^ kNtWaitAbandoned) < pn) { diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index 141bc07df..c4da9d610 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -47,6 +47,7 @@ #include "libc/nt/enum/vk.h" #include "libc/nt/enum/wait.h" #include "libc/nt/errors.h" +#include "libc/nt/events.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/inputrecord.h" #include "libc/nt/synchronization.h" @@ -833,74 +834,80 @@ textwindows static void RestoreProcessedInput(uint32_t inmode) { textwindows static int CountConsoleInputBytesBlockingImpl(uint32_t ms, sigset_t waitmask, bool restartable) { - int sig; - int64_t sem; - uint32_t wi; - struct timespec now, deadline; InitConsole(); - deadline = + struct timespec deadline = timespec_add(sys_clock_gettime_monotonic_nt(), timespec_frommillis(ms)); -RestartOperation: - if (_check_cancel() == -1) - return -1; - if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) - goto DeliverSignal; - struct PosixThread *pt = _pthread_self(); - pt->pt_blkmask = waitmask; - pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0); - atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release); - wi = WaitForMultipleObjects(2, (int64_t[2]){__keystroke.cin, sem}, 0, ms); - atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); - CloseHandle(sem); - - // check for wait timeout - if (wi == kNtWaitTimeout) - return etimedout(); - - // handle event on console handle. this means we can now read from the - // conosle without blocking. so the first thing we do is slurp up your - // keystroke data. some of those keystrokes might cause a signal to be - // raised. so we need to check for pending signals again and handle it - if (wi == 0) { - int got = CountConsoleInputBytes(); - if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) - goto DeliverSignal; - if (got == -1) - // this is a bona fide eof and console errors are logged to strace - return 0; - if (got == 0) { - // this can happen for multiple reasons. first our driver controls - // user interactions in canonical mode. secondly we could lose the - // race with another thread that's reading input. - now = sys_clock_gettime_monotonic_nt(); - if (timespec_cmp(now, deadline) >= 0) - return etimedout(); - ms = timespec_tomillis(timespec_sub(deadline, now)); - ms = ms > -1u ? -1u : ms; - goto RestartOperation; - } - return got; - } - - // handle wait itself failing - if (wi != 1) - return __winerr(); - - // handle event on throwaway semaphore, it is poked by signal delivery - if (_weaken(__sig_get)) { - if (!(sig = _weaken(__sig_get)(waitmask))) - return eintr(); - DeliverSignal: - int handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask); - if (_check_cancel() == -1) + for (;;) { + int sig = 0; + intptr_t sev; + if (!(sev = CreateEvent(0, 0, 0, 0))) + return __winerr(); + struct PosixThread *pt = _pthread_self(); + pt->pt_event = sev; + pt->pt_blkmask = waitmask; + atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, + memory_order_release); + if (_check_cancel() == -1) { + atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); + CloseHandle(sev); return -1; - if (handler_was_called & SIG_HANDLED_NO_RESTART) - return eintr(); - if (handler_was_called & SIG_HANDLED_SA_RESTART) - if (!restartable) + } + if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) { + atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); + CloseHandle(sev); + goto DeliverSignal; + } + struct timespec now = sys_clock_gettime_monotonic_nt(); + struct timespec remain = timespec_subz(deadline, now); + int64_t millis = timespec_tomillis(remain); + uint32_t waitms = MIN(millis, 0xffffffffu); + intptr_t hands[] = {__keystroke.cin, sev}; + uint32_t wi = WaitForMultipleObjects(2, hands, 0, waitms); + atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); + CloseHandle(sev); + if (wi == -1u) + return __winerr(); + + // check for wait timeout + if (wi == kNtWaitTimeout) + return etimedout(); + + // handle event on console handle. this means we can now read from the + // conosle without blocking. so the first thing we do is slurp up your + // keystroke data. some of those keystrokes might cause a signal to be + // raised. so we need to check for pending signals again and handle it + if (wi == 0) { + int got = CountConsoleInputBytes(); + // we might have read a keystroke that generated a signal + if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) + goto DeliverSignal; + if (got == -1) + // this is a bona fide eof and console errors are logged to strace + return 0; + if (got == 0) + // this can happen for multiple reasons. first our driver controls + // user interactions in canonical mode. secondly we could lose the + // race with another thread that's reading input. + continue; + return got; + } + + if (wi == 1 && _weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) { + // handle event on throwaway semaphore, it is poked by signal delivery + DeliverSignal:; + int handler_was_called = 0; + do { + handler_was_called |= _weaken(__sig_relay)(sig, SI_KERNEL, waitmask); + } while ((sig = _weaken(__sig_get)(waitmask))); + if (_check_cancel() == -1) + return -1; + if (handler_was_called & SIG_HANDLED_NO_RESTART) return eintr(); + if (handler_was_called & SIG_HANDLED_SA_RESTART) + if (!restartable) + return eintr(); + } } - goto RestartOperation; } textwindows static int CountConsoleInputBytesBlocking(uint32_t ms, @@ -911,7 +918,7 @@ textwindows static int CountConsoleInputBytesBlocking(uint32_t ms, if (got > 0) return got; uint32_t inmode = DisableProcessedInput(); - int rc = CountConsoleInputBytesBlockingImpl(ms, waitmask, false); + int rc = CountConsoleInputBytesBlockingImpl(ms, waitmask, true); RestoreProcessedInput(inmode); return rc; } diff --git a/libc/calls/readwrite-nt.c b/libc/calls/readwrite-nt.c index 2f9a7d8d5..e1c059223 100644 --- a/libc/calls/readwrite-nt.c +++ b/libc/calls/readwrite-nt.c @@ -104,13 +104,13 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset, // atomic block on i/o completion, signal, or cancel // it's not safe to acknowledge cancelation from here // it's not safe to call any signal handlers from here - intptr_t sem; - if ((sem = CreateSemaphore(0, 0, 1, 0))) { + intptr_t sigev; + if ((sigev = CreateEvent(0, 0, 0, 0))) { // installing semaphore before sig get makes wait atomic struct PosixThread *pt = _pthread_self(); - pt->pt_semaphore = sem; + pt->pt_event = sigev; pt->pt_blkmask = waitmask; - atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, + atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, memory_order_release); if (_is_canceled()) { CancelIoEx(handle, &overlap); @@ -118,9 +118,9 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset, (got_sig = _weaken(__sig_get)(waitmask))) { CancelIoEx(handle, &overlap); } else { - intptr_t hands[] = {event, sem}; + intptr_t hands[] = {event, sigev}; uint32_t wi = WaitForMultipleObjects(2, hands, 0, -1u); - if (wi == 1) { // semaphore was signaled by signal enqueue + if (wi == 1) { // event was signaled by signal enqueue CancelIoEx(handle, &overlap); if (_weaken(__sig_get)) got_sig = _weaken(__sig_get)(waitmask); @@ -130,7 +130,7 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset, } } atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); - CloseHandle(sem); + CloseHandle(sigev); } else { other_error = GetLastError(); CancelIoEx(handle, &overlap); diff --git a/libc/calls/sig.c b/libc/calls/sig.c index 7c82c31de..fc2275e8d 100644 --- a/libc/calls/sig.c +++ b/libc/calls/sig.c @@ -40,6 +40,7 @@ #include "libc/nt/enum/exceptionhandleractions.h" #include "libc/nt/enum/signal.h" #include "libc/nt/enum/status.h" +#include "libc/nt/events.h" #include "libc/nt/runtime.h" #include "libc/nt/signals.h" #include "libc/nt/struct/ntexceptionpointers.h" @@ -230,16 +231,10 @@ textwindows void __sig_cancel(struct PosixThread *pt, int sig, unsigned flags) { STRACE("%G sent to %d asynchronously", sig, _pthread_tid(pt)); return; } - // we can cancel another thread's overlapped i/o op after the freeze - if (blocker == PT_BLOCKER_IO) { - STRACE("%G canceling %d's i/o", sig, _pthread_tid(pt)); - CancelIoEx(pt->pt_iohandle, pt->pt_ioverlap); - return; - } // threads can create semaphores on an as-needed basis - if (blocker == PT_BLOCKER_SEM) { - STRACE("%G releasing %d's semaphore", sig, _pthread_tid(pt)); - ReleaseSemaphore(pt->pt_semaphore, 1, 0); + if (blocker == PT_BLOCKER_EVENT) { + STRACE("%G set %d's event object", sig, _pthread_tid(pt)); + SetEvent(pt->pt_event); return; } // all other blocking ops that aren't overlap should use futexes diff --git a/libc/calls/sigtimedwait-nt.c b/libc/calls/sigtimedwait-nt.c index fdf652cf8..9deaa9d33 100644 --- a/libc/calls/sigtimedwait-nt.c +++ b/libc/calls/sigtimedwait-nt.c @@ -25,6 +25,7 @@ #include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/atomic.h" #include "libc/macros.h" +#include "libc/nt/events.h" #include "libc/nt/runtime.h" #include "libc/nt/synchronization.h" #include "libc/str/str.h" @@ -85,7 +86,7 @@ textwindows static int sys_sigtimedwait_nt_impl(sigset_t syncsigs, textwindows int sys_sigtimedwait_nt(const sigset_t *set, siginfo_t *opt_info, const struct timespec *opt_timeout) { int rc; - intptr_t sem; + intptr_t sev; struct PosixThread *pt; struct timespec deadline; sigset_t syncsigs, waitmask; @@ -95,17 +96,17 @@ textwindows int sys_sigtimedwait_nt(const sigset_t *set, siginfo_t *opt_info, } else { deadline = timespec_max; } - if ((sem = CreateSemaphore(0, 0, 1, 0))) { + if ((sev = CreateEvent(0, 0, 0, 0))) { syncsigs = *set & ~(1ull << (SIGTHR - 1)); // internal to pthreads waitmask = ~syncsigs & _SigMask; pt = _pthread_self(); + pt->pt_event = sev; pt->pt_blkmask = waitmask; - pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0); - atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, + atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, memory_order_release); - rc = sys_sigtimedwait_nt_impl(syncsigs, opt_info, deadline, waitmask, sem); + rc = sys_sigtimedwait_nt_impl(syncsigs, opt_info, deadline, waitmask, sev); atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); - CloseHandle(sem); + CloseHandle(sev); } else { rc = __winerr(); } diff --git a/libc/proc/wait4-nt.c b/libc/proc/wait4-nt.c index a00830fa0..0da6a31d3 100644 --- a/libc/proc/wait4-nt.c +++ b/libc/proc/wait4-nt.c @@ -131,15 +131,15 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options, // perform blocking operation uint32_t wi; - uintptr_t sem; + uintptr_t event; struct PosixThread *pt = _pthread_self(); pt->pt_blkmask = waitmask; - pt->pt_semaphore = sem = CreateSemaphore(0, 0, 1, 0); - atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, + pt->pt_event = event = CreateEvent(0, 0, 0, 0); + atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, memory_order_release); - wi = WaitForMultipleObjects(2, (intptr_t[2]){hWaitObject, sem}, 0, -1u); + wi = WaitForMultipleObjects(2, (intptr_t[2]){hWaitObject, event}, 0, -1u); atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); - CloseHandle(sem); + CloseHandle(event); // log warning if handle unexpectedly closed if (wi & kNtWaitAbandoned) { diff --git a/libc/sock/winsockblock.c b/libc/sock/winsockblock.c index 170c9e106..2e2e45446 100644 --- a/libc/sock/winsockblock.c +++ b/libc/sock/winsockblock.c @@ -27,6 +27,7 @@ #include "libc/intrin/weaken.h" #include "libc/nt/enum/wait.h" #include "libc/nt/errors.h" +#include "libc/nt/events.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/synchronization.h" @@ -75,13 +76,13 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock, // atomic block on i/o completion, signal, or cancel // it's not safe to acknowledge cancelation from here // it's not safe to call any signal handlers from here - intptr_t sem; - if ((sem = CreateSemaphore(0, 0, 1, 0))) { + intptr_t sev; + if ((sev = CreateEvent(0, 0, 0, 0))) { // installing semaphore before sig get makes wait atomic struct PosixThread *pt = _pthread_self(); - pt->pt_semaphore = sem; + pt->pt_event = sev; pt->pt_blkmask = waitmask; - atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, + atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, memory_order_release); if (_is_canceled()) { got_cancel = true; @@ -94,7 +95,7 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock, struct timespec remain = timespec_subz(deadline, now); int64_t millis = timespec_tomillis(remain); uint32_t waitms = MIN(millis, 0xffffffffu); - intptr_t hands[] = {event, sem}; + intptr_t hands[] = {event, sev}; uint32_t wi = WSAWaitForMultipleEvents(2, hands, 0, waitms, 0); if (wi == 1) { // semaphore was signaled by signal enqueue CancelIoEx(handle, &overlap); @@ -109,7 +110,7 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock, } } atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); - CloseHandle(sem); + CloseHandle(sev); } else { other_error = GetLastError(); CancelIoEx(handle, &overlap); diff --git a/libc/thread/posixthread.internal.h b/libc/thread/posixthread.internal.h index 938a73baf..40c84330d 100644 --- a/libc/thread/posixthread.internal.h +++ b/libc/thread/posixthread.internal.h @@ -9,8 +9,7 @@ #include "libc/thread/thread.h" #include "libc/thread/tls.h" -#define PT_BLOCKER_SEM ((atomic_int *)-1) -#define PT_BLOCKER_IO ((atomic_int *)-2) +#define PT_BLOCKER_EVENT ((atomic_int *)-1) COSMOPOLITAN_C_START_ @@ -86,10 +85,8 @@ struct PosixThread { struct _pthread_cleanup_buffer *pt_cleanup; _Atomic(atomic_int *) pt_blocker; uint64_t pt_blkmask; - int64_t pt_semaphore; - intptr_t pt_iohandle; + int64_t pt_event; locale_t pt_locale; - void *pt_ioverlap; jmp_buf pt_exiter; pthread_attr_t pt_attr; }; diff --git a/third_party/python/Modules/selectmodule.c b/third_party/python/Modules/selectmodule.c index 265e90b13..e79dafb11 100644 --- a/third_party/python/Modules/selectmodule.c +++ b/third_party/python/Modules/selectmodule.c @@ -9,7 +9,6 @@ #include "libc/errno.h" #include "libc/mem/gc.h" #include "libc/mem/mem.h" -#include "libc/nt/efi.h" #include "libc/sock/select.h" #include "libc/sock/sock.h" #include "libc/sock/struct/pollfd.h"