mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-06 08:56:22 +00:00
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:
parent
0d7c265392
commit
3f0bcdc3ef
173 changed files with 1599 additions and 782 deletions
|
@ -20,22 +20,22 @@ int main(int argc, char *argv[]) {
|
|||
volatile unsigned long x;
|
||||
struct timespec now, start, next, interval;
|
||||
printf("hammering the cpu...\n");
|
||||
next = start = _timespec_mono();
|
||||
interval = _timespec_frommillis(500);
|
||||
next = _timespec_add(next, interval);
|
||||
next = start = timespec_mono();
|
||||
interval = timespec_frommillis(500);
|
||||
next = timespec_add(next, interval);
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
x *= 7;
|
||||
if (!(i % 256)) {
|
||||
now = _timespec_mono();
|
||||
if (_timespec_gte(now, next)) {
|
||||
now = timespec_mono();
|
||||
if (timespec_cmp(now, next) >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
next = _timespec_add(next, interval);
|
||||
next = timespec_add(next, interval);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ void show(int clock) {
|
|||
}
|
||||
shown[n++] = clock;
|
||||
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 {
|
||||
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
|
||||
}
|
||||
|
|
39
examples/reboot.c
Normal file
39
examples/reboot.c
Normal 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
39
examples/shutdown.c
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -7,13 +7,16 @@ COSMOPOLITAN_C_START_
|
|||
#define BLOCK_CANCELLATIONS \
|
||||
do { \
|
||||
int _CancelState; \
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_CancelState)
|
||||
_CancelState = _pthread_block_cancellations()
|
||||
|
||||
#define ALLOW_CANCELLATIONS \
|
||||
pthread_setcancelstate(_CancelState, 0); \
|
||||
} \
|
||||
#define ALLOW_CANCELLATIONS \
|
||||
_pthread_allow_cancellations(_CancelState); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
int _pthread_block_cancellations(void);
|
||||
void _pthread_allow_cancellations(int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */
|
||||
|
|
|
@ -179,12 +179,12 @@ o//libc/calls/statfs2cosmo.o: private \
|
|||
# we always want -O2 because:
|
||||
# division is expensive if not optimized
|
||||
o/$(MODE)/libc/calls/clock.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/_timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/_timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
|
||||
o/$(MODE)/libc/calls/timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommicros.o: private \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ int64_t clock(void) {
|
|||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
|
||||
errno = e;
|
||||
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 {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static struct {
|
||||
pthread_once_t once;
|
||||
|
@ -30,7 +30,7 @@ static struct {
|
|||
} g_mono;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
|
|||
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||
cycles = rdtsc() - g_mono.base_tick;
|
||||
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;
|
||||
} else {
|
||||
return einval();
|
||||
|
|
|
@ -33,24 +33,24 @@ textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
|||
abs = *req;
|
||||
for (;;) {
|
||||
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;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
abs = _timespec_add(now, *req);
|
||||
abs = timespec_add(now, *req);
|
||||
for (;;) {
|
||||
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 (rem) *rem = _timespec_sub(abs, now);
|
||||
if (rem) *rem = timespec_sub(abs, now);
|
||||
return -1;
|
||||
}
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
_timespec_tomillis(_timespec_sub(abs, now))),
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ int sys_clock_nanosleep_openbsd(int clock, int flags,
|
|||
res = sys_nanosleep(req, rem);
|
||||
} else {
|
||||
sys_clock_gettime(clock, &now);
|
||||
if (_timespec_gt(*req, now)) {
|
||||
rel = _timespec_sub(*req, now);
|
||||
if (timespec_cmp(*req, now) > 0) {
|
||||
rel = timespec_sub(*req, now);
|
||||
res = sys_nanosleep(&rel, 0);
|
||||
} else {
|
||||
res = 0;
|
||||
|
|
|
@ -31,10 +31,10 @@ int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
|
|||
struct timeval now, abs, rel;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = _timespec_totimeval(*req);
|
||||
abs = timespec_totimeval(*req);
|
||||
sys_gettimeofday_xnu(&now, 0, 0);
|
||||
if (_timeval_gt(abs, now)) {
|
||||
rel = _timeval_sub(abs, now);
|
||||
if (timeval_cmp(abs, now) > 0) {
|
||||
rel = timeval_sub(abs, now);
|
||||
res = sys_select(0, 0, 0, 0, &rel);
|
||||
} else {
|
||||
res = 0;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
|
@ -55,8 +56,8 @@
|
|||
*
|
||||
* struct timespec rel, now, abs;
|
||||
* clock_gettime(CLOCK_REALTIME, &now);
|
||||
* rel = _timespec_frommillis(100);
|
||||
* abs = _timespec_add(now, rel);
|
||||
* rel = timespec_frommillis(100);
|
||||
* abs = timespec_add(now, rel);
|
||||
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
|
||||
*
|
||||
* 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
|
||||
* @return 0 on success, or errno on error
|
||||
* @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 EFAULT if `req` or null or bad memory was passed
|
||||
* @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,
|
||||
struct timespec *rem) {
|
||||
int rc, e = errno;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
|
||||
(rem && !__asan_is_valid_timespec(rem))))) {
|
||||
|
@ -113,6 +116,8 @@ errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
|
|||
errno = e;
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
#if SYSDEBUG
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
* @raise EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @raise EINVAL if flags are bad or first is greater than last
|
||||
* @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 ENOMEM on Linux maybe
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
|
@ -39,6 +41,7 @@ static bool HasCopyFileRange(void) {
|
|||
bool ok;
|
||||
int e, rc;
|
||||
e = errno;
|
||||
BLOCK_CANCELLATIONS;
|
||||
if (IsLinux()) {
|
||||
// We modernize our detection by a few years for simplicity.
|
||||
// This system call is chosen since it's listed by pledge().
|
||||
|
@ -49,6 +52,7 @@ static bool HasCopyFileRange(void) {
|
|||
} else {
|
||||
ok = false;
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
errno = e;
|
||||
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 EPERM if `fdout` refers to an immutable file on Linux
|
||||
* @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 EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
|
||||
* @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
|
||||
* @see sendfile() for seekable → socket
|
||||
* @see splice() for fd ↔ pipe
|
||||
* @cancellationpoint
|
||||
*/
|
||||
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
int64_t *opt_in_out_outoffset, size_t uptobytes,
|
||||
uint32_t flags) {
|
||||
ssize_t rc;
|
||||
pthread_once(&g_copy_file_range.once, copy_file_range_init);
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!g_copy_file_range.ok) {
|
||||
rc = enosys();
|
||||
} 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,
|
||||
opt_in_out_outoffset, uptobytes, flags);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
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_outoffset), uptobytes, flags);
|
||||
|
|
|
@ -16,19 +16,44 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ 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
|
||||
|
||||
/**
|
||||
* Returns true if timeval `x` is greater than `y`.
|
||||
*/
|
||||
bool _timeval_gt(struct timeval x, struct timeval y) {
|
||||
if (x.tv_sec > y.tv_sec) {
|
||||
return true;
|
||||
}
|
||||
if (x.tv_sec == y.tv_sec) {
|
||||
if (x.tv_usec > y.tv_usec) {
|
||||
return true;
|
||||
int begin_cancellation_point(void) {
|
||||
int state = 0;
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
state = pt->flags & PT_INCANCEL;
|
||||
pt->flags |= PT_INCANCEL;
|
||||
}
|
||||
}
|
||||
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
25
libc/calls/cp.internal.h
Normal 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_ */
|
|
@ -31,6 +31,7 @@
|
|||
* @param mode is octal bits, e.g. 0644 usually
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
|
|
|
@ -31,13 +31,11 @@
|
|||
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
int64_t rc, proc, handle;
|
||||
_unassert(oldfd >= 0);
|
||||
_unassert(newfd >= -1);
|
||||
_unassert(!(flags & ~O_CLOEXEC));
|
||||
|
||||
__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 != kFdConsole)) {
|
||||
__fds_unlock();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -40,6 +41,8 @@ static bool IsApeBinary(const char *path) {
|
|||
int fd;
|
||||
char buf[8];
|
||||
bool res = false;
|
||||
// TODO(jart): Should we block signals too?
|
||||
BLOCK_CANCELLATIONS;
|
||||
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
|
||||
if (sys_read(fd, buf, 8) == 8 && //
|
||||
(READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
|
@ -48,6 +51,7 @@ static bool IsApeBinary(const char *path) {
|
|||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/flock.internal.h"
|
||||
|
@ -94,7 +95,7 @@
|
|||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW`
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW` or `F_OFD_SETLKW`
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
|
@ -113,7 +114,9 @@ int fcntl(int fd, int cmd, ...) {
|
|||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
|
||||
END_CANCELLATION_POINT;
|
||||
} else {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
|
||||
}
|
||||
|
|
|
@ -23,5 +23,6 @@
|
|||
textwindows int sys_fdatasync_nt(int fd) {
|
||||
// TODO(jart): what should we do with worker pipes?
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (_check_interrupts(false, 0)) return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -30,6 +31,8 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
|
@ -37,11 +40,13 @@ int fdatasync(int fd) {
|
|||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fdatasync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fdatasync(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = fstat(fd, &st);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -35,11 +36,15 @@
|
|||
*/
|
||||
int flock(int fd, int op) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!IsWindows()) {
|
||||
rc = sys_flock(fd, op);
|
||||
} else {
|
||||
rc = sys_flock_nt(fd, op);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("flock(%d, %d) → %d% m", fd, op, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
|
@ -33,7 +34,9 @@
|
|||
int fstatfs(int fd, struct statfs *sf) {
|
||||
int rc;
|
||||
union statfs_meta m;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
CheckLargeStackAllocation(&m, sizeof(m));
|
||||
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_fstatfs(fd, &m)) != -1) {
|
||||
statfs2cosmo(sf, &m);
|
||||
|
@ -43,6 +46,8 @@ int fstatfs(int fd, struct statfs *sf) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fstatfs(%d, [%s]) → %d% m", fd, DescribeStatfs(rc, sf));
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -28,6 +29,8 @@
|
|||
* Blocks until kernel flushes buffers for fd to disk.
|
||||
*
|
||||
* @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 __nosync to secretly disable
|
||||
* @cancellationpoint
|
||||
|
@ -37,11 +40,13 @@ int fsync(int fd) {
|
|||
int rc;
|
||||
struct stat st;
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fsync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("fysnc(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = fstat(fd, &st);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -49,6 +50,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `length` is negative
|
||||
* @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 EFBIG or EINVAL if `length` is too huge
|
||||
* @raise ENOTSUP if `fd` is a zip file descriptor
|
||||
|
@ -62,6 +64,8 @@
|
|||
*/
|
||||
int ftruncate(int fd, int64_t length) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (fd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(fd, kFdZip)) {
|
||||
|
@ -78,6 +82,8 @@ int ftruncate(int fd, int64_t length) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("ftruncate(%d, %'ld) → %d% m", fd, length, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
|
|||
int fd;
|
||||
union metastat st[2];
|
||||
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 (st[0].xnu.st_dev && st[0].xnu.st_ino) {
|
||||
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
|
||||
|
|
|
@ -29,7 +29,7 @@ int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
|
|||
int rc;
|
||||
struct timeval wt, t1, t2, td;
|
||||
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);
|
||||
if (rem) {
|
||||
if (!rc) {
|
||||
|
@ -39,12 +39,12 @@ int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
|
|||
// xnu select() doesn't modify timeout
|
||||
// so we need, yet another system call
|
||||
sys_gettimeofday_xnu(&t2, 0, 0);
|
||||
td = _timeval_sub(t2, t1);
|
||||
if (_timeval_gte(td, wt)) {
|
||||
td = timeval_sub(t2, t1);
|
||||
if (timeval_cmp(td, wt) >= 0) {
|
||||
rem->tv_sec = 0;
|
||||
rem->tv_nsec = 0;
|
||||
} else {
|
||||
*rem = _timeval_totimespec(_timeval_sub(wt, td));
|
||||
*rem = timeval_totimespec(timeval_sub(wt, td));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* time when -1 w/ `EINTR` is returned otherwise `rem` is undefined
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @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 EFAULT if `req` is NULL or `req` / `rem` is a bad pointer
|
||||
* @raise ENOSYS on bare metal
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.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 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 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` points to a string that's empty
|
||||
* @raise ENOMEM if insufficient memory was available
|
||||
|
@ -155,6 +157,8 @@ int openat(int dirfd, const char *file, int flags, ...) {
|
|||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (file && (!IsAsan() || __asan_is_valid_str(file))) {
|
||||
if (!__isfdkind(dirfd, kFdZip)) {
|
||||
if (_weaken(__zipos_open) &&
|
||||
|
@ -177,6 +181,8 @@ int openat(int dirfd, const char *file, int flags, ...) {
|
|||
} else {
|
||||
rc = efault();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(dirfd), file,
|
||||
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
|
||||
rc);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
@ -44,6 +45,7 @@
|
|||
int pause(void) {
|
||||
int rc;
|
||||
STRACE("pause() → [...]");
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!IsWindows()) {
|
||||
// We'll polyfill pause() using select() with a null timeout, which
|
||||
|
@ -64,6 +66,7 @@ int pause(void) {
|
|||
rc = sys_pause_nt();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("[...] pause → %d% m", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* 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 flags can have O_CLOEXEC or O_DIRECT or O_NONBLOCK
|
||||
* @return 0 on success, or -1 w/ errno and pipefd isn't modified
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
@ -55,6 +56,8 @@
|
|||
* @return fds[𝑖].revents is always zero initializaed and then will
|
||||
* be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something
|
||||
* was determined about the file descriptor
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
|
@ -64,6 +67,7 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
|
|||
int rc;
|
||||
size_t n;
|
||||
uint64_t millis;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &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);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("poll(%s, %'zu, %'d) → %d% lm", DescribePollFds(rc, fds, nfds), nfds,
|
||||
timeout_ms, rc);
|
||||
return rc;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
|
@ -50,6 +51,8 @@
|
|||
*
|
||||
* @param timeout if null will block indefinitely
|
||||
* @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
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
|
@ -62,6 +65,7 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
|
|||
uint64_t millis;
|
||||
sigset_t oldmask;
|
||||
struct timespec ts, *tsp;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && (__builtin_mul_overflow(nfds, sizeof(struct pollfd), &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);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("ppoll(%s, %'zu, %s, %s) → %d% lm", DescribePollFds(rc, fds, nfds),
|
||||
nfds, DescribeTimespec(0, timeout), DescribeSigset(0, sigmask), rc);
|
||||
return rc;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
|
@ -47,6 +48,7 @@
|
|||
* @raise EBADF if `fd` isn't an open file descriptor
|
||||
* @raise EIO if a complicated i/o error happened
|
||||
* @raise EINTR if signal was delivered instead
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @see pwrite(), write()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
|
@ -55,6 +57,8 @@
|
|||
*/
|
||||
ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
|
||||
ssize_t rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (offset < 0) {
|
||||
rc = einval();
|
||||
} else if (fd < 0) {
|
||||
|
@ -73,6 +77,8 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
|
|||
rc = ebadf();
|
||||
}
|
||||
_npassert(rc == -1 || (size_t)rc <= size);
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
|
||||
return rc;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.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 rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
rc = Preadv(fd, iov, iovlen, off);
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("preadv(%d, [%s], %d, %'ld) → %'ld% m", fd,
|
||||
DescribeIovec(rc, iov, iovlen), iovlen, off, rc);
|
||||
return rc;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.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 rc;
|
||||
size_t wrote;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (offset < 0) {
|
||||
rc = einval();
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
|
||||
return rc;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.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 rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
rc = Pwritev(fd, iov, iovlen, off);
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("pwritev(%d, %s, %d, %'ld) → %'ld% m", fd,
|
||||
DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, off, rc);
|
||||
return rc;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
|
@ -49,6 +50,7 @@
|
|||
* @raise EPERM if pledge() is in play without the stdio promise
|
||||
* @raise EIO if low-level i/o error happened
|
||||
* @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 ECONNRESET if socket peer forcibly closed connection
|
||||
* @raise ETIMEDOUT if socket transmission timeout occurred
|
||||
|
@ -63,6 +65,7 @@
|
|||
*/
|
||||
ssize_t read(int fd, void *buf, size_t size) {
|
||||
ssize_t rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (fd >= 0) {
|
||||
if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) {
|
||||
rc = efault();
|
||||
|
@ -82,6 +85,7 @@ ssize_t read(int fd, void *buf, size_t size) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
|
||||
buf, rc > 40 ? "..." : "", size, rc);
|
||||
return rc;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.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 rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (fd >= 0 && iovlen >= 0) {
|
||||
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();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("readv(%d, [%s], %d) → %'ld% m", fd, DescribeIovec(rc, iov, iovlen),
|
||||
iovlen, rc);
|
||||
return rc;
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
/**
|
||||
* Accumulates resource statistics in `y` to `x`.
|
||||
*/
|
||||
void _addrusage(struct rusage *x, const struct rusage *y) {
|
||||
x->ru_utime = _timeval_add(x->ru_utime, y->ru_utime);
|
||||
x->ru_stime = _timeval_add(x->ru_stime, y->ru_stime);
|
||||
void rusage_add(struct rusage *x, const struct rusage *y) {
|
||||
x->ru_utime = timeval_add(x->ru_utime, y->ru_utime);
|
||||
x->ru_stime = timeval_add(x->ru_stime, y->ru_stime);
|
||||
x->ru_maxrss = MAX(x->ru_maxrss, y->ru_maxrss);
|
||||
x->ru_ixrss += y->ru_ixrss;
|
||||
x->ru_idrss += y->ru_idrss;
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
@ -49,6 +50,8 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
long ms, totoms;
|
||||
sigset_t save, *arg, mask = {0};
|
||||
STRACE("sigsuspend(%s) → ...", DescribeSigset(0, ignore));
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
|
||||
rc = efault();
|
||||
} else if (IsXnu() || IsOpenbsd()) {
|
||||
|
@ -94,6 +97,8 @@ int sigsuspend(const sigset_t *ignore) {
|
|||
// TODO(jart): sigsuspend metal support
|
||||
rc = enosys();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("...sigsuspend → %d% m", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/sigtimedwait.h"
|
||||
#include "libc/calls/sigtimedwait.internal.h"
|
||||
#include "libc/calls/struct/siginfo.internal.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
* @param timeout is relative deadline and null means wait forever
|
||||
* @return signal number on success, or -1 w/ errno
|
||||
* @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 EAGAIN if deadline expired
|
||||
* @raise ENOSYS on Windows, XNU, OpenBSD, Metal
|
||||
|
@ -48,6 +50,7 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info,
|
|||
char strsig[15];
|
||||
struct timespec ts;
|
||||
union siginfo_meta si = {0};
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && (!__asan_is_valid(set, sizeof(*set)) ||
|
||||
(info && !__asan_is_valid(info, sizeof(*info))) ||
|
||||
|
@ -69,6 +72,7 @@ int sigtimedwait(const sigset_t *set, siginfo_t *info,
|
|||
rc = enosys();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("sigtimedwait(%s, [%s], %s) → %s% m", DescribeSigset(0, set),
|
||||
DescribeSiginfo(rc, info), DescribeTimespec(0, timeout),
|
||||
strsignal_r(rc, strsig));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* @param info if not null shall receive info about signal
|
||||
* @return signal number on success, or -1 w/ errno
|
||||
* @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
|
||||
* @see sigtimedwait()
|
||||
* @cancellationpoint
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
@ -27,16 +29,20 @@
|
|||
* @return 0 if the full time elapsed, otherwise we assume an interrupt
|
||||
* was delivered, in which case the errno condition is ignored, and
|
||||
* this function shall return the number of unslept seconds rounded
|
||||
* using the ceiling function
|
||||
* using the ceiling function, and finally `-1u` may be returned if
|
||||
* thread was cancelled with `PTHREAD_CANCEL_MASKED` in play
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @norestart
|
||||
*/
|
||||
unsigned sleep(unsigned seconds) {
|
||||
errno_t rc;
|
||||
unsigned unslept;
|
||||
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;
|
||||
if (tv.tv_nsec && unslept < UINT_MAX) {
|
||||
++unslept;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/statfs-meta.internal.h"
|
||||
#include "libc/calls/struct/statfs.internal.h"
|
||||
|
@ -29,11 +30,15 @@
|
|||
/**
|
||||
* Returns information about filesystem.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
*/
|
||||
int statfs(const char *path, struct statfs *sf) {
|
||||
int rc;
|
||||
union statfs_meta m;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
CheckLargeStackAllocation(&m, sizeof(m));
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_statfs(path, &m)) != -1) {
|
||||
|
@ -42,6 +47,8 @@ int statfs(const char *path, struct statfs *sf) {
|
|||
} else {
|
||||
rc = sys_statfs_nt(path, sf);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("statfs(%#s, [%s]) → %d% m", path, DescribeStatfs(rc, sf));
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ struct rusage {
|
|||
int getrusage(int, struct rusage *);
|
||||
int wait3(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_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define _timespec_zero ((struct timespec){0})
|
||||
#define _timespec_max ((struct timespec){0x7fffffffffffffff, 999999999})
|
||||
#define timespec_zero ((struct timespec){0})
|
||||
#define timespec_max ((struct timespec){0x7fffffffffffffff, 999999999})
|
||||
|
||||
struct timespec {
|
||||
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_getres(struct timespec *, int);
|
||||
|
||||
int _timespec_cmp(struct timespec, struct timespec) pureconst;
|
||||
bool _timespec_eq(struct timespec, struct timespec) pureconst;
|
||||
bool _timespec_gt(struct timespec, struct timespec) pureconst;
|
||||
bool _timespec_gte(struct timespec, struct timespec) pureconst;
|
||||
int64_t _timespec_tomicros(struct timespec) pureconst;
|
||||
int64_t _timespec_tomillis(struct timespec) pureconst;
|
||||
int64_t _timespec_tonanos(struct timespec) pureconst;
|
||||
struct timespec _timespec_add(struct timespec, struct timespec) pureconst;
|
||||
struct timespec _timespec_fromnanos(int64_t) pureconst;
|
||||
struct timespec _timespec_frommicros(int64_t) pureconst;
|
||||
struct timespec _timespec_frommillis(int64_t) pureconst;
|
||||
struct timespec _timespec_real(void);
|
||||
struct timespec _timespec_mono(void);
|
||||
struct timespec _timespec_sleep(struct timespec);
|
||||
int _timespec_sleep_until(struct timespec);
|
||||
struct timespec _timespec_sub(struct timespec, struct timespec) pureconst;
|
||||
int timespec_cmp(struct timespec, struct timespec) pureconst;
|
||||
int64_t timespec_tomicros(struct timespec) pureconst;
|
||||
int64_t timespec_tomillis(struct timespec) pureconst;
|
||||
int64_t timespec_tonanos(struct timespec) pureconst;
|
||||
struct timespec timespec_add(struct timespec, struct timespec) pureconst;
|
||||
struct timespec timespec_fromnanos(int64_t) pureconst;
|
||||
struct timespec timespec_frommicros(int64_t) pureconst;
|
||||
struct timespec timespec_frommillis(int64_t) pureconst;
|
||||
struct timespec timespec_real(void);
|
||||
struct timespec timespec_mono(void);
|
||||
struct timespec timespec_sleep(struct timespec);
|
||||
int timespec_sleep_until(struct timespec);
|
||||
struct timespec timespec_sub(struct timespec, struct timespec) pureconst;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -16,14 +16,11 @@ int gettimeofday(struct timeval *, struct timezone *);
|
|||
int lutimes(const char *, const struct timeval[2]);
|
||||
int utimes(const char *, const struct timeval[2]);
|
||||
|
||||
int _timeval_cmp(struct timeval, struct timeval) pureconst;
|
||||
bool _timeval_eq(struct timeval, struct timeval) pureconst;
|
||||
bool _timeval_gt(struct timeval, struct timeval) pureconst;
|
||||
bool _timeval_gte(struct timeval, struct timeval) pureconst;
|
||||
struct timeval _timeval_add(struct timeval, 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;
|
||||
int timeval_cmp(struct timeval, struct timeval) pureconst;
|
||||
struct timeval timeval_add(struct timeval, 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_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -24,6 +24,7 @@ i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
|
|||
i32 __sys_gettid(i64 *) hidden;
|
||||
i32 __sys_munmap(void *, u64) 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_arch_prctl(i32, i64) hidden;
|
||||
i32 sys_chdir(const char *) hidden;
|
||||
|
|
|
@ -10,21 +10,23 @@ bool __is_linux_2_6_23(void) hidden;
|
|||
bool32 sys_isatty_metal(int);
|
||||
int __fixupnewfd(int, int) hidden;
|
||||
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 gethostname_bsd(char *, size_t, int) hidden;
|
||||
int gethostname_linux(char *, size_t) hidden;
|
||||
int gethostname_nt(char *, size_t, int) hidden;
|
||||
int sys_msyscall(void *, size_t);
|
||||
long sys_bogus(void);
|
||||
ssize_t __getrandom(void *, size_t, unsigned) hidden;
|
||||
void *__vdsosym(const char *, const char *) hidden;
|
||||
void __onfork(void) hidden;
|
||||
void __restore_rt() hidden;
|
||||
void __restore_rt_netbsd(void) hidden;
|
||||
void cosmo2flock(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_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -40,7 +40,7 @@ static int64_t GetUptime(void) {
|
|||
size_t n = sizeof(x);
|
||||
int mib[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
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) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
|
||||
static textwindows int sys_tcdrain_nt(int fd) {
|
||||
if (!__isfdopen(fd)) return ebadf();
|
||||
if (_check_interrupts(false, g_fds.p)) return -1;
|
||||
if (!FlushFileBuffers(g_fds.p[fd].handle)) return __winerr();
|
||||
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 EIO if process group of writer is orphoned, calling thread is
|
||||
* 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
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tcdrain(int fd) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!IsWindows()) {
|
||||
|
@ -52,6 +57,7 @@ int tcdrain(int fd) {
|
|||
} else {
|
||||
rc = sys_tcdrain_nt(fd);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("tcdrain(%d) → %d% m", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* 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_nsec += y.tv_nsec;
|
||||
if (x.tv_nsec >= 1000000000) {
|
|
@ -20,8 +20,10 @@
|
|||
|
||||
/**
|
||||
* 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;
|
||||
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);
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* Converts timespec interval from microseconds.
|
||||
*/
|
||||
struct timespec _timespec_frommicros(int64_t x) {
|
||||
struct timespec timespec_frommicros(int64_t x) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = x / 1000000;
|
||||
ts.tv_nsec = x % 1000000 * 1000;
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* Converts timespec interval from milliseconds.
|
||||
*/
|
||||
struct timespec _timespec_frommillis(int64_t x) {
|
||||
struct timespec timespec_frommillis(int64_t x) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = x / 1000;
|
||||
ts.tv_nsec = x % 1000 * 1000000;
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* Converts timespec interval from nanoseconds.
|
||||
*/
|
||||
struct timespec _timespec_fromnanos(int64_t x) {
|
||||
struct timespec timespec_fromnanos(int64_t x) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = x / 1000000000;
|
||||
ts.tv_nsec = x % 1000000000;
|
|
@ -26,7 +26,7 @@
|
|||
* @param ts receives `CLOCK_REALTIME` timestamp
|
||||
* @param base must be `TIME_UTC`
|
||||
* @return `base` on success, or `0` on failure
|
||||
* @see _timespec_real()
|
||||
* @see timespec_real()
|
||||
*/
|
||||
int timespec_get(struct timespec *ts, int base) {
|
||||
if (base == TIME_UTC && !clock_gettime(CLOCK_REALTIME, ts)) {
|
|
@ -25,9 +25,9 @@
|
|||
*
|
||||
* 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;
|
||||
_npassert(!clock_gettime(CLOCK_MONOTONIC_FAST, &ts));
|
||||
return ts;
|
|
@ -27,9 +27,9 @@
|
|||
* clock_gettime() or timespec_real() this interface avoids the use of
|
||||
* 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;
|
||||
_npassert(!clock_gettime(CLOCK_REALTIME_FAST, &ts));
|
||||
return ts;
|
|
@ -17,8 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
/**
|
||||
|
@ -26,13 +28,14 @@
|
|||
*
|
||||
* @return unslept time which may be non-zero if the call was interrupted
|
||||
*/
|
||||
struct timespec _timespec_sleep(struct timespec delay) {
|
||||
int rc;
|
||||
struct timespec timespec_sleep(struct timespec delay) {
|
||||
errno_t rc;
|
||||
struct timespec remain;
|
||||
if (!(rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) {
|
||||
return (struct timespec){0};
|
||||
} else {
|
||||
_npassert(rc == EINTR || rc == ECANCELED);
|
||||
return remain;
|
||||
BLOCK_CANCELLATIONS;
|
||||
bzero(&remain, sizeof(remain));
|
||||
if ((rc = clock_nanosleep(CLOCK_REALTIME, 0, &delay, &remain))) {
|
||||
_npassert(rc == EINTR);
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
return remain;
|
||||
}
|
|
@ -26,9 +26,12 @@
|
|||
* Sleeps until the specified time.
|
||||
*
|
||||
* @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) {
|
||||
int rc;
|
||||
errno_t timespec_sleep_until(struct timespec abs_deadline) {
|
||||
errno_t rc;
|
||||
rc = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs_deadline, 0);
|
||||
_npassert(!rc || rc == EINTR || rc == ECANCELED);
|
||||
return rc;
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* 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;
|
||||
if (a.tv_nsec < b.tv_nsec) {
|
||||
a.tv_nsec += 1000000000;
|
|
@ -31,9 +31,9 @@
|
|||
* `INT64_MIN` may be returned. The `errno` variable isn't changed.
|
||||
*
|
||||
* @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;
|
||||
// reduce precision from nanos to micros
|
||||
if (ts.tv_nsec <= 999999000) {
|
|
@ -32,7 +32,7 @@
|
|||
*
|
||||
* @return 64-bit scalar milliseconds since epoch
|
||||
*/
|
||||
int64_t _timespec_tomillis(struct timespec ts) {
|
||||
int64_t timespec_tomillis(struct timespec ts) {
|
||||
int64_t ms;
|
||||
// reduce precision from nanos to millis
|
||||
if (ts.tv_nsec <= 999000000) {
|
|
@ -27,7 +27,7 @@
|
|||
*
|
||||
* @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;
|
||||
if (!__builtin_mul_overflow(x.tv_sec, 1000000000ul, &ns) &&
|
||||
!__builtin_add_overflow(ns, x.tv_nsec, &ns)) {
|
|
@ -27,9 +27,9 @@
|
|||
* timestamp has a special meaning.
|
||||
*
|
||||
* @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) {
|
||||
return (struct timeval){ts.tv_sec, (ts.tv_nsec + 999) / 1000};
|
||||
} else {
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* 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_usec += y.tv_usec;
|
||||
if (x.tv_usec >= 1000000) {
|
|
@ -19,9 +19,11 @@
|
|||
#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;
|
||||
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);
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* 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;
|
||||
if (a.tv_usec < b.tv_usec) {
|
||||
a.tv_usec += 1000000;
|
|
@ -21,6 +21,6 @@
|
|||
/**
|
||||
* 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};
|
||||
}
|
|
@ -19,29 +19,35 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.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.
|
||||
*
|
||||
* @param tid is thread id
|
||||
* @param sig does nothing on xnu
|
||||
* @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 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
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int tkill(int tid, int sig) {
|
||||
int rc;
|
||||
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;
|
||||
return __tkill(tid, sig, 0);
|
||||
}
|
||||
|
|
|
@ -62,7 +62,10 @@
|
|||
* other platforms.
|
||||
*
|
||||
* @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
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -34,7 +35,10 @@ int touch(const char *file, uint32_t mode) {
|
|||
olderr = errno;
|
||||
if ((rc = utimes(file, 0)) == -1 && errno == ENOENT) {
|
||||
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 rc;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -46,6 +47,7 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `length` is negative
|
||||
* @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 EFAULT if `path` points to invalid memory
|
||||
* @raise ENOTSUP if `path` is a zip filesystem path
|
||||
|
@ -65,6 +67,8 @@
|
|||
int truncate(const char *path, int64_t length) {
|
||||
int rc;
|
||||
struct ZiposUri zipname;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
|
@ -80,6 +84,8 @@ int truncate(const char *path, int64_t length) {
|
|||
} else {
|
||||
rc = sys_truncate_nt(path, length);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("truncate(%#s, %'ld) → %d% m", path, length, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/landlock.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/bpf.h"
|
||||
#include "libc/calls/struct/filter.h"
|
||||
#include "libc/calls/struct/seccomp.h"
|
||||
|
@ -29,8 +29,8 @@
|
|||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
|
@ -45,6 +45,7 @@
|
|||
#include "libc/sysv/consts/pr.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#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
|
||||
BLOCK_CANCELLATIONS;
|
||||
rc = sys_open(path, O_PATH | O_NOFOLLOW | O_CLOEXEC, 0);
|
||||
ALLOW_CANCELLATIONS;
|
||||
if (rc == -1) return rc;
|
||||
|
||||
pb.parent_fd = rc;
|
||||
|
|
|
@ -26,12 +26,13 @@
|
|||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINTR if a signal was delivered while sleeping
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @see clock_nanosleep()
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
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();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ int sys_utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
|||
if (rc == -1 && errno == ENOSYS && path) {
|
||||
errno = olderr;
|
||||
if (ts) {
|
||||
tv[0] = _timespec_totimeval(ts[0]);
|
||||
tv[1] = _timespec_totimeval(ts[1]);
|
||||
tv[0] = timespec_totimeval(ts[0]);
|
||||
tv[1] = timespec_totimeval(ts[1]);
|
||||
rc = sys_utimes(path, tv);
|
||||
} else {
|
||||
rc = sys_utimes(path, NULL);
|
||||
|
|
|
@ -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) {
|
||||
tv[0] = now;
|
||||
} else if (ts[0].tv_nsec == UTIME_OMIT) {
|
||||
tv[0] = _timespec_totimeval(st.st_atim);
|
||||
tv[0] = timespec_totimeval(st.st_atim);
|
||||
} else {
|
||||
tv[0] = _timespec_totimeval(ts[0]);
|
||||
tv[0] = timespec_totimeval(ts[0]);
|
||||
}
|
||||
if (ts[1].tv_nsec == UTIME_NOW) {
|
||||
tv[1] = now;
|
||||
} else if (ts[1].tv_nsec == UTIME_OMIT) {
|
||||
tv[1] = _timespec_totimeval(st.st_mtim);
|
||||
tv[1] = timespec_totimeval(st.st_mtim);
|
||||
} else {
|
||||
tv[1] = _timespec_totimeval(ts[1]);
|
||||
tv[1] = timespec_totimeval(ts[1]);
|
||||
}
|
||||
} else {
|
||||
tv[0] = now;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/struct/rusage.internal.h"
|
||||
#include "libc/calls/wait4.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -41,6 +42,8 @@
|
|||
int wait4(int pid, int *opt_out_wstatus, int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
int rc, ws = 0;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() &&
|
||||
((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);
|
||||
}
|
||||
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,
|
||||
rc);
|
||||
return rc;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
|
@ -51,6 +52,7 @@
|
|||
* @raise ENOSPC if device containing `fd` is full
|
||||
* @raise EIO if low-level i/o error happened
|
||||
* @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 ENOBUFS if kernel lacked internal resources; which FreeBSD
|
||||
* 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 rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (fd >= 0) {
|
||||
if ((!buf && size) || (IsAsan() && !__asan_is_valid(buf, size))) {
|
||||
rc = efault();
|
||||
|
@ -83,6 +87,8 @@ ssize_t write(int fd, const void *buf, size_t size) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("write(%d, %#.*hhs%s, %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)),
|
||||
buf, rc > 40 ? "..." : "", size, rc);
|
||||
return rc;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.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 rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (fd >= 0 && iovlen >= 0) {
|
||||
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();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("writev(%d, %s, %d) → %'ld% m", fd,
|
||||
DescribeIovec(rc != -1 ? rc : -2, iov, iovlen), iovlen, rc);
|
||||
return rc;
|
||||
|
|
|
@ -8,7 +8,8 @@ COSMOPOLITAN_C_START_
|
|||
* @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 \
|
||||
(*({ \
|
||||
errno_t *_ep; \
|
||||
|
|
|
@ -34,10 +34,10 @@ char *getenv(const char *s) {
|
|||
if (!(p = environ)) return 0;
|
||||
e = _getenv(p, s);
|
||||
#if SYSDEBUG
|
||||
if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
|
||||
// TODO(jart): memoize TZ or something
|
||||
STRACE("getenv(%#s) → %#s", s, e.s);
|
||||
}
|
||||
// if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) {
|
||||
// TODO(jart): memoize TZ or something
|
||||
STRACE("getenv(%#s) → %#s", s, e.s);
|
||||
//}
|
||||
#endif
|
||||
return e.s;
|
||||
}
|
||||
|
|
|
@ -61,12 +61,12 @@ kSignalNames:
|
|||
.e SIGWINCH,"SIGWINCH"
|
||||
.e SIGIO,"SIGIO"
|
||||
.e SIGSYS,"SIGSYS"
|
||||
.e SIGINFO,"SIGINFO"
|
||||
.e SIGCANCEL,"SIGCANCEL"
|
||||
.e SIGPWR,"SIGPWR"
|
||||
.e SIGINFO,"SIGINFO" # order matters
|
||||
.e SIGTHR,"SIGTHR" # order matters
|
||||
.e SIGRTMAX,"SIGRTMAX"
|
||||
.e SIGRTMIN,"SIGRTMIN"
|
||||
.e SIGEMT,"SIGEMT"
|
||||
.e SIGPWR,"SIGPWR"
|
||||
.e SIGEMT,"SIGEMT" # order matters
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kSignalNames,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
* 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.
|
||||
*
|
||||
* The result should be passed to pthread_key_delete() later.
|
||||
*
|
||||
* @param key is set to the allocated key on success
|
||||
* @param dtor specifies an optional destructor callback
|
||||
* @return 0 on success, or errno on error
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
@ -76,3 +77,13 @@ errno_t pthread_setcancelstate(int state, int *oldstate) {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
M(SIGKILL)
|
||||
M(SIGABRT)
|
||||
M(SIGSTOP)
|
||||
M(SIGCANCEL)
|
||||
M(SIGTHR)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/errors.h"
|
||||
|
@ -34,6 +35,7 @@ privileged int64_t __winerr(void) {
|
|||
errno_t e;
|
||||
if (IsWindows()) {
|
||||
e = __dos2errno(__imp_GetLastError());
|
||||
_npassert(e > 0);
|
||||
} else {
|
||||
e = ENOSYS;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,13 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
char *debugbin, *p1, *p2, *p3, *addr2line;
|
||||
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)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -69,13 +76,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
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
|
||||
// don't want to pull in the high-level syscalls here anyway
|
||||
if (IsWindows()) {
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigaltstack.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/internal.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("GetSymbolByAddr"); // for asan memory origin
|
||||
|
||||
extern const unsigned char __oncrash_thunks[8][11];
|
||||
static struct sigaltstack g_oldsigaltstack;
|
||||
static struct sigaction g_oldcrashacts[8];
|
||||
extern const unsigned char __oncrash_thunks[8][11];
|
||||
|
||||
static void InstallCrashHandlers(int extraflags) {
|
||||
int e;
|
||||
size_t i;
|
||||
struct sigaction sa;
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sa_flags = SA_SIGINFO | SA_NODEFER | extraflags;
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO | SA_NODEFER | extraflags;
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
||||
}
|
||||
|
@ -81,11 +82,6 @@ relegated void RestoreDefaultCrashSignalHandlers(void) {
|
|||
strace_enabled(+1);
|
||||
}
|
||||
|
||||
static void FreeSigAltStack(void *p) {
|
||||
sigaltstack(&g_oldsigaltstack, 0);
|
||||
munmap(p, GetStackSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void ShowCrashReports(void) {
|
||||
char *sp;
|
||||
struct sigaltstack ss;
|
||||
_wantcrashreports = true;
|
||||
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
|
@ -116,19 +111,12 @@ void ShowCrashReports(void) {
|
|||
kCrashSigs[7] = SIGURG; /* placeholder */
|
||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
if (!IsWindows()) {
|
||||
bzero(&ss, sizeof(ss));
|
||||
ss.ss_flags = 0;
|
||||
ss.ss_size = GetStackSize();
|
||||
// FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here
|
||||
// OpenBSD sigaltstack() auto-applies MAP_STACK to the memory
|
||||
if ((sp = _mapanon(GetStackSize()))) {
|
||||
ss.ss_sp = sp;
|
||||
if (!sigaltstack(&ss, &g_oldsigaltstack)) {
|
||||
__cxa_atexit(FreeSigAltStack, ss.ss_sp, 0);
|
||||
} else {
|
||||
munmap(ss.ss_sp, GetStackSize());
|
||||
}
|
||||
}
|
||||
_npassert((ss.ss_sp = _mapanon(GetStackSize())));
|
||||
_npassert(!sigaltstack(&ss, 0));
|
||||
InstallCrashHandlers(SA_ONSTACK);
|
||||
} else {
|
||||
InstallCrashHandlers(0);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.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;
|
||||
flockfile(f);
|
||||
strace_enabled(-1);
|
||||
BLOCK_CANCELLATIONS;
|
||||
|
||||
// We display TIMESTAMP.MICROS normally. However, when we log multiple
|
||||
// times in the same second, we display TIMESTAMP+DELTAMICROS instead.
|
||||
t2 = _timespec_real();
|
||||
t2 = timespec_real();
|
||||
if (t2.tv_sec == vflogf_ts.tv_sec) {
|
||||
sign = "+";
|
||||
dots = t2.tv_nsec - vflogf_ts.tv_nsec;
|
||||
|
@ -138,6 +140,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
unreachable;
|
||||
}
|
||||
|
||||
ALLOW_CANCELLATIONS;
|
||||
strace_enabled(+1);
|
||||
funlockfile(f);
|
||||
}
|
||||
|
|
|
@ -309,10 +309,10 @@ static int Usleep(void) {
|
|||
struct timespec t;
|
||||
if (n > 1) {
|
||||
f = 0;
|
||||
t = _timespec_frommicros(atoi(args[1]));
|
||||
t = timespec_frommicros(atoi(args[1]));
|
||||
} else {
|
||||
f = TIMER_ABSTIME;
|
||||
t = _timespec_max;
|
||||
t = timespec_max;
|
||||
}
|
||||
return clock_nanosleep(0, f, &t, 0);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue