From 9d372f48dd263c20138828842ff8655d694f7e61 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 9 Oct 2023 20:18:48 -0700 Subject: [PATCH] Fix some issues --- ape/ape-m1.c | 53 +++++++++++++++- ape/loader.c | 1 + libc/calls/assertfail.c | 2 +- libc/calls/clock_nanosleep-xnu.c | 4 +- libc/calls/clock_nanosleep.c | 17 +++++- libc/calls/sigaction.c | 20 +++++- libc/calls/sigaltstack.c | 11 +++- libc/calls/sigenter-xnu.c | 16 ++--- libc/calls/sleep.c | 25 ++++++-- libc/calls/struct/sigaction.internal.h | 7 +++ libc/calls/timespec_sleep.c | 23 +++++-- libc/calls/timespec_sleep_until.c | 2 +- libc/calls/usleep.c | 5 +- libc/log/appendresourcereport.c | 3 + libc/proc/execve-nt.greg.c | 5 +- libc/runtime/syslib.internal.h | 9 +++ libc/stdio/printargs.c | 2 + libc/thread/pthread_cancel.c | 13 ++-- libc/thread/sem_open.c | 42 +++++++++++-- libc/thread/sem_post.c | 10 +++ libc/thread/sem_timedwait.c | 48 ++++++++++++++- libc/thread/sem_trywait.c | 10 +++ libc/thread/semaphore.h | 2 + test/libc/thread/pthread_cancel_test.c | 27 ++++++++ test/libc/thread/pthread_kill_test.c | 3 - .../Modules/_multiprocessing/semaphore.c | 2 +- tool/build/runit.c | 7 --- tool/viz/clock_nanosleep_accuracy.c | 6 -- tool/viz/setitimer_accuracy.c | 61 +++++++++++++++++++ 29 files changed, 373 insertions(+), 63 deletions(-) create mode 100644 tool/viz/setitimer_accuracy.c diff --git a/ape/ape-m1.c b/ape/ape-m1.c index d77cefd5161..9fdcc885e88 100644 --- a/ape/ape-m1.c +++ b/ape/ape-m1.c @@ -30,10 +30,11 @@ #include #include #include +#include #define pagesz 16384 #define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24) -#define SYSLIB_VERSION 4 +#define SYSLIB_VERSION 5 struct Syslib { int magic; @@ -79,6 +80,15 @@ struct Syslib { long (*pselect)(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *); long (*mprotect)(void *, size_t, int); + /* v5 (2023-10-09) */ + long (*sigaltstack)(const stack_t *, stack_t *); + long (*getentropy)(void *, size_t); + long (*sem_open)(const char *, int, uint16_t, unsigned); + long (*sem_unlink)(const char *); + long (*sem_close)(int *); + long (*sem_post)(int *); + long (*sem_wait)(int *); + long (*sem_trywait)(int *); }; #define ELFCLASS32 1 @@ -350,6 +360,7 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) { if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0; if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; MemMove(ps->path + pathlen, ps->name, ps->namelen); + ps->path[pathlen + ps->namelen] = 0; return !access(ps->path, X_OK); } @@ -795,6 +806,38 @@ static long sys_mprotect(void *data, size_t size, int prot) { return sysret(mprotect(data, size, prot)); } +static long sys_sigaltstack(const stack_t *ss, stack_t *oss) { + return sysret(sigaltstack(ss, oss)); +} + +static long sys_getentropy(void *buf, size_t buflen) { + return sysret(getentropy(buf, buflen)); +} + +static long sys_sem_open(const char *name, int oflags, mode_t mode, unsigned value) { + return sysret((long)sem_open(name, oflags, mode, value)); +} + +static long sys_sem_unlink(const char *name) { + return sysret(sem_unlink(name)); +} + +static long sys_sem_close(sem_t *sem) { + return sysret(sem_close(sem)); +} + +static long sys_sem_post(sem_t *sem) { + return sysret(sem_post(sem)); +} + +static long sys_sem_wait(sem_t *sem) { + return sysret(sem_wait(sem)); +} + +static long sys_sem_trywait(sem_t *sem) { + return sysret(sem_trywait(sem)); +} + static long sys_write(int fd, const void *data, size_t size) { return sysret(write(fd, data, size)); } @@ -879,6 +922,14 @@ int main(int argc, char **argv, char **envp) { M->lib.sigaction = sys_sigaction; M->lib.pselect = sys_pselect; M->lib.mprotect = sys_mprotect; + M->lib.sigaltstack = sys_sigaltstack; + M->lib.getentropy = sys_getentropy; + M->lib.sem_open = sys_sem_open; + M->lib.sem_unlink = sys_sem_unlink; + M->lib.sem_close = sys_sem_close; + M->lib.sem_post = sys_sem_post; + M->lib.sem_wait = sys_sem_wait; + M->lib.sem_trywait = sys_sem_trywait; /* getenv("_") is close enough to at_execfn */ execfn = argc > 0 ? argv[0] : 0; diff --git a/ape/loader.c b/ape/loader.c index 74b2cf6f443..67b96f9a3b9 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -538,6 +538,7 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) { if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0; if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; MemMove(ps->path + pathlen, ps->name, ps->namelen); + ps->path[pathlen + ps->namelen] = 0; return !Access(ps->path, X_OK, ps->os); } diff --git a/libc/calls/assertfail.c b/libc/calls/assertfail.c index a8fe202ee46..5399980864d 100644 --- a/libc/calls/assertfail.c +++ b/libc/calls/assertfail.c @@ -29,7 +29,7 @@ void __assert_fail(const char *expr, const char *file, int line) { char ibuf[12]; FormatInt32(ibuf, line); - tinyprint(2, "\n", file, ":", ibuf, ": assert(", expr, ") failed (", + tinyprint(2, file, ":", ibuf, ": assert(", expr, ") failed (", program_invocation_short_name, " ", DescribeBacktrace(__builtin_frame_address(0)), ")\n", NULL); abort(); diff --git a/libc/calls/clock_nanosleep-xnu.c b/libc/calls/clock_nanosleep-xnu.c index f0502ac007a..e8ad33c800e 100644 --- a/libc/calls/clock_nanosleep-xnu.c +++ b/libc/calls/clock_nanosleep-xnu.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.internal.h" #include "libc/calls/struct/timeval.h" @@ -27,6 +28,7 @@ #include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/timer.h" #include "libc/sysv/errfuns.h" +#include "libc/thread/posixthread.internal.h" #include "libc/thread/thread.h" int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req, @@ -74,7 +76,7 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req, } if (res == -EINTR && // (_weaken(pthread_testcancel_np) && // - _weaken(pthread_testcancel_np))) { + _weaken(pthread_testcancel_np)())) { return ecanceled(); } return _sysret(res); diff --git a/libc/calls/clock_nanosleep.c b/libc/calls/clock_nanosleep.c index ca69816c70d..3db418207f6 100644 --- a/libc/calls/clock_nanosleep.c +++ b/libc/calls/clock_nanosleep.c @@ -23,11 +23,14 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/strace.internal.h" +#include "libc/intrin/weaken.h" #include "libc/runtime/clktck.h" #include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/timer.h" #include "libc/sysv/errfuns.h" +#include "libc/thread/thread.h" static int sys_clock_nanosleep(int clock, int flags, // const struct timespec *req, @@ -45,6 +48,16 @@ static int sys_clock_nanosleep(int clock, int flags, // } else { rc = enosys(); } + if (rc > 0) { + errno = rc; + rc = -1; + } + // system call support might not detect cancelation on bsds + if (rc == -1 && errno == EINTR && // + _weaken(pthread_testcancel_np) && // + _weaken(pthread_testcancel_np)()) { + rc = ecanceled(); + } END_CANCELATION_POINT; STRACE("sys_clock_nanosleep(%s, %s, %s, [%s]) → %d% m", DescribeClockName(clock), DescribeSleepFlags(flags), @@ -62,11 +75,11 @@ static int cosmo_clock_nanosleep(int clock, int flags, if (clock == CLOCK_REALTIME || // clock == CLOCK_REALTIME_PRECISE) { time_clock = clock; - sleep_clock = CLOCK_REALTIME_PRECISE; + sleep_clock = CLOCK_REALTIME; } else if (clock == CLOCK_MONOTONIC || // clock == CLOCK_MONOTONIC_PRECISE) { time_clock = clock; - sleep_clock = CLOCK_MONOTONIC_PRECISE; + sleep_clock = CLOCK_MONOTONIC; } else if (clock == CLOCK_REALTIME_COARSE || // clock == CLOCK_REALTIME_FAST) { return sys_clock_nanosleep(CLOCK_REALTIME, flags, req, rem); diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index e03791afc06..10d4df1c225 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -41,6 +41,7 @@ #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/syslib.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/limits.h" #include "libc/sysv/consts/sa.h" @@ -70,6 +71,10 @@ static void sigaction_cosmo2native(union metasigaction *sa) { sa->linux.sa_restorer = restorer; sa->linux.sa_mask[0] = masklo; sa->linux.sa_mask[1] = maskhi; + } else if (IsXnuSilicon()) { + sa->silicon.sa_flags = flags; + sa->silicon.sa_handler = handler; + sa->silicon.sa_mask[0] = masklo; } else if (IsXnu()) { sa->xnu_in.sa_flags = flags; sa->xnu_in.sa_handler = handler; @@ -109,6 +114,10 @@ static void sigaction_native2cosmo(union metasigaction *sa) { restorer = sa->linux.sa_restorer; masklo = sa->linux.sa_mask[0]; maskhi = sa->linux.sa_mask[1]; + } else if (IsXnu()) { + flags = sa->silicon.sa_flags; + handler = sa->silicon.sa_handler; + masklo = sa->silicon.sa_mask[0]; } else if (IsXnu()) { flags = sa->xnu_out.sa_flags; handler = sa->xnu_out.sa_handler; @@ -142,6 +151,7 @@ static int __sigaction(int sig, const struct sigaction *act, (sizeof(struct sigaction) >= sizeof(struct sigaction_linux) && sizeof(struct sigaction) >= sizeof(struct sigaction_xnu_in) && sizeof(struct sigaction) >= sizeof(struct sigaction_xnu_out) && + sizeof(struct sigaction) >= sizeof(struct sigaction_silicon) && sizeof(struct sigaction) >= sizeof(struct sigaction_freebsd) && sizeof(struct sigaction) >= sizeof(struct sigaction_openbsd) && sizeof(struct sigaction) >= sizeof(struct sigaction_netbsd)), @@ -193,6 +203,9 @@ static int __sigaction(int sig, const struct sigaction *act, // mitigate Rosetta signal handling strangeness // https://github.com/jart/cosmopolitan/issues/455 ap->sa_flags |= SA_SIGINFO; + } else if (IsXnu()) { + sigenter = __sigenter_xnu; + ap->sa_flags |= SA_SIGINFO; // couldn't hurt } else if (IsNetbsd()) { sigenter = __sigenter_netbsd; } else if (IsFreebsd()) { @@ -231,7 +244,12 @@ static int __sigaction(int sig, const struct sigaction *act, arg4 = 8; /* or linux whines */ arg5 = 0; } - if ((rc = sys_sigaction(sig, ap, oldact, arg4, arg5)) != -1) { + if (!IsXnuSilicon()) { + rc = sys_sigaction(sig, ap, oldact, arg4, arg5); + } else { + rc = _sysret(__syslib->__sigaction(sig, ap, oldact)); + } + if (rc != -1) { sigaction_native2cosmo((union metasigaction *)oldact); } } else { diff --git a/libc/calls/sigaltstack.c b/libc/calls/sigaltstack.c index 8afcb94ba76..69ea9bb84d5 100644 --- a/libc/calls/sigaltstack.c +++ b/libc/calls/sigaltstack.c @@ -25,6 +25,7 @@ #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/syslib.internal.h" #include "libc/sysv/consts/ss.h" #include "libc/sysv/errfuns.h" #include "libc/thread/tls.h" @@ -82,9 +83,17 @@ static textwindows int sigaltstack_cosmo(const struct sigaltstack *neu, static int sigaltstack_bsd(const struct sigaltstack *neu, struct sigaltstack *old) { + int rc; struct sigaltstack_bsd oldbsd, neubsd, *neup = 0; if (neu) sigaltstack2bsd(&neubsd, neu), neup = &neubsd; - if (sys_sigaltstack(neup, &oldbsd) == -1) return -1; + if (IsXnuSilicon()) { + rc = _sysret(__syslib->__sigaltstack(neup, &oldbsd)); + } else { + rc = sys_sigaltstack(neup, &oldbsd); + } + if (rc == -1) { + return -1; + } if (old) sigaltstack2linux(old, &oldbsd); return 0; } diff --git a/libc/calls/sigenter-xnu.c b/libc/calls/sigenter-xnu.c index 741839ab41d..fb6628fed00 100644 --- a/libc/calls/sigenter-xnu.c +++ b/libc/calls/sigenter-xnu.c @@ -486,9 +486,14 @@ static privileged void linuxssefpustate2xnu( #endif /* __x86_64__ */ +#ifdef __x86_64__ privileged void __sigenter_xnu(void *fn, int infostyle, int sig, struct siginfo_xnu *xnuinfo, struct __darwin_ucontext *xnuctx) { +#else +privileged void __sigenter_xnu(int sig, struct siginfo_xnu *xnuinfo, + struct __darwin_ucontext *xnuctx) { +#endif #pragma GCC push_options #pragma GCC diagnostic ignored "-Wframe-larger-than=" struct Goodies { @@ -579,15 +584,6 @@ privileged void __sigenter_xnu(void *fn, int infostyle, int sig, : "=a"(ax) : "0"(0x20000b8 /* sigreturn */), "D"(xnuctx), "S"(infostyle) : "rcx", "r11", "memory", "cc"); -#else - register long r0 asm("x0") = (long)xnuctx; - register long r1 asm("x1") = (long)infostyle; - asm volatile("mov\tx16,%0\n\t" - "svc\t0" - : /* no outputs */ - : "i"(0x0b8 /* sigreturn */), "r"(r0), "r"(r1) - : "x16", "memory"); -#endif /* __x86_64__ */ - notpossible; +#endif /* __x86_64__ */ } diff --git a/libc/calls/sleep.c b/libc/calls/sleep.c index 639b74380cc..18d7c555994 100644 --- a/libc/calls/sleep.c +++ b/libc/calls/sleep.c @@ -17,32 +17,45 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/calls/blockcancel.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/errno.h" #include "libc/limits.h" #include "libc/sysv/consts/clock.h" +#include "libc/thread/posixthread.internal.h" +#include "libc/thread/thread.h" #include "libc/time/time.h" /** * Sleeps for particular number of seconds. * + * This function may be canceled except when using masked mode in which + * case cancelation is temporarily disabled, because there is no way to + * report the ECANCELED state. + * * @return 0 if the full time elapsed, otherwise we assume an interrupt * was delivered, in which case the errno condition is ignored, and * this function shall return the number of unslept seconds rounded - * using the ceiling function, and finally `-1u` may be returned if - * thread was cancelled with `PTHREAD_CANCEL_MASKED` in play + * using the ceiling function * @see clock_nanosleep() * @cancelationpoint * @asyncsignalsafe * @norestart */ unsigned sleep(unsigned seconds) { - errno_t rc; + int cs = -1; + errno_t err; unsigned unslept; struct timespec tv = {seconds}; - if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv))) return 0; - if (rc == ECANCELED) return -1u; - npassert(rc == EINTR); + if (_pthread_self()->pt_flags & PT_MASKED) { + cs = _pthread_block_cancelation(); + } + err = clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv); + if (cs != -1) { + _pthread_allow_cancelation(cs); + } + if (!err) return 0; + unassert(err == EINTR); unslept = tv.tv_sec; if (tv.tv_nsec && unslept < UINT_MAX) { ++unslept; diff --git a/libc/calls/struct/sigaction.internal.h b/libc/calls/struct/sigaction.internal.h index 30e461a88db..d944ad0d159 100644 --- a/libc/calls/struct/sigaction.internal.h +++ b/libc/calls/struct/sigaction.internal.h @@ -31,6 +31,12 @@ struct sigaction_netbsd { uint32_t sa_flags; }; +struct sigaction_silicon { + void *sa_handler; + uint32_t sa_mask[1]; + uint32_t sa_flags; +}; + struct sigaction_xnu_in { void *sa_handler; void *sa_restorer; @@ -50,6 +56,7 @@ union metasigaction { struct sigaction_freebsd freebsd; struct sigaction_openbsd openbsd; struct sigaction_netbsd netbsd; + struct sigaction_silicon silicon; struct sigaction_xnu_in xnu_in; struct sigaction_xnu_out xnu_out; }; diff --git a/libc/calls/timespec_sleep.c b/libc/calls/timespec_sleep.c index 98f13b70db1..36df8f9dd55 100644 --- a/libc/calls/timespec_sleep.c +++ b/libc/calls/timespec_sleep.c @@ -22,20 +22,31 @@ #include "libc/errno.h" #include "libc/str/str.h" #include "libc/sysv/consts/clock.h" +#include "libc/thread/posixthread.internal.h" /** * Sleeps for specified delay. * + * This function may be canceled except when using masked mode in which + * case cancelation is temporarily disabled, because there is no way to + * report the ECANCELED state. + * * @return unslept time which may be non-zero if the call was interrupted + * @cancelationpoint */ struct timespec timespec_sleep(struct timespec delay) { - errno_t rc; + int cs = -1; + errno_t err; struct timespec remain; - BLOCK_CANCELATION; - bzero(&remain, sizeof(remain)); - if ((rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) { - npassert(rc == EINTR); + remain = timespec_zero; + if (_pthread_self()->pt_flags & PT_MASKED) { + cs = _pthread_block_cancelation(); + } + if ((err = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) { + unassert(err == EINTR); + } + if (cs != -1) { + _pthread_allow_cancelation(cs); } - ALLOW_CANCELATION; return remain; } diff --git a/libc/calls/timespec_sleep_until.c b/libc/calls/timespec_sleep_until.c index e6a4f6cef86..2040a86f8e2 100644 --- a/libc/calls/timespec_sleep_until.c +++ b/libc/calls/timespec_sleep_until.c @@ -33,6 +33,6 @@ errno_t timespec_sleep_until(struct timespec abs_deadline) { errno_t rc; rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0); - npassert(!rc || rc == EINTR || rc == ECANCELED); + unassert(!rc || rc == EINTR || rc == ECANCELED); return rc; } diff --git a/libc/calls/usleep.c b/libc/calls/usleep.c index 4f827d0cd67..15c37d1d0d9 100644 --- a/libc/calls/usleep.c +++ b/libc/calls/usleep.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" +#include "libc/errno.h" #include "libc/sysv/consts/clock.h" #include "libc/sysv/errfuns.h" #include "libc/time/time.h" @@ -32,7 +33,9 @@ * @norestart */ int usleep(uint32_t micros) { + errno_t err; struct timespec ts = timespec_frommicros(micros); - if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, 0)) return eintr(); + err = clock_nanosleep(CLOCK_REALTIME, 0, &ts, 0); + if (err) return errno = err, -1; return 0; } diff --git a/libc/log/appendresourcereport.c b/libc/log/appendresourcereport.c index 84f39fd9146..953a635efde 100644 --- a/libc/log/appendresourcereport.c +++ b/libc/log/appendresourcereport.c @@ -130,6 +130,9 @@ void AppendResourceReport(char **b, struct rusage *ru, const char *nl) { if (ru->ru_nsignals) { appends(b, "delivered "); AppendUnit(st, ru->ru_nsignals, "signal"); + if ((ru->ru_nsignals) > 1) { + appendw(b, READ16LE("s")); + } AppendNl(st); } if (ru->ru_nswap) { diff --git a/libc/proc/execve-nt.greg.c b/libc/proc/execve-nt.greg.c index 387e61e18a7..e2989b0df36 100644 --- a/libc/proc/execve-nt.greg.c +++ b/libc/proc/execve-nt.greg.c @@ -92,7 +92,6 @@ textwindows int sys_execve_nt(const char *program, char *const argv[], if (rc == -1) { free(fdspec); CloseHandle(hParentProcess); - __undescribe_fds(hParentProcess, lpExplicitHandles, dwExplicitHandleCount); _pthread_unlock(); __sig_unblock(m); if (GetLastError() == kNtErrorSharingViolation) { @@ -104,8 +103,8 @@ textwindows int sys_execve_nt(const char *program, char *const argv[], // give child to libc/proc/proc.c worker thread in parent int64_t handle; - unassert(!DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, - &handle, 0, false, kNtDuplicateSameAccess)); + unassert(DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, + &handle, 0, false, kNtDuplicateSameAccess)); unassert(!(handle & 0xFFFFFFFFFF000000)); TerminateThisProcess(0x23000000u | handle); } diff --git a/libc/runtime/syslib.internal.h b/libc/runtime/syslib.internal.h index de3cc8a4ec2..3f3053b24e8 100644 --- a/libc/runtime/syslib.internal.h +++ b/libc/runtime/syslib.internal.h @@ -59,6 +59,15 @@ struct Syslib { long (*__sigaction)(int, const void *, void *); long (*__pselect)(int, void *, void *, void *, const void *, const void *); long (*__mprotect)(void *, size_t, int); + /* v5 (2023-10-09) */ + long (*__sigaltstack)(const void *, void *); + long (*__getentropy)(void *, size_t); + long (*__sem_open)(const char *, int, uint16_t, unsigned); + long (*__sem_unlink)(const char *); + long (*__sem_close)(int *); + long (*__sem_post)(int *); + long (*__sem_wait)(int *); + long (*__sem_trywait)(int *); }; extern struct Syslib *__syslib; diff --git a/libc/stdio/printargs.c b/libc/stdio/printargs.c index 179a2b3aede..24e4c7e4617 100644 --- a/libc/stdio/printargs.c +++ b/libc/stdio/printargs.c @@ -45,6 +45,7 @@ #include "libc/nt/struct/ldrdatatableentry.h" #include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/teb.h" +#include "libc/runtime/clktck.h" #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" @@ -457,6 +458,7 @@ textstartup void __printargs(const char *prologue) { PRINT(" ☼ %s = %d", "geteuid()", geteuid()); PRINT(" ☼ %s = %d", "getgid()", getgid()); PRINT(" ☼ %s = %d", "getegid()", getegid()); + PRINT(" ☼ %s = %d", "CLK_TCK", CLK_TCK); PRINT(" ☼ %s = %#s", "__get_tmpdir()", __get_tmpdir()); #ifdef __x86_64__ PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory); diff --git a/libc/thread/pthread_cancel.c b/libc/thread/pthread_cancel.c index f36f85cf1cb..ec688404014 100644 --- a/libc/thread/pthread_cancel.c +++ b/libc/thread/pthread_cancel.c @@ -46,7 +46,9 @@ extern const char systemfive_cancellable[]; extern const char systemfive_cancellable_end[]; long _pthread_cancel_ack(void) { - struct PosixThread *pt = _pthread_self(); + struct PosixThread *pt; + STRACE("_pthread_cancel_ack()"); + pt = _pthread_self(); if (!(pt->pt_flags & (PT_NOCANCEL | PT_MASKED)) || (pt->pt_flags & PT_ASYNC)) { pthread_exit(PTHREAD_CANCELED); @@ -58,6 +60,7 @@ long _pthread_cancel_ack(void) { return ecanceled(); } +// the purpose of this routine is to force a blocking system call to end static void _pthread_cancel_sig(int sig, siginfo_t *si, void *arg) { ucontext_t *ctx = arg; @@ -231,6 +234,7 @@ static errno_t _pthread_cancel_everyone(void) { * - `nsync_cv_wait` * - `opendir` * - `openatemp`, 'mkstemp', etc. + * - `sleep`, `usleep`, `nanosleep`, `timespec_sleep`, etc. * - `pclose` * - `popen` * - `fwrite`, `printf`, `fprintf`, `putc`, etc. @@ -344,15 +348,12 @@ static errno_t _pthread_cancel_everyone(void) { * @raise ESRCH if system thread wasn't alive or we lost a race */ errno_t pthread_cancel(pthread_t thread) { - errno_t err; struct PosixThread *arg; if ((arg = (struct PosixThread *)thread)) { - err = _pthread_cancel_single(arg); + return _pthread_cancel_single(arg); } else { - err = _pthread_cancel_everyone(); + return _pthread_cancel_everyone(); } - STRACE("pthread_cancel(%d) → %s", _pthread_tid(arg), DescribeErrno(err)); - return err; } /** diff --git a/libc/thread/sem_open.c b/libc/thread/sem_open.c index cbac0ead01d..89c68fc44e0 100644 --- a/libc/thread/sem_open.c +++ b/libc/thread/sem_open.c @@ -20,6 +20,7 @@ #include "libc/calls/blockcancel.internal.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" @@ -27,6 +28,7 @@ #include "libc/limits.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/syslib.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/consts/map.h" @@ -173,15 +175,32 @@ sem_t *sem_open(const char *name, int oflag, ...) { struct Semaphore *s; char pathbuf[PATH_MAX]; unsigned mode = 0, value = 0; + + va_start(va, oflag); + mode = va_arg(va, unsigned); + value = va_arg(va, unsigned); + va_end(va); + +#if 0 + if (IsXnuSilicon()) { + long kernel; + if (!(sem = calloc(1, sizeof(sem_t)))) return SEM_FAILED; + sem->sem_magic = SEM_MAGIC_KERNEL; + kernel = _sysret(__syslib->__sem_open(name, oflag, mode, value)); + if (kernel == -1) { + free(sem); + return SEM_FAILED; + } + sem->sem_magic = SEM_MAGIC_KERNEL; + sem->sem_kernel = (int *)kernel; + } +#endif + if (oflag & ~(O_CREAT | O_EXCL)) { einval(); return SEM_FAILED; } if (oflag & O_CREAT) { - va_start(va, oflag); - mode = va_arg(va, unsigned); - value = va_arg(va, unsigned); - va_end(va); if (value > SEM_VALUE_MAX) { einval(); return SEM_FAILED; @@ -250,6 +269,14 @@ int sem_close(sem_t *sem) { int prefs; bool unmap, delete; struct Semaphore *s, **p; + +#if 0 + if (IsXnuSilicon()) { + npassert(sem->sem_magic == SEM_MAGIC_KERNEL); + return _sysret(__syslib->__sem_close(sem->sem_kernel)); + } +#endif + npassert(sem->sem_magic == SEM_MAGIC_NAMED); sem_open_init(); sem_open_lock(); @@ -298,6 +325,13 @@ int sem_unlink(const char *name) { int rc, e = errno; struct Semaphore *s; char pathbuf[PATH_MAX]; + +#if 0 + if (IsXnuSilicon()) { + return _sysret(__syslib->__sem_unlink(name)); + } +#endif + if (!(path = sem_path_np(name, pathbuf, sizeof(pathbuf)))) return -1; if ((rc = unlink(path)) == -1 && IsWindows() && errno == EACCES) { sem_open_init(); diff --git a/libc/thread/sem_post.c b/libc/thread/sem_post.c index 4ed66ec4509..0cedcc6c1f5 100644 --- a/libc/thread/sem_post.c +++ b/libc/thread/sem_post.c @@ -18,9 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" #include "libc/limits.h" +#include "libc/runtime/syslib.internal.h" #include "libc/sysv/errfuns.h" #include "libc/thread/semaphore.h" #include "third_party/nsync/futex.internal.h" @@ -33,6 +36,13 @@ */ int sem_post(sem_t *sem) { int rc, old, wakeups; + +#if 0 + if (IsXnuSilicon() && sem->sem_magic == SEM_MAGIC_KERNEL) { + return _sysret(__syslib->__sem_post(sem->sem_kernel)); + } +#endif + old = atomic_fetch_add_explicit(&sem->sem_value, 1, memory_order_acq_rel); unassert(old > INT_MIN); if (old >= 0) { diff --git a/libc/thread/sem_timedwait.c b/libc/thread/sem_timedwait.c index d2d117482f0..f2a278147b8 100644 --- a/libc/thread/sem_timedwait.c +++ b/libc/thread/sem_timedwait.c @@ -17,12 +17,17 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/calls/calls.h" #include "libc/calls/cp.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" +#include "libc/intrin/weaken.h" #include "libc/limits.h" +#include "libc/runtime/syslib.internal.h" #include "libc/sysv/errfuns.h" #include "libc/thread/semaphore.h" #include "libc/thread/thread.h" @@ -52,9 +57,48 @@ static void sem_timedwait_cleanup(void *arg) { * @cancelationpoint */ int sem_timedwait(sem_t *sem, const struct timespec *abstime) { - int e, i, v, rc; + int i, v, rc, e = errno; + +#if 0 + if (IsXnuSilicon() && sem->sem_magic == SEM_MAGIC_KERNEL) { + if (!abstime) { + if (_weaken(pthread_testcancel_np) && // + _weaken(pthread_testcancel_np)()) { + return ecanceled(); + } + rc = _sysret(__syslib->__sem_wait(sem->sem_kernel)); + if (rc == -1 && errno == EINTR && // + _weaken(pthread_testcancel_np) && // + _weaken(pthread_testcancel_np)()) { + return ecanceled(); + } + return rc; + } + for (;;) { + if (_weaken(pthread_testcancel_np) && // + _weaken(pthread_testcancel_np)()) { + return ecanceled(); + } + rc = _sysret(__syslib->__sem_trywait(sem->sem_kernel)); + if (!rc) return 0; + if (errno == EINTR && // + _weaken(pthread_testcancel_np) && // + _weaken(pthread_testcancel_np)()) { + return ecanceled(); + } + if (errno != EAGAIN) return -1; + errno = e; + struct timespec now = timespec_real(); + if (timespec_cmp(*abstime, now) >= 0) { + return etimedout(); + } + if (usleep(10 * 1000) == -1) { + return -1; + } + } + } +#endif - e = errno; for (i = 0; i < 7; ++i) { rc = sem_trywait(sem); if (!rc) { diff --git a/libc/thread/sem_trywait.c b/libc/thread/sem_trywait.c index d76a6402a87..8f49d081243 100644 --- a/libc/thread/sem_trywait.c +++ b/libc/thread/sem_trywait.c @@ -18,9 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/atomic.h" #include "libc/limits.h" +#include "libc/runtime/syslib.internal.h" #include "libc/sysv/errfuns.h" #include "libc/thread/semaphore.h" @@ -34,6 +37,13 @@ */ int sem_trywait(sem_t *sem) { int v; + +#if 0 + if (IsXnuSilicon() && sem->sem_magic == SEM_MAGIC_KERNEL) { + return _sysret(__syslib->__sem_trywait(sem->sem_kernel)); + } +#endif + v = atomic_load_explicit(&sem->sem_value, memory_order_relaxed); do { unassert(v > INT_MIN); diff --git a/libc/thread/semaphore.h b/libc/thread/semaphore.h index 4e759e1c80a..5f0c2cb15ab 100644 --- a/libc/thread/semaphore.h +++ b/libc/thread/semaphore.h @@ -8,6 +8,7 @@ COSMOPOLITAN_C_START_ #define SEM_FAILED ((sem_t *)0) #define SEM_MAGIC_NAMED 0xDEADBEEFu #define SEM_MAGIC_UNNAMED 0xFEEDABEEu +#define SEM_MAGIC_KERNEL 0xCAFEBABEu typedef struct { union { @@ -21,6 +22,7 @@ typedef struct { int sem_pid; /* unnamed only */ bool sem_lazydelete; /* named only */ bool sem_pshared; + int *sem_kernel; }; void *sem_space[32]; }; diff --git a/test/libc/thread/pthread_cancel_test.c b/test/libc/thread/pthread_cancel_test.c index c15298ec3c0..ca4a246a44e 100644 --- a/test/libc/thread/pthread_cancel_test.c +++ b/test/libc/thread/pthread_cancel_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/atomic.h" #include "libc/calls/calls.h" +#include "libc/calls/struct/sigaction.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/kprintf.h" @@ -26,6 +27,7 @@ #include "libc/nexgen32e/nexgen32e.h" #include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" +#include "libc/sysv/consts/sig.h" #include "libc/testlib/testlib.h" #include "libc/thread/thread.h" #include "libc/thread/thread2.h" @@ -283,3 +285,28 @@ TEST(pthread_cancel, self_asynchronous_takesImmediateEffect) { ASSERT_SYS(0, 0, close(pfds[1])); ASSERT_SYS(0, 0, close(pfds[0])); } + +atomic_bool was_completed; + +void WaitUntilReady(void) { + while (!ready) pthread_yield(); + ASSERT_EQ(0, errno); + ASSERT_SYS(0, 0, usleep(1000)); +} + +void *SleepWorker(void *arg) { + pthread_setcancelstate(PTHREAD_CANCEL_MASKED, 0); + ready = true; + ASSERT_SYS(ECANCELED, -1, usleep(30 * 1e6)); + was_completed = true; + return 0; +} + +TEST(pthread_cancel, canInterruptSleepOperation) { + pthread_t th; + ASSERT_EQ(0, pthread_create(&th, 0, SleepWorker, 0)); + WaitUntilReady(); + ASSERT_EQ(0, pthread_cancel(th)); + ASSERT_EQ(0, pthread_join(th, 0)); + ASSERT_TRUE(was_completed); +} diff --git a/test/libc/thread/pthread_kill_test.c b/test/libc/thread/pthread_kill_test.c index 1f4e5ac70e3..679e4460f15 100644 --- a/test/libc/thread/pthread_kill_test.c +++ b/test/libc/thread/pthread_kill_test.c @@ -21,7 +21,6 @@ #include "libc/calls/struct/sigaction.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/sock/struct/sockaddr.h" @@ -85,7 +84,6 @@ TEST(pthread_kill, canInterruptSleepOperation) { signal(SIGUSR1, old); } -#if 0 void *ReadWorker(void *arg) { char buf[8] = {0}; ready = true; @@ -324,4 +322,3 @@ TEST(pthread_kill, canInterruptSigsuspend) { ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &oldss, 0)); signal(SIGUSR1, oldsig); } -#endif diff --git a/third_party/python/Modules/_multiprocessing/semaphore.c b/third_party/python/Modules/_multiprocessing/semaphore.c index 1c18450b7a8..3c3d29a2fd5 100644 --- a/third_party/python/Modules/_multiprocessing/semaphore.c +++ b/third_party/python/Modules/_multiprocessing/semaphore.c @@ -207,7 +207,7 @@ semlock_release(SemLockObject *self, PyObject *args) #endif #ifndef HAVE_SEM_TIMEDWAIT -# define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save) +# define sem_timedwait_(sem,deadline) sem_timedwait_save(sem,deadline,_save) static int sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save) diff --git a/tool/build/runit.c b/tool/build/runit.c index 7ec48fee4f5..33380a125cf 100644 --- a/tool/build/runit.c +++ b/tool/build/runit.c @@ -25,7 +25,6 @@ #include "libc/calls/struct/timespec.h" #include "libc/dns/dns.h" #include "libc/errno.h" -#include "libc/fmt/conv.h" #include "libc/fmt/libgen.h" #include "libc/intrin/bits.h" #include "libc/intrin/kprintf.h" @@ -33,9 +32,7 @@ #include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/log.h" -#include "libc/macros.internal.h" #include "libc/mem/gc.h" -#include "libc/mem/gc.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/sock/ipclassify.internal.h" @@ -51,12 +48,8 @@ #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sock.h" -#include "libc/time/time.h" -#include "libc/x/x.h" #include "libc/x/xasprintf.h" -#include "libc/x/xsigaction.h" #include "net/https/https.h" -#include "third_party/mbedtls/debug.h" #include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/ssl.h" #include "third_party/zlib/zlib.h" diff --git a/tool/viz/clock_nanosleep_accuracy.c b/tool/viz/clock_nanosleep_accuracy.c index c21f483e048..b4fb98f0700 100644 --- a/tool/viz/clock_nanosleep_accuracy.c +++ b/tool/viz/clock_nanosleep_accuracy.c @@ -26,11 +26,6 @@ #define MAXIMUM 1e9 #define ITERATIONS 10 -void WarmUp(void) { - struct timespec wf = {0, 1}; - npassert(!clock_nanosleep(CLOCK_REALTIME, 0, &wf, 0)); -} - void TestSleepRealRelative(void) { printf("\n"); printf("testing: clock_nanosleep(CLOCK_REALTIME) with relative " @@ -68,7 +63,6 @@ void TestSleepMonoRelative(void) { } int main(int argc, char *argv[]) { - WarmUp(); TestSleepRealRelative(); TestSleepMonoRelative(); } diff --git a/tool/viz/setitimer_accuracy.c b/tool/viz/setitimer_accuracy.c new file mode 100644 index 00000000000..64fb0836fa4 --- /dev/null +++ b/tool/viz/setitimer_accuracy.c @@ -0,0 +1,61 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net 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/itimerval.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/timespec.h" +#include "libc/calls/struct/timeval.h" +#include "libc/fmt/itoa.h" +#include "libc/sysv/consts/itimer.h" +#include "libc/sysv/consts/sig.h" + +#define HZ 120 + +struct timeval start; +struct timeval expect; +struct timeval interval = {0, 1e6 / HZ}; + +void OnTick(int sig) { + char ibuf[27]; + struct timeval now = timeval_real(); + switch (timeval_cmp(now, expect)) { + case 0: + tinyprint(1, "100% precise\n", NULL); + break; + case -1: + FormatInt64Thousands(ibuf, timeval_tomicros(timeval_sub(expect, now))); + tinyprint(1, ibuf, " µs early\n", NULL); + break; + case +1: + FormatInt64Thousands(ibuf, timeval_tomicros(timeval_sub(now, expect))); + tinyprint(1, ibuf, " µs late\n", NULL); + break; + default: + __builtin_unreachable(); + } + expect = timeval_add(expect, interval); +} + +int main(int argc, char *argv[]) { + start = timeval_real(); + expect = timeval_add(start, interval); + signal(SIGALRM, OnTick); + setitimer(ITIMER_REAL, &(struct itimerval){interval, interval}, 0); + for (;;) pause(); +}