Improve cancellations, randomness, and time

- Exhaustively document cancellation points
- Rename SIGCANCEL to SIGTHR just like BSDs
- Further improve POSIX thread cancellations
- Ensure asynchronous cancellations work correctly
- Elevate the quality of getrandom() and getentropy()
- Make futexes cancel correctly on OpenBSD 6.x and 7.x
- Add reboot.com and shutdown.com to examples directory
- Remove underscore prefix from awesome timespec_*() APIs
- Create assertions that help verify our cancellation points
- Remove bad timespec APIs (cmp generalizes eq/ne/gt/gte/lt/lte)
This commit is contained in:
Justine Tunney 2022-11-05 19:49:41 -07:00
parent 0d7c265392
commit 3f0bcdc3ef
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
173 changed files with 1599 additions and 782 deletions

View file

@ -20,22 +20,22 @@ int main(int argc, char *argv[]) {
volatile unsigned long x; volatile unsigned long x;
struct timespec now, start, next, interval; struct timespec now, start, next, interval;
printf("hammering the cpu...\n"); printf("hammering the cpu...\n");
next = start = _timespec_mono(); next = start = timespec_mono();
interval = _timespec_frommillis(500); interval = timespec_frommillis(500);
next = _timespec_add(next, interval); next = timespec_add(next, interval);
for (;;) { for (;;) {
for (i = 0;; ++i) { for (i = 0;; ++i) {
x *= 7; x *= 7;
if (!(i % 256)) { if (!(i % 256)) {
now = _timespec_mono(); now = timespec_mono();
if (_timespec_gte(now, next)) { if (timespec_cmp(now, next) >= 0) {
break; break;
} }
} }
} }
next = _timespec_add(next, interval); next = timespec_add(next, interval);
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n", printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
_timespec_tonanos(_timespec_sub(now, start)) / 1000000000., timespec_tonanos(timespec_sub(now, start)) / 1000000000.,
(double)clock() / CLOCKS_PER_SEC); (double)clock() / CLOCKS_PER_SEC);
} }
} }

View file

@ -28,7 +28,7 @@ void show(int clock) {
} }
shown[n++] = clock; shown[n++] = clock;
if (clock_getres(clock, &ts) != -1) { if (clock_getres(clock, &ts) != -1) {
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts)); kprintf("%s %'ld ns\n", DescribeClockName(clock), timespec_tonanos(ts));
} else { } else {
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno)); kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
} }

39
examples/reboot.c Normal file
View file

@ -0,0 +1,39 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/reboot.h"
int main(int argc, char *argv[]) {
char line[8] = {0};
if (argc > 1 && !strcmp(argv[1], "-y")) {
line[0] = 'y';
} else {
printf("reboot your computer? yes or no [no] ");
fflush(stdout);
fgets(line, sizeof(line), stdin);
}
if (line[0] == 'y' || line[0] == 'Y') {
if (reboot(RB_AUTOBOOT)) {
printf("system is rebooting...\n");
exit(0);
} else {
perror("reboot");
exit(1);
}
} else if (line[0] == 'n' || line[0] == 'N') {
exit(0);
} else {
printf("error: unrecognized response\n");
exit(2);
}
}

39
examples/shutdown.c Normal file
View file

@ -0,0 +1,39 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/reboot.h"
int main(int argc, char *argv[]) {
char line[8] = {0};
if (argc > 1 && !strcmp(argv[1], "-y")) {
line[0] = 'y';
} else {
printf("shutdown your computer? yes or no [no] ");
fflush(stdout);
fgets(line, sizeof(line), stdin);
}
if (line[0] == 'y' || line[0] == 'Y') {
if (reboot(RB_POWER_OFF)) {
printf("system is shutting down...\n");
exit(0);
} else {
perror("reboot");
exit(1);
}
} else if (line[0] == 'n' || line[0] == 'N') {
exit(0);
} else {
printf("error: unrecognized response\n");
exit(2);
}
}

View file

@ -1,26 +0,0 @@
/*-*- 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 2022 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/struct/timespec.h"
/**
* Checks if 𝑥 = 𝑦.
*/
bool _timespec_eq(struct timespec x, struct timespec y) {
return x.tv_sec == y.tv_sec && x.tv_nsec == y.tv_nsec;
}

View file

@ -1,34 +0,0 @@
/*-*- 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 2022 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/struct/timespec.h"
/**
* Returns true if timespec `x` is greater than `y`.
*/
bool _timespec_gt(struct timespec x, struct timespec y) {
if (x.tv_sec > y.tv_sec) {
return true;
}
if (x.tv_sec == y.tv_sec) {
if (x.tv_nsec > y.tv_nsec) {
return true;
}
}
return false;
}

View file

@ -1,28 +0,0 @@
/*-*- 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 2022 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/struct/timespec.h"
/**
* Checks if 𝑥 𝑦.
*/
bool _timespec_gte(struct timespec x, struct timespec y) {
if (x.tv_sec > y.tv_sec) return true;
if (x.tv_sec < y.tv_sec) return false;
return x.tv_nsec >= y.tv_nsec;
}

View file

@ -1,26 +0,0 @@
/*-*- 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 2022 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/struct/timeval.h"
/**
* Checks if 𝑥 = 𝑦.
*/
bool _timeval_eq(struct timeval x, struct timeval y) {
return x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec;
}

View file

@ -1,28 +0,0 @@
/*-*- 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 2022 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/struct/timeval.h"
/**
* Checks if 𝑥 𝑦.
*/
bool _timeval_gte(struct timeval x, struct timeval y) {
if (x.tv_sec > y.tv_sec) return true;
if (x.tv_sec < y.tv_sec) return false;
return x.tv_usec >= y.tv_usec;
}

View file

@ -7,13 +7,16 @@ COSMOPOLITAN_C_START_
#define BLOCK_CANCELLATIONS \ #define BLOCK_CANCELLATIONS \
do { \ do { \
int _CancelState; \ int _CancelState; \
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_CancelState) _CancelState = _pthread_block_cancellations()
#define ALLOW_CANCELLATIONS \ #define ALLOW_CANCELLATIONS \
pthread_setcancelstate(_CancelState, 0); \ _pthread_allow_cancellations(_CancelState); \
} \ } \
while (0) while (0)
int _pthread_block_cancellations(void);
void _pthread_allow_cancellations(int);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */

View file

@ -179,12 +179,12 @@ o//libc/calls/statfs2cosmo.o: private \
# we always want -O2 because: # we always want -O2 because:
# division is expensive if not optimized # division is expensive if not optimized
o/$(MODE)/libc/calls/clock.o \ o/$(MODE)/libc/calls/clock.o \
o/$(MODE)/libc/calls/_timespec_tomillis.o \ o/$(MODE)/libc/calls/timespec_tomillis.o \
o/$(MODE)/libc/calls/_timespec_tomicros.o \ o/$(MODE)/libc/calls/timespec_tomicros.o \
o/$(MODE)/libc/calls/_timespec_totimeval.o \ o/$(MODE)/libc/calls/timespec_totimeval.o \
o/$(MODE)/libc/calls/_timespec_fromnanos.o \ o/$(MODE)/libc/calls/timespec_fromnanos.o \
o/$(MODE)/libc/calls/_timespec_frommillis.o \ o/$(MODE)/libc/calls/timespec_frommillis.o \
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \ o/$(MODE)/libc/calls/timespec_frommicros.o: private \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-O2 -O2

View file

@ -55,7 +55,7 @@ int64_t clock(void) {
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) { if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
errno = e; errno = e;
if (getrusage(RUSAGE_SELF, &ru) != -1) { if (getrusage(RUSAGE_SELF, &ru) != -1) {
ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime)); ts = timeval_totimespec(timeval_add(ru.ru_utime, ru.ru_stime));
} else { } else {
return -1; return -1;
} }

View file

@ -17,11 +17,11 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/thread/thread.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/clock.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
static struct { static struct {
pthread_once_t once; pthread_once_t once;
@ -30,7 +30,7 @@ static struct {
} g_mono; } g_mono;
static void sys_clock_gettime_mono_init(void) { static void sys_clock_gettime_mono_init(void) {
g_mono.base_wall = _timespec_real(); g_mono.base_wall = timespec_real();
g_mono.base_tick = rdtsc(); g_mono.base_tick = rdtsc();
} }
@ -42,7 +42,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
pthread_once(&g_mono.once, sys_clock_gettime_mono_init); pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
cycles = rdtsc() - g_mono.base_tick; cycles = rdtsc() - g_mono.base_tick;
nanos = cycles / 3; nanos = cycles / 3;
*time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos)); *time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos));
return 0; return 0;
} else { } else {
return einval(); return einval();

View file

@ -33,24 +33,24 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
abs = *req; abs = *req;
for (;;) { for (;;) {
if (sys_clock_gettime_nt(clock, &now)) return -1; if (sys_clock_gettime_nt(clock, &now)) return -1;
if (_timespec_gte(now, abs)) return 0; if (timespec_cmp(now, abs) >= 0) return 0;
if (_check_interrupts(false, g_fds.p)) return -1; if (_check_interrupts(false, g_fds.p)) return -1;
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS, SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))), timespec_tomillis(timespec_sub(abs, now))),
false); false);
} }
} else { } else {
if (sys_clock_gettime_nt(clock, &now)) return -1; if (sys_clock_gettime_nt(clock, &now)) return -1;
abs = _timespec_add(now, *req); abs = timespec_add(now, *req);
for (;;) { for (;;) {
sys_clock_gettime_nt(clock, &now); sys_clock_gettime_nt(clock, &now);
if (_timespec_gte(now, abs)) return 0; if (timespec_cmp(now, abs) >= 0) return 0;
if (_check_interrupts(false, g_fds.p)) { if (_check_interrupts(false, g_fds.p)) {
if (rem) *rem = _timespec_sub(abs, now); if (rem) *rem = timespec_sub(abs, now);
return -1; return -1;
} }
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS, SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
_timespec_tomillis(_timespec_sub(abs, now))), timespec_tomillis(timespec_sub(abs, now))),
false); false);
} }
} }

View file

@ -31,8 +31,8 @@ int sys_clock_nanosleep_openbsd(int clock, int flags,
res = sys_nanosleep(req, rem); res = sys_nanosleep(req, rem);
} else { } else {
sys_clock_gettime(clock, &now); sys_clock_gettime(clock, &now);
if (_timespec_gt(*req, now)) { if (timespec_cmp(*req, now) > 0) {
rel = _timespec_sub(*req, now); rel = timespec_sub(*req, now);
res = sys_nanosleep(&rel, 0); res = sys_nanosleep(&rel, 0);
} else { } else {
res = 0; res = 0;

View file

@ -31,10 +31,10 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
struct timeval now, abs, rel; struct timeval now, abs, rel;
if (clock == CLOCK_REALTIME) { if (clock == CLOCK_REALTIME) {
if (flags & TIMER_ABSTIME) { if (flags & TIMER_ABSTIME) {
abs = _timespec_totimeval(*req); abs = timespec_totimeval(*req);
sys_gettimeofday_xnu(&now, 0, 0); sys_gettimeofday_xnu(&now, 0, 0);
if (_timeval_gt(abs, now)) { if (timeval_cmp(abs, now) > 0) {
rel = _timeval_sub(abs, now); rel = timeval_sub(abs, now);
res = sys_select(0, 0, 0, 0, &rel); res = sys_select(0, 0, 0, 0, &rel);
} else { } else {
res = 0; res = 0;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/asan.internal.h" #include "libc/calls/asan.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h" #include "libc/calls/struct/timespec.internal.h"
@ -55,8 +56,8 @@
* *
* struct timespec rel, now, abs; * struct timespec rel, now, abs;
* clock_gettime(CLOCK_REALTIME, &now); * clock_gettime(CLOCK_REALTIME, &now);
* rel = _timespec_frommillis(100); * rel = timespec_frommillis(100);
* abs = _timespec_add(now, rel); * abs = timespec_add(now, rel);
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0)); * while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
* *
* will accurately spin on `EINTR` errors. That way you're not impeding * will accurately spin on `EINTR` errors. That way you're not impeding
@ -74,6 +75,7 @@
* if flags is `TIMER_ABSTIME` then `rem` is ignored * if flags is `TIMER_ABSTIME` then `rem` is ignored
* @return 0 on success, or errno on error * @return 0 on success, or errno on error
* @raise EINTR when a signal got delivered while we were waiting * @raise EINTR when a signal got delivered while we were waiting
* @raise ECANCELED if thread was cancelled in masked mode
* @raise ENOTSUP if `clock` is known but we can't use it here * @raise ENOTSUP if `clock` is known but we can't use it here
* @raise EFAULT if `req` or null or bad memory was passed * @raise EFAULT if `req` or null or bad memory was passed
* @raise EINVAL if `clock` is unknown to current platform * @raise EINVAL if `clock` is unknown to current platform
@ -87,6 +89,7 @@
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req, errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
struct timespec *rem) { struct timespec *rem) {
int rc, e = errno; int rc, e = errno;
BEGIN_CANCELLATION_POINT;
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) || if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
(rem && !__asan_is_valid_timespec(rem))))) { (rem && !__asan_is_valid_timespec(rem))))) {
@ -113,6 +116,8 @@ errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
errno = e; errno = e;
} }
END_CANCELLATION_POINT;
#if SYSDEBUG #if SYSDEBUG
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) { if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock), STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),

View file

@ -37,6 +37,7 @@
* @raise EBADF on OpenBSD if `first` is greater than highest fd * @raise EBADF on OpenBSD if `first` is greater than highest fd
* @raise EINVAL if flags are bad or first is greater than last * @raise EINVAL if flags are bad or first is greater than last
* @raise EMFILE if a weird race condition happens on Linux * @raise EMFILE if a weird race condition happens on Linux
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR possibly on OpenBSD * @raise EINTR possibly on OpenBSD
* @raise ENOMEM on Linux maybe * @raise ENOMEM on Linux maybe
*/ */

View file

@ -16,7 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
@ -39,6 +41,7 @@ static bool HasCopyFileRange(void) {
bool ok; bool ok;
int e, rc; int e, rc;
e = errno; e = errno;
BLOCK_CANCELLATIONS;
if (IsLinux()) { if (IsLinux()) {
// We modernize our detection by a few years for simplicity. // We modernize our detection by a few years for simplicity.
// This system call is chosen since it's listed by pledge(). // This system call is chosen since it's listed by pledge().
@ -49,6 +52,7 @@ static bool HasCopyFileRange(void) {
} else { } else {
ok = false; ok = false;
} }
ALLOW_CANCELLATIONS;
errno = e; errno = e;
return ok; return ok;
} }
@ -81,6 +85,7 @@ static void copy_file_range_init(void) {
* @raise EBADF if `infd` or `outfd` aren't open files or append-only * @raise EBADF if `infd` or `outfd` aren't open files or append-only
* @raise EPERM if `fdout` refers to an immutable file on Linux * @raise EPERM if `fdout` refers to an immutable file on Linux
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor * @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINVAL if ranges overlap or `flags` is non-zero * @raise EINVAL if ranges overlap or `flags` is non-zero
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded * @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
* @raise EFAULT if one of the pointers memory is bad * @raise EFAULT if one of the pointers memory is bad
@ -93,12 +98,15 @@ static void copy_file_range_init(void) {
* @raise EIO if a low-level i/o error happens * @raise EIO if a low-level i/o error happens
* @see sendfile() for seekable socket * @see sendfile() for seekable socket
* @see splice() for fd pipe * @see splice() for fd pipe
* @cancellationpoint
*/ */
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd, ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
int64_t *opt_in_out_outoffset, size_t uptobytes, int64_t *opt_in_out_outoffset, size_t uptobytes,
uint32_t flags) { uint32_t flags) {
ssize_t rc; ssize_t rc;
pthread_once(&g_copy_file_range.once, copy_file_range_init); pthread_once(&g_copy_file_range.once, copy_file_range_init);
BEGIN_CANCELLATION_POINT;
if (!g_copy_file_range.ok) { if (!g_copy_file_range.ok) {
rc = enosys(); rc = enosys();
} else if (IsAsan() && ((opt_in_out_inoffset && } else if (IsAsan() && ((opt_in_out_inoffset &&
@ -112,6 +120,8 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd, rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
opt_in_out_outoffset, uptobytes, flags); opt_in_out_outoffset, uptobytes, flags);
} }
END_CANCELLATION_POINT;
STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd, STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd, DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags); DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);

View file

@ -16,19 +16,44 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/struct/timeval.h" #include "libc/calls/blockcancel.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/posixthread.internal.h"
#include "libc/thread/tls.h"
#ifdef MODE_DBG
/** int begin_cancellation_point(void) {
* Returns true if timeval `x` is greater than `y`. int state = 0;
*/ struct CosmoTib *tib;
bool _timeval_gt(struct timeval x, struct timeval y) { struct PosixThread *pt;
if (x.tv_sec > y.tv_sec) { if (__enable_tls) {
return true; tib = __get_tls();
} if ((pt = (struct PosixThread *)tib->tib_pthread)) {
if (x.tv_sec == y.tv_sec) { state = pt->flags & PT_INCANCEL;
if (x.tv_usec > y.tv_usec) { pt->flags |= PT_INCANCEL;
return true;
} }
} }
return false; return state;
} }
void end_cancellation_point(int state) {
struct CosmoTib *tib;
struct PosixThread *pt;
if (__enable_tls) {
tib = __get_tls();
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
pt->flags &= ~PT_INCANCEL;
pt->flags |= state;
}
}
}
void report_cancellation_point(void) {
BLOCK_CANCELLATIONS;
_bt("error: need BEGIN/END_CANCELLATION_POINT\n");
ALLOW_CANCELLATIONS;
}
#endif /* MODE_DBG */

25
libc/calls/cp.internal.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int begin_cancellation_point(void);
void end_cancellation_point(int);
#ifndef MODE_DBG
#define BEGIN_CANCELLATION_POINT (void)0
#define END_CANCELLATION_POINT (void)0
#else
#define BEGIN_CANCELLATION_POINT \
do { \
int _Cp; \
_Cp = begin_cancellation_point()
#define END_CANCELLATION_POINT \
end_cancellation_point(_Cp); \
} \
while (0)
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_ */

View file

@ -31,6 +31,7 @@
* @param mode is octal bits, e.g. 0644 usually * @param mode is octal bits, e.g. 0644 usually
* @return file descriptor, or -1 w/ errno * @return file descriptor, or -1 w/ errno
* @see openat() for further documentation * @see openat() for further documentation
* @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
* @restartable * @restartable
* @threadsafe * @threadsafe

View file

@ -31,13 +31,11 @@
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows. // Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) { textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t rc, proc, handle; int64_t rc, proc, handle;
_unassert(oldfd >= 0);
_unassert(newfd >= -1);
_unassert(!(flags & ~O_CLOEXEC)); _unassert(!(flags & ~O_CLOEXEC));
__fds_lock(); __fds_lock();
if (oldfd >= g_fds.n || if (!__isfdopen(oldfd) || newfd < -1 ||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket && (g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
g_fds.p[oldfd].kind != kFdConsole)) { g_fds.p[oldfd].kind != kFdConsole)) {
__fds_unlock(); __fds_unlock();

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/blocksigs.internal.h" #include "libc/calls/blocksigs.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
@ -40,6 +41,8 @@ static bool IsApeBinary(const char *path) {
int fd; int fd;
char buf[8]; char buf[8];
bool res = false; bool res = false;
// TODO(jart): Should we block signals too?
BLOCK_CANCELLATIONS;
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) { if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
if (sys_read(fd, buf, 8) == 8 && // if (sys_read(fd, buf, 8) == 8 && //
(READ64LE(buf) == READ64LE("MZqFpD='") || (READ64LE(buf) == READ64LE("MZqFpD='") ||
@ -48,6 +51,7 @@ static bool IsApeBinary(const char *path) {
} }
sys_close(fd); sys_close(fd);
} }
ALLOW_CANCELLATIONS;
return res; return res;
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h" #include "libc/calls/struct/flock.h"
#include "libc/calls/struct/flock.internal.h" #include "libc/calls/struct/flock.internal.h"
@ -94,7 +95,7 @@
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock * @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and * @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
* `RLIMIT_NOFILE` would be exceeded * `RLIMIT_NOFILE` would be exceeded
* @cancellationpoint when `cmd` is `F_SETLKW` * @cancellationpoint when `cmd` is `F_SETLKW` or `F_OFD_SETLKW`
* @asyncsignalsafe * @asyncsignalsafe
* @restartable * @restartable
*/ */
@ -113,7 +114,9 @@ int fcntl(int fd, int cmd, ...) {
rc = _weaken(__zipos_fcntl)(fd, cmd, arg); rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
} else if (!IsWindows()) { } else if (!IsWindows()) {
if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) { if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) {
BEGIN_CANCELLATION_POINT;
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp); rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
END_CANCELLATION_POINT;
} else { } else {
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl); rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
} }

View file

@ -23,5 +23,6 @@
textwindows int sys_fdatasync_nt(int fd) { textwindows int sys_fdatasync_nt(int fd) {
// TODO(jart): what should we do with worker pipes? // TODO(jart): what should we do with worker pipes?
if (!__isfdkind(fd, kFdFile)) return ebadf(); if (!__isfdkind(fd, kFdFile)) return ebadf();
if (_check_interrupts(false, 0)) return -1;
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1; return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
@ -30,6 +31,8 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @see sync(), fsync(), sync_file_range() * @see sync(), fsync(), sync_file_range()
* @see __nosync to secretly disable * @see __nosync to secretly disable
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
*/ */
@ -37,11 +40,13 @@ int fdatasync(int fd) {
int rc; int rc;
struct stat st; struct stat st;
if (__nosync != 0x5453455454534146) { if (__nosync != 0x5453455454534146) {
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {
rc = sys_fdatasync(fd); rc = sys_fdatasync(fd);
} else { } else {
rc = sys_fdatasync_nt(fd); rc = sys_fdatasync_nt(fd);
} }
END_CANCELLATION_POINT;
STRACE("fdatasync(%d) → %d% m", fd, rc); STRACE("fdatasync(%d) → %d% m", fd, rc);
} else { } else {
rc = fstat(fd, &st); rc = fstat(fd, &st);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -35,11 +36,15 @@
*/ */
int flock(int fd, int op) { int flock(int fd, int op) {
int rc; int rc;
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {
rc = sys_flock(fd, op); rc = sys_flock(fd, op);
} else { } else {
rc = sys_flock_nt(fd, op); rc = sys_flock_nt(fd, op);
} }
END_CANCELLATION_POINT;
STRACE("flock(%d, %d) → %d% m", fd, op, rc); STRACE("flock(%d, %d) → %d% m", fd, op, rc);
return rc; return rc;
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/statfs-meta.internal.h" #include "libc/calls/struct/statfs-meta.internal.h"
#include "libc/calls/struct/statfs.internal.h" #include "libc/calls/struct/statfs.internal.h"
@ -33,7 +34,9 @@
int fstatfs(int fd, struct statfs *sf) { int fstatfs(int fd, struct statfs *sf) {
int rc; int rc;
union statfs_meta m; union statfs_meta m;
BEGIN_CANCELLATION_POINT;
CheckLargeStackAllocation(&m, sizeof(m)); CheckLargeStackAllocation(&m, sizeof(m));
if (!IsWindows()) { if (!IsWindows()) {
if ((rc = sys_fstatfs(fd, &m)) != -1) { if ((rc = sys_fstatfs(fd, &m)) != -1) {
statfs2cosmo(sf, &m); statfs2cosmo(sf, &m);
@ -43,6 +46,8 @@ int fstatfs(int fd, struct statfs *sf) {
} else { } else {
rc = ebadf(); rc = ebadf();
} }
END_CANCELLATION_POINT;
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf)); STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
return rc; return rc;
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
@ -28,6 +29,8 @@
* Blocks until kernel flushes buffers for fd to disk. * Blocks until kernel flushes buffers for fd to disk.
* *
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @see fdatasync(), sync_file_range() * @see fdatasync(), sync_file_range()
* @see __nosync to secretly disable * @see __nosync to secretly disable
* @cancellationpoint * @cancellationpoint
@ -37,11 +40,13 @@ int fsync(int fd) {
int rc; int rc;
struct stat st; struct stat st;
if (__nosync != 0x5453455454534146) { if (__nosync != 0x5453455454534146) {
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {
rc = sys_fsync(fd); rc = sys_fsync(fd);
} else { } else {
rc = sys_fdatasync_nt(fd); rc = sys_fdatasync_nt(fd);
} }
END_CANCELLATION_POINT;
STRACE("fysnc(%d) → %d% m", fd, rc); STRACE("fysnc(%d) → %d% m", fd, rc);
} else { } else {
rc = fstat(fd, &st); rc = fstat(fd, &st);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
@ -49,6 +50,7 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise EINVAL if `length` is negative * @raise EINVAL if `length` is negative
* @raise EINTR if signal was delivered instead * @raise EINTR if signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EIO if a low-level i/o error happened * @raise EIO if a low-level i/o error happened
* @raise EFBIG or EINVAL if `length` is too huge * @raise EFBIG or EINVAL if `length` is too huge
* @raise ENOTSUP if `fd` is a zip file descriptor * @raise ENOTSUP if `fd` is a zip file descriptor
@ -62,6 +64,8 @@
*/ */
int ftruncate(int fd, int64_t length) { int ftruncate(int fd, int64_t length) {
int rc; int rc;
BEGIN_CANCELLATION_POINT;
if (fd < 0) { if (fd < 0) {
rc = ebadf(); rc = ebadf();
} else if (__isfdkind(fd, kFdZip)) { } else if (__isfdkind(fd, kFdZip)) {
@ -78,6 +82,8 @@ int ftruncate(int fd, int64_t length) {
} else { } else {
rc = ebadf(); rc = ebadf();
} }
END_CANCELLATION_POINT;
STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc); STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc);
return rc; return rc;
} }

View file

@ -42,7 +42,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
int fd; int fd;
union metastat st[2]; union metastat st[2];
char buf[XNU_MAXPATHLEN], *ret = NULL; char buf[XNU_MAXPATHLEN], *ret = NULL;
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) { if ((fd = __sys_openat_nc(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
if (__sys_fstat(fd, &st[0]) != -1) { if (__sys_fstat(fd, &st[0]) != -1) {
if (st[0].xnu.st_dev && st[0].xnu.st_ino) { if (st[0].xnu.st_dev && st[0].xnu.st_ino) {
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) { if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {

View file

@ -29,7 +29,7 @@ int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
int rc; int rc;
struct timeval wt, t1, t2, td; struct timeval wt, t1, t2, td;
if (rem) sys_gettimeofday_xnu(&t1, 0, 0); if (rem) sys_gettimeofday_xnu(&t1, 0, 0);
wt = _timespec_totimeval(*req); // rounds up wt = timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &wt); rc = sys_select(0, 0, 0, 0, &wt);
if (rem) { if (rem) {
if (!rc) { if (!rc) {
@ -39,12 +39,12 @@ int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
// xnu select() doesn't modify timeout // xnu select() doesn't modify timeout
// so we need, yet another system call // so we need, yet another system call
sys_gettimeofday_xnu(&t2, 0, 0); sys_gettimeofday_xnu(&t2, 0, 0);
td = _timeval_sub(t2, t1); td = timeval_sub(t2, t1);
if (_timeval_gte(td, wt)) { if (timeval_cmp(td, wt) >= 0) {
rem->tv_sec = 0; rem->tv_sec = 0;
rem->tv_nsec = 0; rem->tv_nsec = 0;
} else { } else {
*rem = _timeval_totimespec(_timeval_sub(wt, td)); *rem = timeval_totimespec(timeval_sub(wt, td));
} }
} }
} }

View file

@ -28,6 +28,7 @@
* time when -1 w/ `EINTR` is returned otherwise `rem` is undefined * time when -1 w/ `EINTR` is returned otherwise `rem` is undefined
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise EINVAL if `req->tv_nsec [0,1000000000)` * @raise EINVAL if `req->tv_nsec [0,1000000000)`
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if a signal was delivered and `rem` is updated * @raise EINTR if a signal was delivered and `rem` is updated
* @raise EFAULT if `req` is NULL or `req` / `rem` is a bad pointer * @raise EFAULT if `req` is NULL or `req` / `rem` is a bad pointer
* @raise ENOSYS on bare metal * @raise ENOSYS on bare metal

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
@ -130,6 +131,7 @@
* @raise ENOTSUP if `file` is on zip file system and process is vfork()'d * @raise ENOTSUP if `file` is on zip file system and process is vfork()'d
* @raise ENOSPC if file system is full when `file` would be `O_CREAT`ed * @raise ENOSPC if file system is full when `file` would be `O_CREAT`ed
* @raise EINTR if we needed to block and a signal was delivered instead * @raise EINTR if we needed to block and a signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise ENOENT if `file` doesn't exist when `O_CREAT` isn't in `flags` * @raise ENOENT if `file` doesn't exist when `O_CREAT` isn't in `flags`
* @raise ENOENT if `file` points to a string that's empty * @raise ENOENT if `file` points to a string that's empty
* @raise ENOMEM if insufficient memory was available * @raise ENOMEM if insufficient memory was available
@ -155,6 +157,8 @@ int openat(int dirfd, const char *file, int flags, ...) {
va_start(va, flags); va_start(va, flags);
mode = va_arg(va, unsigned); mode = va_arg(va, unsigned);
va_end(va); va_end(va);
BEGIN_CANCELLATION_POINT;
if (file && (!IsAsan() || __asan_is_valid_str(file))) { if (file && (!IsAsan() || __asan_is_valid_str(file))) {
if (!__isfdkind(dirfd, kFdZip)) { if (!__isfdkind(dirfd, kFdZip)) {
if (_weaken(__zipos_open) && if (_weaken(__zipos_open) &&
@ -177,6 +181,8 @@ int openat(int dirfd, const char *file, int flags, ...) {
} else { } else {
rc = efault(); rc = efault();
} }
END_CANCELLATION_POINT;
STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(dirfd), file, STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(dirfd), file,
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0, DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
rc); rc);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
@ -44,6 +45,7 @@
int pause(void) { int pause(void) {
int rc; int rc;
STRACE("pause() → [...]"); STRACE("pause() → [...]");
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {
// We'll polyfill pause() using select() with a null timeout, which // We'll polyfill pause() using select() with a null timeout, which
@ -64,6 +66,7 @@ int pause(void) {
rc = sys_pause_nt(); rc = sys_pause_nt();
} }
END_CANCELLATION_POINT;
STRACE("[...] pause → %d% m", rc); STRACE("[...] pause → %d% m", rc);
return rc; return rc;
} }

View file

@ -16,17 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
* Creates file-less file descriptors for interprocess communication. * Creates file-less file descriptors for interprocess communication.
* *
* @raise EMFILE if process `RLIMIT_NOFILE` has been reached
* @raise ENFILE if system-wide file limit has been reached
* @param pipefd is used to return (reader, writer) file descriptors * @param pipefd is used to return (reader, writer) file descriptors
* @param flags can have O_CLOEXEC or O_DIRECT or O_NONBLOCK * @param flags can have O_CLOEXEC or O_DIRECT or O_NONBLOCK
* @return 0 on success, or -1 w/ errno and pipefd isn't modified * @return 0 on success, or -1 w/ errno and pipefd isn't modified

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
@ -55,6 +56,8 @@
* @return fds[𝑖].revents is always zero initializaed and then will * @return fds[𝑖].revents is always zero initializaed and then will
* be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something * be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something
* was determined about the file descriptor * was determined about the file descriptor
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
* @threadsafe * @threadsafe
@ -64,6 +67,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
int rc; int rc;
size_t n; size_t n;
uint64_t millis; uint64_t millis;
BEGIN_CANCELLATION_POINT;
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) || if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) ||
!__asan_is_valid(fds, n))) { !__asan_is_valid(fds, n))) {
@ -79,6 +83,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
rc = sys_poll_nt(fds, nfds, &millis, 0); rc = sys_poll_nt(fds, nfds, &millis, 0);
} }
END_CANCELLATION_POINT;
STRACE("poll(%s, %'zu, %'d) → %d% lm", DescribePollFds(rc, fds, nfds), nfds, STRACE("poll(%s, %'zu, %'d) → %d% lm", DescribePollFds(rc, fds, nfds), nfds,
timeout_ms, rc); timeout_ms, rc);
return rc; return rc;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
@ -50,6 +51,8 @@
* *
* @param timeout if null will block indefinitely * @param timeout if null will block indefinitely
* @param sigmask may be null in which case no mask change happens * @param sigmask may be null in which case no mask change happens
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
* @threadsafe * @threadsafe
@ -62,6 +65,7 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
uint64_t millis; uint64_t millis;
sigset_t oldmask; sigset_t oldmask;
struct timespec ts, *tsp; struct timespec ts, *tsp;
BEGIN_CANCELLATION_POINT;
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) || if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &n) ||
!__asan_is_valid(fds, n) || !__asan_is_valid(fds, n) ||
@ -96,6 +100,7 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
rc = sys_poll_nt(fds, nfds, &millis, sigmask); rc = sys_poll_nt(fds, nfds, &millis, sigmask);
} }
END_CANCELLATION_POINT;
STRACE("ppoll(%s, %'zu, %s, %s) → %d% lm", DescribePollFds(rc, fds, nfds), STRACE("ppoll(%s, %'zu, %s, %s) → %d% lm", DescribePollFds(rc, fds, nfds),
nfds, DescribeTimespec(0, timeout), DescribeSigset(0, sigmask), rc); nfds, DescribeTimespec(0, timeout), DescribeSigset(0, sigmask), rc);
return rc; return rc;

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -47,6 +48,7 @@
* @raise EBADF if `fd` isn't an open file descriptor * @raise EBADF if `fd` isn't an open file descriptor
* @raise EIO if a complicated i/o error happened * @raise EIO if a complicated i/o error happened
* @raise EINTR if signal was delivered instead * @raise EINTR if signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @see pwrite(), write() * @see pwrite(), write()
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
@ -55,6 +57,8 @@
*/ */
ssize_t pread(int fd, void *buf, size_t size, int64_t offset) { ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
if (offset < 0) { if (offset < 0) {
rc = einval(); rc = einval();
} else if (fd < 0) { } else if (fd < 0) {
@ -73,6 +77,8 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
rc = ebadf(); rc = ebadf();
} }
_npassert(rc == -1 || (size_t)rc <= size); _npassert(rc == -1 || (size_t)rc <= size);
END_CANCELLATION_POINT;
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd, DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc); MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
return rc; return rc;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -114,7 +115,9 @@ static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
*/ */
ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) { ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
rc = Preadv(fd, iov, iovlen, off); rc = Preadv(fd, iov, iovlen, off);
END_CANCELLATION_POINT;
STRACE("preadv(%d, [%s], %d, %'ld) → %'ld% m", fd, STRACE("preadv(%d, [%s], %d, %'ld) → %'ld% m", fd,
DescribeIovec(rc, iov, iovlen), iovlen, off, rc); DescribeIovec(rc, iov, iovlen), iovlen, off, rc);
return rc; return rc;

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -50,6 +51,8 @@
ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) { ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
ssize_t rc; ssize_t rc;
size_t wrote; size_t wrote;
BEGIN_CANCELLATION_POINT;
if (offset < 0) { if (offset < 0) {
rc = einval(); rc = einval();
} else if (fd == -1) { } else if (fd == -1) {
@ -71,6 +74,8 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
_npassert(wrote <= size); _npassert(wrote <= size);
} }
} }
END_CANCELLATION_POINT;
DATATRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd, DATATRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc); MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
return rc; return rc;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -120,7 +121,9 @@ static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
*/ */
ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) { ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
rc = Pwritev(fd, iov, iovlen, off); rc = Pwritev(fd, iov, iovlen, off);
END_CANCELLATION_POINT;
STRACE("pwritev(%d, %s, %d, %'ld) → %'ld% m", fd, STRACE("pwritev(%d, %s, %d, %'ld) → %'ld% m", fd,
DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, off, rc); DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, off, rc);
return rc; return rc;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -49,6 +50,7 @@
* @raise EPERM if pledge() is in play without the stdio promise * @raise EPERM if pledge() is in play without the stdio promise
* @raise EIO if low-level i/o error happened * @raise EIO if low-level i/o error happened
* @raise EINTR if signal was delivered instead * @raise EINTR if signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise ENOTCONN if `fd` is a socket and it isn't connected * @raise ENOTCONN if `fd` is a socket and it isn't connected
* @raise ECONNRESET if socket peer forcibly closed connection * @raise ECONNRESET if socket peer forcibly closed connection
* @raise ETIMEDOUT if socket transmission timeout occurred * @raise ETIMEDOUT if socket transmission timeout occurred
@ -63,6 +65,7 @@
*/ */
ssize_t read(int fd, void *buf, size_t size) { ssize_t read(int fd, void *buf, size_t size) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
if (fd >= 0) { if (fd >= 0) {
if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) { if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) {
rc = efault(); rc = efault();
@ -82,6 +85,7 @@ ssize_t read(int fd, void *buf, size_t size) {
} else { } else {
rc = ebadf(); rc = ebadf();
} }
END_CANCELLATION_POINT;
DATATRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)), DATATRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, rc); buf, rc > 40 ? "..." : "", size, rc);
return rc; return rc;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -48,6 +49,7 @@
*/ */
ssize_t readv(int fd, const struct iovec *iov, int iovlen) { ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
if (fd >= 0 && iovlen >= 0) { if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) { if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
@ -74,6 +76,7 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
rc = einval(); rc = einval();
} }
END_CANCELLATION_POINT;
STRACE("readv(%d, [%s], %d) → %'ld% m", fd, DescribeIovec(rc, iov, iovlen), STRACE("readv(%d, [%s], %d) → %'ld% m", fd, DescribeIovec(rc, iov, iovlen),
iovlen, rc); iovlen, rc);
return rc; return rc;

View file

@ -22,9 +22,9 @@
/** /**
* Accumulates resource statistics in `y` to `x`. * Accumulates resource statistics in `y` to `x`.
*/ */
void _addrusage(struct rusage *x, const struct rusage *y) { void rusage_add(struct rusage *x, const struct rusage *y) {
x->ru_utime = _timeval_add(x->ru_utime, y->ru_utime); x->ru_utime = timeval_add(x->ru_utime, y->ru_utime);
x->ru_stime = _timeval_add(x->ru_stime, y->ru_stime); x->ru_stime = timeval_add(x->ru_stime, y->ru_stime);
x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss); x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss);
x->ru_ixrss += y->ru_ixrss; x->ru_ixrss += y->ru_ixrss;
x->ru_idrss += y->ru_idrss; x->ru_idrss += y->ru_idrss;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
@ -49,6 +50,8 @@ int sigsuspend(const sigset_t *ignore) {
long ms, totoms; long ms, totoms;
sigset_t save, *arg, mask = {0}; sigset_t save, *arg, mask = {0};
STRACE("sigsuspend(%s) → ...", DescribeSigset(0, ignore)); STRACE("sigsuspend(%s) → ...", DescribeSigset(0, ignore));
BEGIN_CANCELLATION_POINT;
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) { if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
rc = efault(); rc = efault();
} else if (IsXnu() || IsOpenbsd()) { } else if (IsXnu() || IsOpenbsd()) {
@ -94,6 +97,8 @@ int sigsuspend(const sigset_t *ignore) {
// TODO(jart): sigsuspend metal support // TODO(jart): sigsuspend metal support
rc = enosys(); rc = enosys();
} }
END_CANCELLATION_POINT;
STRACE("...sigsuspend → %d% m", rc); STRACE("...sigsuspend → %d% m", rc);
return rc; return rc;
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/asan.internal.h" #include "libc/calls/asan.internal.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/sigtimedwait.h" #include "libc/calls/sigtimedwait.h"
#include "libc/calls/sigtimedwait.internal.h" #include "libc/calls/sigtimedwait.internal.h"
#include "libc/calls/struct/siginfo.internal.h" #include "libc/calls/struct/siginfo.internal.h"
@ -36,6 +37,7 @@
* @param timeout is relative deadline and null means wait forever * @param timeout is relative deadline and null means wait forever
* @return signal number on success, or -1 w/ errno * @return signal number on success, or -1 w/ errno
* @raise EINTR if an asynchronous signal was delivered instead * @raise EINTR if an asynchronous signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINVAL if nanoseconds parameter was out of range * @raise EINVAL if nanoseconds parameter was out of range
* @raise EAGAIN if deadline expired * @raise EAGAIN if deadline expired
* @raise ENOSYS on Windows, XNU, OpenBSD, Metal * @raise ENOSYS on Windows, XNU, OpenBSD, Metal
@ -48,6 +50,7 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info,
char strsig[15]; char strsig[15];
struct timespec ts; struct timespec ts;
union siginfo_meta si = {0}; union siginfo_meta si = {0};
BEGIN_CANCELLATION_POINT;
if (IsAsan() && (!__asan_is_valid(set, sizeof(*set)) || if (IsAsan() && (!__asan_is_valid(set, sizeof(*set)) ||
(info && !__asan_is_valid(info, sizeof(*info))) || (info && !__asan_is_valid(info, sizeof(*info))) ||
@ -69,6 +72,7 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info,
rc = enosys(); rc = enosys();
} }
END_CANCELLATION_POINT;
STRACE("sigtimedwait(%s, [%s], %s) → %s% m", DescribeSigset(0, set), STRACE("sigtimedwait(%s, [%s], %s) → %s% m", DescribeSigset(0, set),
DescribeSiginfo(rc, info), DescribeTimespec(0, timeout), DescribeSiginfo(rc, info), DescribeTimespec(0, timeout),
strsignal_r(rc, strsig)); strsignal_r(rc, strsig));

View file

@ -25,6 +25,7 @@
* @param info if not null shall receive info about signal * @param info if not null shall receive info about signal
* @return signal number on success, or -1 w/ errno * @return signal number on success, or -1 w/ errno
* @raise EINTR if an asynchronous signal was delivered instead * @raise EINTR if an asynchronous signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise ENOSYS on OpenBSD, XNU, and Windows * @raise ENOSYS on OpenBSD, XNU, and Windows
* @see sigtimedwait() * @see sigtimedwait()
* @cancellationpoint * @cancellationpoint

View file

@ -16,7 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/clock.h"
#include "libc/time/time.h" #include "libc/time/time.h"
@ -27,16 +29,20 @@
* @return 0 if the full time elapsed, otherwise we assume an interrupt * @return 0 if the full time elapsed, otherwise we assume an interrupt
* was delivered, in which case the errno condition is ignored, and * was delivered, in which case the errno condition is ignored, and
* this function shall return the number of unslept seconds rounded * this function shall return the number of unslept seconds rounded
* using the ceiling function * using the ceiling function, and finally `-1u` may be returned if
* thread was cancelled with `PTHREAD_CANCEL_MASKED` in play
* @see clock_nanosleep() * @see clock_nanosleep()
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
* @norestart * @norestart
*/ */
unsigned sleep(unsigned seconds) { unsigned sleep(unsigned seconds) {
errno_t rc;
unsigned unslept; unsigned unslept;
struct timespec tv = {seconds}; struct timespec tv = {seconds};
if (!clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv)) return 0; if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &tv, &tv))) return 0;
if (rc == ECANCELED) return -1u;
_npassert(rc == EINTR);
unslept = tv.tv_sec; unslept = tv.tv_sec;
if (tv.tv_nsec && unslept < UINT_MAX) { if (tv.tv_nsec && unslept < UINT_MAX) {
++unslept; ++unslept;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/struct/statfs-meta.internal.h" #include "libc/calls/struct/statfs-meta.internal.h"
#include "libc/calls/struct/statfs.internal.h" #include "libc/calls/struct/statfs.internal.h"
@ -29,11 +30,15 @@
/** /**
* Returns information about filesystem. * Returns information about filesystem.
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint * @cancellationpoint
*/ */
int statfs(const char *path, struct statfs *sf) { int statfs(const char *path, struct statfs *sf) {
int rc; int rc;
union statfs_meta m; union statfs_meta m;
BEGIN_CANCELLATION_POINT;
CheckLargeStackAllocation(&m, sizeof(m)); CheckLargeStackAllocation(&m, sizeof(m));
if (!IsWindows()) { if (!IsWindows()) {
if ((rc = sys_statfs(path, &m)) != -1) { if ((rc = sys_statfs(path, &m)) != -1) {
@ -42,6 +47,8 @@ int statfs(const char *path, struct statfs *sf) {
} else { } else {
rc = sys_statfs_nt(path, sf); rc = sys_statfs_nt(path, sf);
} }
END_CANCELLATION_POINT;
STRACE("statfs(%#s, [%s]) → %d% m", path, DescribeStatfs(rc, sf)); STRACE("statfs(%#s, [%s]) → %d% m", path, DescribeStatfs(rc, sf));
return rc; return rc;
} }

View file

@ -26,7 +26,7 @@ struct rusage {
int getrusage(int, struct rusage *); int getrusage(int, struct rusage *);
int wait3(int *, int, struct rusage *); int wait3(int *, int, struct rusage *);
int wait4(int, int *, int, struct rusage *); int wait4(int, int *, int, struct rusage *);
void _addrusage(struct rusage *, const struct rusage *); void rusage_add(struct rusage *, const struct rusage *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -3,8 +3,8 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#define _timespec_zero ((struct timespec){0}) #define timespec_zero ((struct timespec){0})
#define _timespec_max ((struct timespec){0x7fffffffffffffff, 999999999}) #define timespec_max ((struct timespec){0x7fffffffffffffff, 999999999})
struct timespec { struct timespec {
int64_t tv_sec; int64_t tv_sec;
@ -21,22 +21,19 @@ int utimensat(int, const char *, const struct timespec[2], int);
int timespec_get(struct timespec *, int); int timespec_get(struct timespec *, int);
int timespec_getres(struct timespec *, int); int timespec_getres(struct timespec *, int);
int _timespec_cmp(struct timespec, struct timespec) pureconst; int timespec_cmp(struct timespec, struct timespec) pureconst;
bool _timespec_eq(struct timespec, struct timespec) pureconst; int64_t timespec_tomicros(struct timespec) pureconst;
bool _timespec_gt(struct timespec, struct timespec) pureconst; int64_t timespec_tomillis(struct timespec) pureconst;
bool _timespec_gte(struct timespec, struct timespec) pureconst; int64_t timespec_tonanos(struct timespec) pureconst;
int64_t _timespec_tomicros(struct timespec) pureconst; struct timespec timespec_add(struct timespec, struct timespec) pureconst;
int64_t _timespec_tomillis(struct timespec) pureconst; struct timespec timespec_fromnanos(int64_t) pureconst;
int64_t _timespec_tonanos(struct timespec) pureconst; struct timespec timespec_frommicros(int64_t) pureconst;
struct timespec _timespec_add(struct timespec, struct timespec) pureconst; struct timespec timespec_frommillis(int64_t) pureconst;
struct timespec _timespec_fromnanos(int64_t) pureconst; struct timespec timespec_real(void);
struct timespec _timespec_frommicros(int64_t) pureconst; struct timespec timespec_mono(void);
struct timespec _timespec_frommillis(int64_t) pureconst; struct timespec timespec_sleep(struct timespec);
struct timespec _timespec_real(void); int timespec_sleep_until(struct timespec);
struct timespec _timespec_mono(void); struct timespec timespec_sub(struct timespec, struct timespec) pureconst;
struct timespec _timespec_sleep(struct timespec);
int _timespec_sleep_until(struct timespec);
struct timespec _timespec_sub(struct timespec, struct timespec) pureconst;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -16,14 +16,11 @@ int gettimeofday(struct timeval *, struct timezone *);
int lutimes(const char *, const struct timeval[2]); int lutimes(const char *, const struct timeval[2]);
int utimes(const char *, const struct timeval[2]); int utimes(const char *, const struct timeval[2]);
int _timeval_cmp(struct timeval, struct timeval) pureconst; int timeval_cmp(struct timeval, struct timeval) pureconst;
bool _timeval_eq(struct timeval, struct timeval) pureconst; struct timeval timeval_add(struct timeval, struct timeval) pureconst;
bool _timeval_gt(struct timeval, struct timeval) pureconst; struct timeval timeval_sub(struct timeval, struct timeval) pureconst;
bool _timeval_gte(struct timeval, struct timeval) pureconst; struct timeval timespec_totimeval(struct timespec) pureconst;
struct timeval _timeval_add(struct timeval, struct timeval) pureconst; struct timespec timeval_totimespec(struct timeval) pureconst;
struct timeval _timeval_sub(struct timeval, struct timeval) pureconst;
struct timeval _timespec_totimeval(struct timespec) pureconst;
struct timespec _timeval_totimespec(struct timeval) pureconst;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -24,6 +24,7 @@ i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
i32 __sys_gettid(i64 *) hidden; i32 __sys_gettid(i64 *) hidden;
i32 __sys_munmap(void *, u64) hidden; i32 __sys_munmap(void *, u64) hidden;
i32 __sys_openat(i32, const char *, i32, u32) hidden; i32 __sys_openat(i32, const char *, i32, u32) hidden;
i32 __sys_openat_nc(i32, const char *, i32, u32) hidden;
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden; i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
i32 sys_arch_prctl(i32, i64) hidden; i32 sys_arch_prctl(i32, i64) hidden;
i32 sys_chdir(const char *) hidden; i32 sys_chdir(const char *) hidden;

View file

@ -10,21 +10,23 @@ bool __is_linux_2_6_23(void) hidden;
bool32 sys_isatty_metal(int); bool32 sys_isatty_metal(int);
int __fixupnewfd(int, int) hidden; int __fixupnewfd(int, int) hidden;
int __notziposat(int, const char *); int __notziposat(int, const char *);
int __tkill(int, int, void *) hidden;
int _fork(uint32_t) hidden;
int _isptmaster(int) hidden;
int _ptsname(int, char *, size_t) hidden;
int getdomainname_linux(char *, size_t) hidden; int getdomainname_linux(char *, size_t) hidden;
int gethostname_bsd(char *, size_t, int) hidden; int gethostname_bsd(char *, size_t, int) hidden;
int gethostname_linux(char *, size_t) hidden; int gethostname_linux(char *, size_t) hidden;
int gethostname_nt(char *, size_t, int) hidden; int gethostname_nt(char *, size_t, int) hidden;
int sys_msyscall(void *, size_t); int sys_msyscall(void *, size_t);
long sys_bogus(void); long sys_bogus(void);
ssize_t __getrandom(void *, size_t, unsigned) hidden;
void *__vdsosym(const char *, const char *) hidden; void *__vdsosym(const char *, const char *) hidden;
void __onfork(void) hidden; void __onfork(void) hidden;
void __restore_rt() hidden; void __restore_rt() hidden;
void __restore_rt_netbsd(void) hidden; void __restore_rt_netbsd(void) hidden;
void cosmo2flock(uintptr_t) hidden; void cosmo2flock(uintptr_t) hidden;
void flock2cosmo(uintptr_t) hidden; void flock2cosmo(uintptr_t) hidden;
int _ptsname(int, char *, size_t) hidden;
int _isptmaster(int) hidden;
int _fork(uint32_t) hidden;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -40,7 +40,7 @@ static int64_t GetUptime(void) {
size_t n = sizeof(x); size_t n = sizeof(x);
int mib[] = {CTL_KERN, KERN_BOOTTIME}; int mib[] = {CTL_KERN, KERN_BOOTTIME};
if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return 0; if (sys_sysctl(mib, ARRAYLEN(mib), &x, &n, 0, 0) == -1) return 0;
return _timespec_real().tv_sec - x.tv_sec; return timespec_real().tv_sec - x.tv_sec;
} }
static int64_t GetPhysmem(void) { static int64_t GetPhysmem(void) {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
@ -27,6 +28,7 @@
static textwindows int sys_tcdrain_nt(int fd) { static textwindows int sys_tcdrain_nt(int fd) {
if (!__isfdopen(fd)) return ebadf(); if (!__isfdopen(fd)) return ebadf();
if (_check_interrupts(false, g_fds.p)) return -1;
if (!FlushFileBuffers(g_fds.p[fd].handle)) return __winerr(); if (!FlushFileBuffers(g_fds.p[fd].handle)) return __winerr();
return 0; return 0;
} }
@ -39,12 +41,15 @@ static textwindows int sys_tcdrain_nt(int fd) {
* @raise ENOTTY if `fd` is open but not a teletypewriter * @raise ENOTTY if `fd` is open but not a teletypewriter
* @raise EIO if process group of writer is orphoned, calling thread is * @raise EIO if process group of writer is orphoned, calling thread is
* not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU` * not blocking `SIGTTOU`, and process isn't ignoring `SIGTTOU`
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @raise ENOSYS on bare metal * @raise ENOSYS on bare metal
* @cancellationpoint * @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int tcdrain(int fd) { int tcdrain(int fd) {
int rc; int rc;
BEGIN_CANCELLATION_POINT;
if (IsMetal()) { if (IsMetal()) {
rc = enosys(); rc = enosys();
} else if (!IsWindows()) { } else if (!IsWindows()) {
@ -52,6 +57,7 @@ int tcdrain(int fd) {
} else { } else {
rc = sys_tcdrain_nt(fd); rc = sys_tcdrain_nt(fd);
} }
END_CANCELLATION_POINT;
STRACE("tcdrain(%d) → %d% m", fd, rc); STRACE("tcdrain(%d) → %d% m", fd, rc);
return rc; return rc;
} }

View file

@ -21,7 +21,7 @@
/** /**
* Adds two nanosecond timestamps. * Adds two nanosecond timestamps.
*/ */
struct timespec _timespec_add(struct timespec x, struct timespec y) { struct timespec timespec_add(struct timespec x, struct timespec y) {
x.tv_sec += y.tv_sec; x.tv_sec += y.tv_sec;
x.tv_nsec += y.tv_nsec; x.tv_nsec += y.tv_nsec;
if (x.tv_nsec >= 1000000000) { if (x.tv_nsec >= 1000000000) {

View file

@ -20,8 +20,10 @@
/** /**
* Compares nanosecond timestamps. * Compares nanosecond timestamps.
*
* @return 0 if equal, -1 if `a < b`, or +1 if `a > b`
*/ */
int _timespec_cmp(struct timespec a, struct timespec b) { int timespec_cmp(struct timespec a, struct timespec b) {
int cmp; int cmp;
if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) { if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) {
cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);

View file

@ -21,7 +21,7 @@
/** /**
* Converts timespec interval from microseconds. * Converts timespec interval from microseconds.
*/ */
struct timespec _timespec_frommicros(int64_t x) { struct timespec timespec_frommicros(int64_t x) {
struct timespec ts; struct timespec ts;
ts.tv_sec = x / 1000000; ts.tv_sec = x / 1000000;
ts.tv_nsec = x % 1000000 * 1000; ts.tv_nsec = x % 1000000 * 1000;

View file

@ -21,7 +21,7 @@
/** /**
* Converts timespec interval from milliseconds. * Converts timespec interval from milliseconds.
*/ */
struct timespec _timespec_frommillis(int64_t x) { struct timespec timespec_frommillis(int64_t x) {
struct timespec ts; struct timespec ts;
ts.tv_sec = x / 1000; ts.tv_sec = x / 1000;
ts.tv_nsec = x % 1000 * 1000000; ts.tv_nsec = x % 1000 * 1000000;

View file

@ -21,7 +21,7 @@
/** /**
* Converts timespec interval from nanoseconds. * Converts timespec interval from nanoseconds.
*/ */
struct timespec _timespec_fromnanos(int64_t x) { struct timespec timespec_fromnanos(int64_t x) {
struct timespec ts; struct timespec ts;
ts.tv_sec = x / 1000000000; ts.tv_sec = x / 1000000000;
ts.tv_nsec = x % 1000000000; ts.tv_nsec = x % 1000000000;

View file

@ -26,7 +26,7 @@
* @param ts receives `CLOCK_REALTIME` timestamp * @param ts receives `CLOCK_REALTIME` timestamp
* @param base must be `TIME_UTC` * @param base must be `TIME_UTC`
* @return `base` on success, or `0` on failure * @return `base` on success, or `0` on failure
* @see _timespec_real() * @see timespec_real()
*/ */
int timespec_get(struct timespec *ts, int base) { int timespec_get(struct timespec *ts, int base) {
if (base == TIME_UTC && !clock_gettime(CLOCK_REALTIME, ts)) { if (base == TIME_UTC && !clock_gettime(CLOCK_REALTIME, ts)) {

View file

@ -25,9 +25,9 @@
* *
* This function uses a `CLOCK_MONOTONIC` clock and never fails. * This function uses a `CLOCK_MONOTONIC` clock and never fails.
* *
* @see _timespec_real() * @see timespec_real()
*/ */
struct timespec _timespec_mono(void) { struct timespec timespec_mono(void) {
struct timespec ts; struct timespec ts;
_npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts)); _npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts));
return ts; return ts;

View file

@ -27,9 +27,9 @@
* clock_gettime() or timespec_real() this interface avoids the use of * clock_gettime() or timespec_real() this interface avoids the use of
* pointers which lets time handling code become more elegant. * pointers which lets time handling code become more elegant.
* *
* @see _timespec_mono() * @see timespec_mono()
*/ */
struct timespec _timespec_real(void) { struct timespec timespec_real(void) {
struct timespec ts; struct timespec ts;
_npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts)); _npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts));
return ts; return ts;

View file

@ -17,8 +17,10 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/clock.h"
/** /**
@ -26,13 +28,14 @@
* *
* @return unslept time which may be non-zero if the call was interrupted * @return unslept time which may be non-zero if the call was interrupted
*/ */
struct timespec _timespec_sleep(struct timespec delay) { struct timespec timespec_sleep(struct timespec delay) {
int rc; errno_t rc;
struct timespec remain; struct timespec remain;
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) { BLOCK_CANCELLATIONS;
return (struct timespec){0}; bzero(&remain, sizeof(remain));
} else { if ((rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) {
_npassert(rc == EINTR || rc == ECANCELED); _npassert(rc == EINTR);
return remain;
} }
ALLOW_CANCELLATIONS;
return remain;
} }

View file

@ -26,9 +26,12 @@
* Sleeps until the specified time. * Sleeps until the specified time.
* *
* @return 0 on success, or EINTR if interrupted * @return 0 on success, or EINTR if interrupted
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @cancellationpoint
*/ */
errno_t _timespec_sleep_until(struct timespec abs_deadline) { errno_t timespec_sleep_until(struct timespec abs_deadline) {
int rc; errno_t rc;
rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0); rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0);
_npassert(!rc || rc == EINTR || rc == ECANCELED); _npassert(!rc || rc == EINTR || rc == ECANCELED);
return rc; return rc;

View file

@ -21,7 +21,7 @@
/** /**
* Subtracts two nanosecond timestamps. * Subtracts two nanosecond timestamps.
*/ */
struct timespec _timespec_sub(struct timespec a, struct timespec b) { struct timespec timespec_sub(struct timespec a, struct timespec b) {
a.tv_sec -= b.tv_sec; a.tv_sec -= b.tv_sec;
if (a.tv_nsec < b.tv_nsec) { if (a.tv_nsec < b.tv_nsec) {
a.tv_nsec += 1000000000; a.tv_nsec += 1000000000;

View file

@ -31,9 +31,9 @@
* `INT64_MIN` may be returned. The `errno` variable isn't changed. * `INT64_MIN` may be returned. The `errno` variable isn't changed.
* *
* @return 64-bit scalar holding microseconds since epoch * @return 64-bit scalar holding microseconds since epoch
* @see _timespec_totimeval() * @see timespec_totimeval()
*/ */
int64_t _timespec_tomicros(struct timespec ts) { int64_t timespec_tomicros(struct timespec ts) {
int64_t us; int64_t us;
// reduce precision from nanos to micros // reduce precision from nanos to micros
if (ts.tv_nsec <= 999999000) { if (ts.tv_nsec <= 999999000) {

View file

@ -32,7 +32,7 @@
* *
* @return 64-bit scalar milliseconds since epoch * @return 64-bit scalar milliseconds since epoch
*/ */
int64_t _timespec_tomillis(struct timespec ts) { int64_t timespec_tomillis(struct timespec ts) {
int64_t ms; int64_t ms;
// reduce precision from nanos to millis // reduce precision from nanos to millis
if (ts.tv_nsec <= 999000000) { if (ts.tv_nsec <= 999000000) {

View file

@ -27,7 +27,7 @@
* *
* @return 64-bit integer holding nanoseconds since epoch * @return 64-bit integer holding nanoseconds since epoch
*/ */
int64_t _timespec_tonanos(struct timespec x) { int64_t timespec_tonanos(struct timespec x) {
int64_t ns; int64_t ns;
if (!__builtin_mul_overflow(x.tv_sec, 1000000000ul, &ns) && if (!__builtin_mul_overflow(x.tv_sec, 1000000000ul, &ns) &&
!__builtin_add_overflow(ns, x.tv_nsec, &ns)) { !__builtin_add_overflow(ns, x.tv_nsec, &ns)) {

View file

@ -27,9 +27,9 @@
* timestamp has a special meaning. * timestamp has a special meaning.
* *
* @return microseconds since epoch * @return microseconds since epoch
* @see _timespec_tomicros() * @see timespec_tomicros()
*/ */
struct timeval _timespec_totimeval(struct timespec ts) { struct timeval timespec_totimeval(struct timespec ts) {
if (ts.tv_nsec < 1000000000 - 999) { if (ts.tv_nsec < 1000000000 - 999) {
return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000}; return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000};
} else { } else {

View file

@ -21,7 +21,7 @@
/** /**
* Adds two microsecond timestamps. * Adds two microsecond timestamps.
*/ */
struct timeval _timeval_add(struct timeval x, struct timeval y) { struct timeval timeval_add(struct timeval x, struct timeval y) {
x.tv_sec += y.tv_sec; x.tv_sec += y.tv_sec;
x.tv_usec += y.tv_usec; x.tv_usec += y.tv_usec;
if (x.tv_usec >= 1000000) { if (x.tv_usec >= 1000000) {

View file

@ -19,9 +19,11 @@
#include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.h"
/** /**
* Compares microseconds timestamps. * Compares microsecond timestamps.
*
* @return 0 if equal, -1 if `a < b`, or +1 if `a > b`
*/ */
int _timeval_cmp(struct timeval a, struct timeval b) { int timeval_cmp(struct timeval a, struct timeval b) {
int cmp; int cmp;
if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) { if (!(cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec))) {
cmp = (a.tv_usec > b.tv_usec) - (a.tv_usec < b.tv_usec); cmp = (a.tv_usec > b.tv_usec) - (a.tv_usec < b.tv_usec);

View file

@ -21,7 +21,7 @@
/** /**
* Subtracts two nanosecond timestamps. * Subtracts two nanosecond timestamps.
*/ */
struct timeval _timeval_sub(struct timeval a, struct timeval b) { struct timeval timeval_sub(struct timeval a, struct timeval b) {
a.tv_sec -= b.tv_sec; a.tv_sec -= b.tv_sec;
if (a.tv_usec < b.tv_usec) { if (a.tv_usec < b.tv_usec) {
a.tv_usec += 1000000; a.tv_usec += 1000000;

View file

@ -21,6 +21,6 @@
/** /**
* Coerces `tv` from 1e-6 to 1e-9 granularity. * Coerces `tv` from 1e-6 to 1e-9 granularity.
*/ */
struct timespec _timeval_totimespec(struct timeval tv) { struct timespec timeval_totimespec(struct timeval tv) {
return (struct timespec){tv.tv_sec, tv.tv_usec * 1000}; return (struct timespec){tv.tv_sec, tv.tv_usec * 1000};
} }

View file

@ -19,29 +19,35 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
// OpenBSD has an optional `tib` parameter for extra safety
int __tkill(int tid, int sig, void *tib) {
int rc;
if (!IsWindows() && !IsMetal()) {
rc = sys_tkill(tid, sig, tib);
} else {
rc = __sig_add(tid, sig, SI_TKILL);
}
STRACE("tkill(%d, %G) → %d% m", tid, sig, rc);
return rc;
}
/** /**
* Kills thread. * Kills thread.
* *
* @param tid is thread id * @param tid is thread id
* @param sig does nothing on xnu * @param sig does nothing on xnu
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ESRCH if `tid` was valid but no such thread existed
* @raise EAGAIN if `RLIMIT_SIGPENDING` was exceeded * @raise EAGAIN if `RLIMIT_SIGPENDING` was exceeded
* @raise EINVAL if `tid` or `sig` was invalid * @raise EINVAL if `tid` or `sig` were invalid
* @raise ESRCH if no such `tid` existed
* @raise EPERM if permission was denied * @raise EPERM if permission was denied
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int tkill(int tid, int sig) { int tkill(int tid, int sig) {
int rc; return __tkill(tid, sig, 0);
if (!IsWindows() && !IsMetal()) {
rc = sys_tkill(tid, sig, 0);
} else {
rc = __sig_add(tid, sig, SI_TKILL);
}
STRACE("tkill(%d, %G) → %d% m", tid, sig, rc);
return rc;
} }

View file

@ -62,7 +62,10 @@
* other platforms. * other platforms.
* *
* @return file descriptor on success, or -1 w/ errno * @return file descriptor on success, or -1 w/ errno
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EINTR if signal was delivered
* @see tmpfile() for stdio version * @see tmpfile() for stdio version
* @cancellationpoint
* @asyncsignalsafe * @asyncsignalsafe
* @threadsafe * @threadsafe
* @vforksafe * @vforksafe

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -34,7 +35,10 @@ int touch(const char *file, uint32_t mode) {
olderr = errno; olderr = errno;
if ((rc = utimes(file, 0)) == -1 && errno == ENOENT) { if ((rc = utimes(file, 0)) == -1 && errno == ENOENT) {
errno = olderr; errno = olderr;
if ((fd = open(file, O_CREAT | O_WRONLY, mode)) == -1) return -1; BLOCK_CANCELLATIONS;
fd = open(file, O_CREAT | O_WRONLY, mode);
ALLOW_CANCELLATIONS;
if (fd == -1) return -1;
return close(fd); return close(fd);
} }
return rc; return rc;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -46,6 +47,7 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise EINVAL if `length` is negative * @raise EINVAL if `length` is negative
* @raise EINTR if signal was delivered instead * @raise EINTR if signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EFBIG or EINVAL if `length` is too huge * @raise EFBIG or EINVAL if `length` is too huge
* @raise EFAULT if `path` points to invalid memory * @raise EFAULT if `path` points to invalid memory
* @raise ENOTSUP if `path` is a zip filesystem path * @raise ENOTSUP if `path` is a zip filesystem path
@ -65,6 +67,8 @@
int truncate(const char *path, int64_t length) { int truncate(const char *path, int64_t length) {
int rc; int rc;
struct ZiposUri zipname; struct ZiposUri zipname;
BEGIN_CANCELLATION_POINT;
if (IsMetal()) { if (IsMetal()) {
rc = enosys(); rc = enosys();
} else if (!path || (IsAsan() && !__asan_is_valid_str(path))) { } else if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
@ -80,6 +84,8 @@ int truncate(const char *path, int64_t length) {
} else { } else {
rc = sys_truncate_nt(path, length); rc = sys_truncate_nt(path, length);
} }
END_CANCELLATION_POINT;
STRACE("truncate(%#s, %'ld) → %d% m", path, length, rc); STRACE("truncate(%#s, %'ld) → %d% m", path, length, rc);
return rc; return rc;
} }

View file

@ -17,9 +17,9 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/landlock.h" #include "libc/calls/landlock.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/bpf.h" #include "libc/calls/struct/bpf.h"
#include "libc/calls/struct/filter.h" #include "libc/calls/struct/filter.h"
#include "libc/calls/struct/seccomp.h" #include "libc/calls/struct/seccomp.h"
@ -29,8 +29,8 @@
#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/thread/tls.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
@ -45,6 +45,7 @@
#include "libc/sysv/consts/pr.h" #include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/s.h" #include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
#define OFF(f) offsetof(struct seccomp_data, f) #define OFF(f) offsetof(struct seccomp_data, f)
@ -234,7 +235,9 @@ int sys_unveil_linux(const char *path, const char *permissions) {
} }
// now we can open the path // now we can open the path
BLOCK_CANCELLATIONS;
rc = sys_open(path, O_PATH | O_NOFOLLOW | O_CLOEXEC, 0); rc = sys_open(path, O_PATH | O_NOFOLLOW | O_CLOEXEC, 0);
ALLOW_CANCELLATIONS;
if (rc == -1) return rc; if (rc == -1) return rc;
pb.parent_fd = rc; pb.parent_fd = rc;

View file

@ -26,12 +26,13 @@
* *
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise EINTR if a signal was delivered while sleeping * @raise EINTR if a signal was delivered while sleeping
* @raise ECANCELED if thread was cancelled in masked mode
* @see clock_nanosleep() * @see clock_nanosleep()
* @cancellationpoint * @cancellationpoint
* @norestart * @norestart
*/ */
int usleep(uint32_t micros) { int usleep(uint32_t micros) {
struct timespec ts = _timespec_frommicros(micros); struct timespec ts = timespec_frommicros(micros);
if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, 0)) return eintr(); if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, 0)) return eintr();
return 0; return 0;
} }

View file

@ -39,8 +39,8 @@ int sys_utimensat(int dirfd, const char *path, const struct timespec ts[2],
if (rc == -1 && errno == ENOSYS && path) { if (rc == -1 && errno == ENOSYS && path) {
errno = olderr; errno = olderr;
if (ts) { if (ts) {
tv[0] = _timespec_totimeval(ts[0]); tv[0] = timespec_totimeval(ts[0]);
tv[1] = _timespec_totimeval(ts[1]); tv[1] = timespec_totimeval(ts[1]);
rc = sys_utimes(path, tv); rc = sys_utimes(path, tv);
} else { } else {
rc = sys_utimes(path, NULL); rc = sys_utimes(path, NULL);

View file

@ -42,16 +42,16 @@ int sys_utimensat_xnu(int dirfd, const char *path, const struct timespec ts[2],
if (ts[0].tv_nsec == UTIME_NOW) { if (ts[0].tv_nsec == UTIME_NOW) {
tv[0] = now; tv[0] = now;
} else if (ts[0].tv_nsec == UTIME_OMIT) { } else if (ts[0].tv_nsec == UTIME_OMIT) {
tv[0] = _timespec_totimeval(st.st_atim); tv[0] = timespec_totimeval(st.st_atim);
} else { } else {
tv[0] = _timespec_totimeval(ts[0]); tv[0] = timespec_totimeval(ts[0]);
} }
if (ts[1].tv_nsec == UTIME_NOW) { if (ts[1].tv_nsec == UTIME_NOW) {
tv[1] = now; tv[1] = now;
} else if (ts[1].tv_nsec == UTIME_OMIT) { } else if (ts[1].tv_nsec == UTIME_OMIT) {
tv[1] = _timespec_totimeval(st.st_mtim); tv[1] = timespec_totimeval(st.st_mtim);
} else { } else {
tv[1] = _timespec_totimeval(ts[1]); tv[1] = timespec_totimeval(ts[1]);
} }
} else { } else {
tv[0] = now; tv[0] = now;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/struct/rusage.internal.h" #include "libc/calls/struct/rusage.internal.h"
#include "libc/calls/wait4.h" #include "libc/calls/wait4.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -41,6 +42,8 @@
int wait4(int pid, int *opt_out_wstatus, int options, int wait4(int pid, int *opt_out_wstatus, int options,
struct rusage *opt_out_rusage) { struct rusage *opt_out_rusage) {
int rc, ws = 0; int rc, ws = 0;
BEGIN_CANCELLATION_POINT;
if (IsAsan() && if (IsAsan() &&
((opt_out_wstatus && ((opt_out_wstatus &&
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) || !__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) ||
@ -53,6 +56,8 @@ int wait4(int pid, int *opt_out_wstatus, int options,
rc = sys_wait4_nt(pid, &ws, options, opt_out_rusage); rc = sys_wait4_nt(pid, &ws, options, opt_out_rusage);
} }
if (rc != -1 && opt_out_wstatus) *opt_out_wstatus = ws; if (rc != -1 && opt_out_wstatus) *opt_out_wstatus = ws;
END_CANCELLATION_POINT;
STRACE("wait4(%d, [%#x], %d, %p) → %d% m", pid, ws, options, opt_out_rusage, STRACE("wait4(%d, [%#x], %d, %p) → %d% m", pid, ws, options, opt_out_rusage,
rc); rc);
return rc; return rc;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
@ -51,6 +52,7 @@
* @raise ENOSPC if device containing `fd` is full * @raise ENOSPC if device containing `fd` is full
* @raise EIO if low-level i/o error happened * @raise EIO if low-level i/o error happened
* @raise EINTR if signal was delivered instead * @raise EINTR if signal was delivered instead
* @raise ECANCELED if thread was cancelled in masked mode
* @raise EAGAIN if `O_NONBLOCK` is in play and write needs to block * @raise EAGAIN if `O_NONBLOCK` is in play and write needs to block
* @raise ENOBUFS if kernel lacked internal resources; which FreeBSD * @raise ENOBUFS if kernel lacked internal resources; which FreeBSD
* and XNU say could happen with sockets, and OpenBSD documents it * and XNU say could happen with sockets, and OpenBSD documents it
@ -64,6 +66,8 @@
*/ */
ssize_t write(int fd, const void *buf, size_t size) { ssize_t write(int fd, const void *buf, size_t size) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
if (fd >= 0) { if (fd >= 0) {
if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) { if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) {
rc = efault(); rc = efault();
@ -83,6 +87,8 @@ ssize_t write(int fd, const void *buf, size_t size) {
} else { } else {
rc = ebadf(); rc = ebadf();
} }
END_CANCELLATION_POINT;
DATATRACE("write(%d, %#.*hhs%s, %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)), DATATRACE("write(%d, %#.*hhs%s, %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, rc); buf, rc > 40 ? "..." : "", size, rc);
return rc; return rc;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
@ -52,6 +53,7 @@
*/ */
ssize_t writev(int fd, const struct iovec *iov, int iovlen) { ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELLATION_POINT;
if (fd >= 0 && iovlen >= 0) { if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) { if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
@ -78,6 +80,7 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
rc = einval(); rc = einval();
} }
END_CANCELLATION_POINT;
STRACE("writev(%d, %s, %d) → %'ld% m", fd, STRACE("writev(%d, %s, %d) → %'ld% m", fd,
DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, rc); DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, rc);
return rc; return rc;

View file

@ -8,7 +8,8 @@ COSMOPOLITAN_C_START_
* @see libc/sysv/consts.sh for numbers * @see libc/sysv/consts.sh for numbers
*/ */
#if defined(__GNUC__) && defined(__MNO_RED_ZONE__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && defined(__x86_64__) && defined(__MNO_RED_ZONE__) && \
!defined(__STRICT_ANSI__)
#define errno \ #define errno \
(*({ \ (*({ \
errno_t *_ep; \ errno_t *_ep; \

View file

@ -34,10 +34,10 @@ char *getenv(const char *s) {
if (!(p = environ)) return 0; if (!(p = environ)) return 0;
e = _getenv(p, s); e = _getenv(p, s);
#if SYSDEBUG #if SYSDEBUG
if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) { // if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
// TODO(jart): memoize TZ or something // TODO(jart): memoize TZ or something
STRACE("getenv(%#s) → %#s", s, e.s); STRACE("getenv(%#s) → %#s", s, e.s);
} //}
#endif #endif
return e.s; return e.s;
} }

View file

@ -61,12 +61,12 @@ kSignalNames:
.e SIGWINCH,"SIGWINCH" .e SIGWINCH,"SIGWINCH"
.e SIGIO,"SIGIO" .e SIGIO,"SIGIO"
.e SIGSYS,"SIGSYS" .e SIGSYS,"SIGSYS"
.e SIGINFO,"SIGINFO" .e SIGPWR,"SIGPWR"
.e SIGCANCEL,"SIGCANCEL" .e SIGINFO,"SIGINFO" # order matters
.e SIGTHR,"SIGTHR" # order matters
.e SIGRTMAX,"SIGRTMAX" .e SIGRTMAX,"SIGRTMAX"
.e SIGRTMIN,"SIGRTMIN" .e SIGRTMIN,"SIGRTMIN"
.e SIGEMT,"SIGEMT" .e SIGEMT,"SIGEMT" # order matters
.e SIGPWR,"SIGPWR"
.long MAGNUM_TERMINATOR .long MAGNUM_TERMINATOR
.endobj kSignalNames,globl,hidden .endobj kSignalNames,globl,hidden
.overrun .overrun

View file

@ -29,6 +29,8 @@
* key's value is nonzero. The key's value is set to zero before it gets * key's value is nonzero. The key's value is set to zero before it gets
* called. The ordering for multiple destructor calls is unspecified. * called. The ordering for multiple destructor calls is unspecified.
* *
* The result should be passed to pthread_key_delete() later.
*
* @param key is set to the allocated key on success * @param key is set to the allocated key on success
* @param dtor specifies an optional destructor callback * @param dtor specifies an optional destructor callback
* @return 0 on success, or errno on error * @return 0 on success, or errno on error

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/blockcancel.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
@ -76,3 +77,13 @@ errno_t pthread_setcancelstate(int state, int *oldstate) {
return 0; return 0;
} }
} }
int _pthread_block_cancellations(void) {
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
return oldstate;
}
void _pthread_allow_cancellations(int oldstate) {
pthread_setcancelstate(oldstate, 0);
}

View file

@ -1,4 +1,4 @@
M(SIGKILL) M(SIGKILL)
M(SIGABRT) M(SIGABRT)
M(SIGSTOP) M(SIGSTOP)
M(SIGCANCEL) M(SIGTHR)

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#define ShouldUseMsabiAttribute() 1 #define ShouldUseMsabiAttribute() 1
#include "libc/assert.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
@ -34,6 +35,7 @@ privileged int64_t __winerr(void) {
errno_t e; errno_t e;
if (IsWindows()) { if (IsWindows()) {
e = __dos2errno(__imp_GetLastError()); e = __dos2errno(__imp_GetLastError());
_npassert(e > 0);
} else { } else {
e = ENOSYS; e = ENOSYS;
} }

View file

@ -54,6 +54,13 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
char *debugbin, *p1, *p2, *p3, *addr2line; char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames]; char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
// DWARF is a weak standard. Platforms that use LLVM or old GNU
// usually can't be counted upon to print backtraces correctly.
if (!IsLinux() && !IsWindows()) {
ShowHint("won't print addr2line backtrace because probably llvm");
return -1;
}
if (!PLEDGED(STDIO) || !PLEDGED(EXEC) || !PLEDGED(EXEC)) { if (!PLEDGED(STDIO) || !PLEDGED(EXEC) || !PLEDGED(EXEC)) {
return -1; return -1;
} }
@ -69,13 +76,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
return -1; return -1;
} }
// DWARF is a weak standard. Platforms that use LLVM or old GNU
// usually can't be counted upon to print backtraces correctly.
if (!IsLinux() && !IsWindows()) {
ShowHint("won't print addr2line backtrace because probably llvm");
return -1;
}
// backtrace_test.com failing on windows for some reason via runitd // backtrace_test.com failing on windows for some reason via runitd
// don't want to pull in the high-level syscalls here anyway // don't want to pull in the high-level syscalls here anyway
if (IsWindows()) { if (IsWindows()) {

View file

@ -16,9 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigaltstack.h" #include "libc/calls/struct/sigaltstack.h"
#include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
@ -40,17 +42,16 @@ STATIC_YOINK("PrintBacktraceUsingSymbols"); // for backtracing
STATIC_YOINK("malloc_inspect_all"); // for asan memory origin STATIC_YOINK("malloc_inspect_all"); // for asan memory origin
STATIC_YOINK("GetSymbolByAddr"); // for asan memory origin STATIC_YOINK("GetSymbolByAddr"); // for asan memory origin
extern const unsigned char __oncrash_thunks[8][11];
static struct sigaltstack g_oldsigaltstack;
static struct sigaction g_oldcrashacts[8]; static struct sigaction g_oldcrashacts[8];
extern const unsigned char __oncrash_thunks[8][11];
static void InstallCrashHandlers(int extraflags) { static void InstallCrashHandlers(int extraflags) {
int e; int e;
size_t i; size_t i;
struct sigaction sa; struct sigaction sa;
bzero(&sa, sizeof(sa)); bzero(&sa, sizeof(sa));
sa.sa_flags = SA_SIGINFO | SA_NODEFER | extraflags;
sigfillset(&sa.sa_mask); sigfillset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO | SA_NODEFER | extraflags;
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
sigdelset(&sa.sa_mask, kCrashSigs[i]); sigdelset(&sa.sa_mask, kCrashSigs[i]);
} }
@ -81,11 +82,6 @@ relegated void RestoreDefaultCrashSignalHandlers(void) {
strace_enabled(+1); strace_enabled(+1);
} }
static void FreeSigAltStack(void *p) {
sigaltstack(&g_oldsigaltstack, 0);
munmap(p, GetStackSize());
}
/** /**
* Installs crash signal handlers. * Installs crash signal handlers.
* *
@ -102,7 +98,6 @@ static void FreeSigAltStack(void *p) {
* useful, for example, if a program is caught in an infinite loop. * useful, for example, if a program is caught in an infinite loop.
*/ */
void ShowCrashReports(void) { void ShowCrashReports(void) {
char *sp;
struct sigaltstack ss; struct sigaltstack ss;
_wantcrashreports = true; _wantcrashreports = true;
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */ /* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
@ -116,19 +111,12 @@ void ShowCrashReports(void) {
kCrashSigs[7] = SIGURG; /* placeholder */ kCrashSigs[7] = SIGURG; /* placeholder */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */ /* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
if (!IsWindows()) { if (!IsWindows()) {
bzero(&ss, sizeof(ss));
ss.ss_flags = 0; ss.ss_flags = 0;
ss.ss_size = GetStackSize(); ss.ss_size = GetStackSize();
// FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here // FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here
// OpenBSD sigaltstack() auto-applies MAP_STACK to the memory // OpenBSD sigaltstack() auto-applies MAP_STACK to the memory
if ((sp = _mapanon(GetStackSize()))) { _npassert((ss.ss_sp = _mapanon(GetStackSize())));
ss.ss_sp = sp; _npassert(!sigaltstack(&ss, 0));
if (!sigaltstack(&ss, &g_oldsigaltstack)) {
__cxa_atexit(FreeSigAltStack, ss.ss_sp, 0);
} else {
munmap(ss.ss_sp, GetStackSize());
}
}
InstallCrashHandlers(SA_ONSTACK); InstallCrashHandlers(SA_ONSTACK);
} else { } else {
InstallCrashHandlers(0); InstallCrashHandlers(0);

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/dprintf.h" #include "libc/calls/dprintf.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
@ -96,10 +97,11 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
if (!f) return; if (!f) return;
flockfile(f); flockfile(f);
strace_enabled(-1); strace_enabled(-1);
BLOCK_CANCELLATIONS;
// We display TIMESTAMP.MICROS normally. However, when we log multiple // We display TIMESTAMP.MICROS normally. However, when we log multiple
// times in the same second, we display TIMESTAMP+DELTAMICROS instead. // times in the same second, we display TIMESTAMP+DELTAMICROS instead.
t2 = _timespec_real(); t2 = timespec_real();
if (t2.tv_sec == vflogf_ts.tv_sec) { if (t2.tv_sec == vflogf_ts.tv_sec) {
sign = "+"; sign = "+";
dots = t2.tv_nsec - vflogf_ts.tv_nsec; dots = t2.tv_nsec - vflogf_ts.tv_nsec;
@ -138,6 +140,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
unreachable; unreachable;
} }
ALLOW_CANCELLATIONS;
strace_enabled(+1); strace_enabled(+1);
funlockfile(f); funlockfile(f);
} }

View file

@ -309,10 +309,10 @@ static int Usleep(void) {
struct timespec t; struct timespec t;
if (n > 1) { if (n > 1) {
f = 0; f = 0;
t = _timespec_frommicros(atoi(args[1])); t = timespec_frommicros(atoi(args[1]));
} else { } else {
f = TIMER_ABSTIME; f = TIMER_ABSTIME;
t = _timespec_max; t = timespec_max;
} }
return clock_nanosleep(0, f, &t, 0); return clock_nanosleep(0, f, &t, 0);
} }

Some files were not shown because too many files have changed in this diff Show more