Clean up more code

This commit is contained in:
Justine Tunney 2024-09-15 02:45:16 -07:00
parent baf70af780
commit 949c398327
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
9 changed files with 108 additions and 107 deletions

View file

@ -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) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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();
}

View file

@ -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) {

View file

@ -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);

View file

@ -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;
};

View file

@ -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"