From dcf9596620a94664b9b46973e35194d7e94c31c4 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 7 Oct 2024 15:29:01 -0700 Subject: [PATCH] Make more fixups and quality assurance --- libc/calls/getgroups.c | 1 - libc/calls/pipe-nt.c | 3 --- libc/calls/poll-nt.c | 7 ++--- libc/calls/ppoll.c | 20 ++++++-------- libc/calls/pselect.c | 10 +------ libc/calls/select-nt.c | 22 ++------------- libc/calls/select.c | 5 +--- libc/calls/setgroups.c | 1 - libc/sock/internal.h | 3 ++- libc/sock/send-nt.c | 5 ++-- libc/sock/sendto-nt.c | 5 ++-- libc/sock/struct/pollfd.internal.h | 3 ++- libc/stdio/fwrite_unlocked.c | 3 +-- libc/stdio/vfprintf_unlocked.c | 11 +++----- test/posix/printf_return_test.c | 43 ++++++++++++++++++++++++++++++ third_party/nsync/README.cosmo | 4 --- third_party/nsync/mu.c | 12 ++++----- 17 files changed, 80 insertions(+), 78 deletions(-) create mode 100644 test/posix/printf_return_test.c diff --git a/libc/calls/getgroups.c b/libc/calls/getgroups.c index d4c8fe1a9..25251453b 100644 --- a/libc/calls/getgroups.c +++ b/libc/calls/getgroups.c @@ -21,7 +21,6 @@ #include "libc/dce.h" #include "libc/intrin/describeflags.h" #include "libc/intrin/strace.h" -#include "libc/stdckdint.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/calls/pipe-nt.c b/libc/calls/pipe-nt.c index d2ed971e0..40a16c375 100644 --- a/libc/calls/pipe-nt.c +++ b/libc/calls/pipe-nt.c @@ -56,7 +56,6 @@ static textwindows int sys_pipe_nt_impl(int pipefd[2], unsigned flags) { __fds_unlock(); hin = CreateNamedPipe(pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped, mode, 1, PIPE_BUF, PIPE_BUF, 0, &kNtIsInheritable); - __fds_lock(); if (hin != -1) { if ((hout = CreateFile( pipename, kNtGenericWrite, @@ -73,7 +72,6 @@ static textwindows int sys_pipe_nt_impl(int pipefd[2], unsigned flags) { g_fds.p[writer].handle = hout; pipefd[0] = reader; pipefd[1] = writer; - __fds_unlock(); return 0; } else { CloseHandle(hin); @@ -81,7 +79,6 @@ static textwindows int sys_pipe_nt_impl(int pipefd[2], unsigned flags) { } __releasefd(writer); __releasefd(reader); - __fds_unlock(); return -1; } diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index 23a54ffb5..63ea83c81 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -351,13 +351,14 @@ textwindows static int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds, } } -textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms, +textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, + const struct timespec *relative, const sigset_t *sigmask) { int rc; struct timespec now, timeout, deadline; BLOCK_SIGNALS; - now = ms ? sys_clock_gettime_monotonic_nt() : timespec_zero; - timeout = ms ? timespec_frommillis(*ms) : timespec_max; + now = relative ? sys_clock_gettime_monotonic_nt() : timespec_zero; + timeout = relative ? *relative : timespec_max; deadline = timespec_add(now, timeout); rc = sys_poll_nt_impl(fds, nfds, deadline, sigmask ? *sigmask : _SigMask); ALLOW_SIGNALS; diff --git a/libc/calls/ppoll.c b/libc/calls/ppoll.c index 322937e31..d961a27f4 100644 --- a/libc/calls/ppoll.c +++ b/libc/calls/ppoll.c @@ -25,6 +25,7 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/strace.h" +#include "libc/limits.h" #include "libc/runtime/stack.h" #include "libc/sock/struct/pollfd.h" #include "libc/sock/struct/pollfd.internal.h" @@ -76,10 +77,13 @@ static int ppoll_impl(struct pollfd *fds, size_t nfds, } fdcount = sys_ppoll(fds, nfds, tsp, sigmask, 8); if (fdcount == -1 && errno == ENOSYS) { - int ms; + int64_t ms; errno = e; - if (!timeout || ckd_add(&ms, timeout->tv_sec, - (timeout->tv_nsec + 999999) / 1000000)) { + if (timeout) { + ms = timespec_tomillis(*timeout); + if (ms > INT_MAX) + ms = -1; + } else { ms = -1; } if (sigmask) @@ -89,15 +93,7 @@ static int ppoll_impl(struct pollfd *fds, size_t nfds, sys_sigprocmask(SIG_SETMASK, &oldmask, 0); } } else { - uint32_t ms; - uint32_t *msp; - if (timeout && - !ckd_add(&ms, timeout->tv_sec, (timeout->tv_nsec + 999999) / 1000000)) { - msp = &ms; - } else { - msp = 0; - } - fdcount = sys_poll_nt(fds, nfds, msp, sigmask); + fdcount = sys_poll_nt(fds, nfds, timeout, sigmask); } if (IsOpenbsd() && fdcount != -1) { diff --git a/libc/calls/pselect.c b/libc/calls/pselect.c index e154a773a..93c7f495f 100644 --- a/libc/calls/pselect.c +++ b/libc/calls/pselect.c @@ -67,7 +67,6 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) { int rc; - struct timeval tv, *tvp; struct timespec ts, *tsp; struct { const sigset_t *s; @@ -111,14 +110,7 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, rc = sys_pselect(nfds, readfds, writefds, exceptfds, (struct timespec *)timeout, sigmask); } else { - if (timeout) { - tv.tv_sec = timeout->tv_sec; - tv.tv_usec = timeout->tv_nsec / 1000; - tvp = &tv; - } else { - tvp = 0; - } - rc = sys_select_nt(nfds, readfds, writefds, exceptfds, tvp, sigmask); + rc = sys_select_nt(nfds, readfds, writefds, exceptfds, timeout, sigmask); } } END_CANCELATION_POINT; diff --git a/libc/calls/select-nt.c b/libc/calls/select-nt.c index cbb6797bf..0d9e2f2e0 100644 --- a/libc/calls/select-nt.c +++ b/libc/calls/select-nt.c @@ -25,7 +25,6 @@ #include "libc/sock/sock.h" #include "libc/sock/struct/pollfd.h" #include "libc/sock/struct/pollfd.internal.h" -#include "libc/stdckdint.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/errfuns.h" #ifdef __x86_64__ @@ -44,7 +43,7 @@ // int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds, - fd_set *exceptfds, struct timeval *timeout, + fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) { int pfds = 0; @@ -68,21 +67,8 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds, } } - // convert the wait time to a word - uint32_t millis; - if (!timeout) { - millis = -1u; - } else { - int64_t ms = timeval_tomillis(*timeout); - if (ms < 0 || ms > UINT32_MAX) { - millis = -1u; - } else { - millis = ms; - } - } - // call our nt poll implementation - int fdcount = sys_poll_nt(fds, pfds, &millis, sigmask); + int fdcount = sys_poll_nt(fds, pfds, timeout, sigmask); if (fdcount == -1) return -1; @@ -115,10 +101,6 @@ int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds, } } - // store remaining time back in caller's timeval - if (timeout) - *timeout = timeval_frommillis(millis); - return bits; } diff --git a/libc/calls/select.c b/libc/calls/select.c index e90f69bdb..93704b269 100644 --- a/libc/calls/select.c +++ b/libc/calls/select.c @@ -31,10 +31,7 @@ * such as out-of-band data on a socket; it is equivalent to POLLPRI * in the revents of poll() * @param timeout may be null which means to block indefinitely; cosmo's - * implementation of select() never modifies this parameter which is - * how most platforms except Linux work which modifies it to reflect - * elapsed time, noting that POSIX permits either behavior therefore - * portable code should assume that timeout memory becomes undefined + * implementation of select() never modifies this parameter * @raise E2BIG if we exceeded the 64 socket limit on Windows * @raise ECANCELED if thread was cancelled in masked mode * @raise EINTR if signal was delivered diff --git a/libc/calls/setgroups.c b/libc/calls/setgroups.c index d030239bb..534f5962a 100644 --- a/libc/calls/setgroups.c +++ b/libc/calls/setgroups.c @@ -21,7 +21,6 @@ #include "libc/dce.h" #include "libc/intrin/describeflags.h" #include "libc/intrin/strace.h" -#include "libc/stdckdint.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 9dbd690dc..927b531fe 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -2,6 +2,7 @@ #define COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_ #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/sigset.h" +#include "libc/calls/struct/timespec.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/thunk/msabi.h" #include "libc/nt/winsock.h" @@ -60,7 +61,7 @@ int sys_socketpair_nt_stream(int, int, int, int[2]) ; int sys_socketpair_nt_dgram(int, int, int, int[2]) ; */ int sys_socketpair_nt(int, int, int, int[2]); -int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *, +int sys_select_nt(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *); size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *, size_t); diff --git a/libc/sock/send-nt.c b/libc/sock/send-nt.c index c9169003c..ba0570665 100644 --- a/libc/sock/send-nt.c +++ b/libc/sock/send-nt.c @@ -66,8 +66,9 @@ textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen, __sig_unblock(waitmask); - if (rc == -1 && errno == WSAESHUTDOWN) { // ESHUTDOWN - errno = kNtErrorBrokenPipe; // EPIPE + if (rc == -1 && (errno == WSAESHUTDOWN || // ESHUTDOWN + errno == WSAECONNABORTED)) { // ECONNABORTED + errno = kNtErrorBrokenPipe; // EPIPE if (!(flags & _MSG_NOSIGNAL)) __sig_raise(SIGPIPE, SI_KERNEL); } diff --git a/libc/sock/sendto-nt.c b/libc/sock/sendto-nt.c index 831cf6552..f0be2f4c9 100644 --- a/libc/sock/sendto-nt.c +++ b/libc/sock/sendto-nt.c @@ -71,8 +71,9 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov, __sig_unblock(waitmask); - if (rc == -1 && errno == WSAESHUTDOWN) { // ESHUTDOWN - errno = kNtErrorBrokenPipe; // EPIPE + if (rc == -1 && (errno == WSAESHUTDOWN || // ESHUTDOWN + errno == WSAECONNABORTED)) { // ECONNABORTED + errno = kNtErrorBrokenPipe; // EPIPE if (!(flags & _MSG_NOSIGNAL)) __sig_raise(SIGPIPE, SI_KERNEL); } diff --git a/libc/sock/struct/pollfd.internal.h b/libc/sock/struct/pollfd.internal.h index 0594fa57c..69f58d30d 100644 --- a/libc/sock/struct/pollfd.internal.h +++ b/libc/sock/struct/pollfd.internal.h @@ -11,7 +11,8 @@ int32_t __sys_poll(struct pollfd *, uint64_t, signed); int sys_ppoll(struct pollfd *, size_t, const struct timespec *, const sigset_t *, size_t); int sys_poll_metal(struct pollfd *, size_t, unsigned); -int sys_poll_nt(struct pollfd *, uint64_t, uint32_t *, const sigset_t *); +int sys_poll_nt(struct pollfd *, uint64_t, const struct timespec *, + const sigset_t *); const char *_DescribePollFds(char[300], ssize_t, struct pollfd *, size_t); #define DescribePollFds(x, y, z) _DescribePollFds(alloca(300), x, y, z) diff --git a/libc/stdio/fwrite_unlocked.c b/libc/stdio/fwrite_unlocked.c index 4fa7c4d04..927f05c8c 100644 --- a/libc/stdio/fwrite_unlocked.c +++ b/libc/stdio/fwrite_unlocked.c @@ -74,9 +74,8 @@ size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) { size_t n, m; const char *p; struct iovec iov[2]; - if (!stride || !count) { + if (!stride || !count) return 0; - } if ((f->iomode & O_ACCMODE) == O_RDONLY) { f->state = errno = EBADF; return 0; diff --git a/libc/stdio/vfprintf_unlocked.c b/libc/stdio/vfprintf_unlocked.c index d65bfc089..d0285dcbd 100644 --- a/libc/stdio/vfprintf_unlocked.c +++ b/libc/stdio/vfprintf_unlocked.c @@ -19,6 +19,7 @@ #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/fmt/internal.h" +#include "libc/intrin/kprintf.h" #include "libc/stdckdint.h" #include "libc/stdio/internal.h" #include "libc/stdio/stdio.h" @@ -46,9 +47,8 @@ static int __vfprintf_flbuf(const char *s, struct state *t, size_t n) { } else { rc = -1; } - if (ckd_add(&t->n, t->n, n)) { + if (ckd_add(&t->n, t->n, n)) rc = eoverflow(); - } } else { rc = 0; } @@ -60,9 +60,8 @@ static int __vfprintf_nbuf(const char *s, struct state *t, size_t n) { for (i = 0; i < n; ++i) { t->b.p[t->b.n++] = s[i]; if (t->b.n == sizeof(t->b.p)) { - if (!fwrite_unlocked(t->b.p, 1, t->b.n, t->f)) { + if (!fwrite_unlocked(t->b.p, 1, t->b.n, t->f)) return -1; - } t->b.n = 0; } else if (ckd_add(&t->n, t->n, 1)) { return eoverflow(); @@ -91,9 +90,7 @@ int vfprintf_unlocked(FILE *f, const char *fmt, va_list va) { if (!st.b.n) { rc = st.n; } else if (fwrite_unlocked(st.b.p, 1, st.b.n, st.f)) { - if (ckd_add(&rc, st.n, st.b.n)) { - rc = eoverflow(); - } + rc = st.n; } else { rc = -1; } diff --git a/test/posix/printf_return_test.c b/test/posix/printf_return_test.c new file mode 100644 index 000000000..377bb9c7f --- /dev/null +++ b/test/posix/printf_return_test.c @@ -0,0 +1,43 @@ +// Copyright 2024 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 +#include +#include + +int main() { + + if (close(1)) + return 1; + if (open("/dev/null", O_WRONLY) != 1) + return 2; + + if (printf("a") != 1) + return 4; + if (printf("%s", "") != 0) + return 5; + if (printf("%s", "a") != 1) + return 6; + if (printf("%10s", "a") != 10) + return 6; + if (printf("%-10s", "a") != 10) + return 6; + if (printf("%-10s%-40s %9s %8s %8s %8s\n", "Benchmark", "prog", "ops", + "time", "ops/sec", "time/op") != 89) + return 7; + if (fprintf(stdout, "%-10s%-40s %9s %8s %8s %8s\n", "Benchmark", "prog", + "ops", "time", "ops/sec", "time/op") != 89) + return 8; +} diff --git a/third_party/nsync/README.cosmo b/third_party/nsync/README.cosmo index 34eb18291..fefc56bf6 100644 --- a/third_party/nsync/README.cosmo +++ b/third_party/nsync/README.cosmo @@ -33,10 +33,6 @@ LOCAL CHANGES lets us use weak cas when appropriate. It also avoids a superfluous relaxed load on failure. This mostly impacts aarch64, not x86_64. - - Modified *NSYNC to allocate waiter objects on the stack. We need it - because we use *NSYNC mutexes to implement POSIX mutexes, which are - too low-level to safely depend on malloc, or even mmap in our case. - - Rewrote most of the semaphore and futex system call support code so it works well with Cosmopolitan's fat runtime portability. *NSYNC's unit test suite passes on all supported platforms. However the BSDs diff --git a/third_party/nsync/mu.c b/third_party/nsync/mu.c index 317add4fe..8e172e8ba 100644 --- a/third_party/nsync/mu.c +++ b/third_party/nsync/mu.c @@ -477,9 +477,9 @@ void nsync_mu_unlock (nsync_mu *mu) { and deallocate the mutex before the current thread touched the mutex word again. */ uint32_t old_word = MU_WLOCK; - if (!atomic_compare_exchange_weak_explicit (&mu->word, &old_word, 0, - memory_order_release, - memory_order_relaxed)) { + if (!atomic_compare_exchange_strong_explicit (&mu->word, &old_word, 0, + memory_order_release, + memory_order_relaxed)) { /* Clear MU_ALL_FALSE because the critical section we're just leaving may have made some conditions true. */ uint32_t new_word = (old_word - MU_WLOCK) & ~MU_ALL_FALSE; @@ -508,9 +508,9 @@ void nsync_mu_runlock (nsync_mu *mu) { IGNORE_RACES_START (); /* See comment in nsync_mu_unlock(). */ uint32_t old_word = MU_RLOCK; - if (!atomic_compare_exchange_weak_explicit (&mu->word, &old_word, 0, - memory_order_release, - memory_order_relaxed)) { + if (!atomic_compare_exchange_strong_explicit (&mu->word, &old_word, 0, + memory_order_release, + memory_order_relaxed)) { /* Sanity check: mutex must not be held in write mode and reader count must not be 0. */ if (((old_word ^ MU_WLOCK) & (MU_WLOCK | MU_RLOCK_FIELD)) == 0) {