mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 02:38:31 +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
|
@ -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/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -44,6 +45,8 @@ int accept4(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize,
|
|||
int flags) {
|
||||
int rc;
|
||||
char addrbuf[72];
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!out_addr || !inout_addrsize ||
|
||||
(IsAsan() && !__asan_is_valid(out_addr, *inout_addrsize))) {
|
||||
rc = efault();
|
||||
|
@ -54,6 +57,8 @@ int accept4(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize,
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("accept4(%d, [%s]) -> %d% lm", fd,
|
||||
DescribeSockaddr(out_addr, inout_addrsize ? *inout_addrsize : 0), 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/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -41,6 +42,8 @@
|
|||
*/
|
||||
int connect(int fd, const struct sockaddr *addr, uint32_t addrsize) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (addr && !(IsAsan() && !__asan_is_valid(addr, addrsize))) {
|
||||
if (!IsWindows()) {
|
||||
rc = sys_connect(fd, addr, addrsize);
|
||||
|
@ -52,6 +55,8 @@ int connect(int fd, const struct sockaddr *addr, uint32_t addrsize) {
|
|||
} else {
|
||||
rc = efault();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("connect(%d, %s) → %d% lm", fd, DescribeSockaddr(addr, addrsize), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,13 @@
|
|||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -1431,8 +1433,14 @@ err:
|
|||
* @return epoll file descriptor, or -1 on failure
|
||||
*/
|
||||
int epoll_create(int size) {
|
||||
if (size <= 0) return einval();
|
||||
return epoll_create1(0);
|
||||
int rc;
|
||||
if (size <= 0) {
|
||||
rc = einval();
|
||||
} else {
|
||||
rc = epoll_create1(0);
|
||||
}
|
||||
STRACE("epoll_create(%d) → %d% m", size, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1443,13 +1451,16 @@ int epoll_create(int size) {
|
|||
* @return epoll file descriptor, or -1 on failure
|
||||
*/
|
||||
int epoll_create1(int flags) {
|
||||
int fd;
|
||||
if (flags & ~O_CLOEXEC) return einval();
|
||||
if (!IsWindows()) {
|
||||
return __fixupnewfd(sys_epoll_create(1337), flags);
|
||||
int rc;
|
||||
if (flags & ~O_CLOEXEC) {
|
||||
rc = einval();
|
||||
} else if (!IsWindows()) {
|
||||
rc = __fixupnewfd(sys_epoll_create(1337), flags);
|
||||
} else {
|
||||
return sys_epoll_create1_nt(flags);
|
||||
rc = sys_epoll_create1_nt(flags);
|
||||
}
|
||||
STRACE("epoll_create1(%#x) → %d% m", flags, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1466,30 +1477,33 @@ int epoll_create1(int flags) {
|
|||
* @param fd is file descriptor to monitor
|
||||
* @param ev is ignored if op is EPOLL_CTL_DEL
|
||||
* @param ev->events can have these flags:
|
||||
* - EPOLLIN: trigger on fd readable
|
||||
* - EPOLLOUT: trigger on fd writeable
|
||||
* - EPOLLERR: trigger on fd error (superfluous: always reported)
|
||||
* - EPOLLHUP: trigger on fd remote hangup (superfluous: always reported)
|
||||
* - EPOLLPRI: trigger on fd exceptional conditions, e.g. oob
|
||||
* - EPOLLONESHOT: report event(s) only once
|
||||
* - EPOLLEXCLUSIVE: not supported on windows
|
||||
* - EPOLLWAKEUP: not supported on windows
|
||||
* - EPOLLET: edge triggered mode (not supported on windows)
|
||||
* - EPOLLRDNORM
|
||||
* - EPOLLRDBAND
|
||||
* - EPOLLWRNORM
|
||||
* - EPOLLWRBAND
|
||||
* - EPOLLRDHUP
|
||||
* - EPOLLMSG
|
||||
* - `EPOLLIN`: trigger on fd readable
|
||||
* - `EPOLLOUT`: trigger on fd writeable
|
||||
* - `EPOLLERR`: trigger on fd error (superfluous: always reported)
|
||||
* - `EPOLLHUP`: trigger on fd remote hangup (superfluous: always reported)
|
||||
* - `EPOLLPRI`: trigger on fd exceptional conditions, e.g. oob
|
||||
* - `EPOLLONESHOT`: report event(s) only once
|
||||
* - `EPOLLEXCLUSIVE`: not supported on windows
|
||||
* - `EPOLLWAKEUP`: not supported on windows
|
||||
* - `EPOLLET`: edge triggered mode (not supported on windows)
|
||||
* - `EPOLLRDNORM`
|
||||
* - `EPOLLRDBAND`
|
||||
* - `EPOLLWRNORM`
|
||||
* - `EPOLLWRBAND`
|
||||
* - `EPOLLRDHUP`
|
||||
* - `EPOLLMSG`
|
||||
* @error ENOTSOCK on Windows if fd isn't a socket :(
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
return sys_epoll_ctl(epfd, op, fd, ev);
|
||||
rc = sys_epoll_ctl(epfd, op, fd, ev);
|
||||
} else {
|
||||
return sys_epoll_ctl_nt(epfd, op, fd, ev);
|
||||
rc = sys_epoll_ctl_nt(epfd, op, fd, ev);
|
||||
}
|
||||
STRACE("epoll_ctl(%d, %d, %d, %p) → %d% m", epfd, op, fd, ev, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1504,9 +1518,15 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev) {
|
|||
*/
|
||||
int epoll_wait(int epfd, struct epoll_event *events, int maxevents,
|
||||
int timeoutms) {
|
||||
int rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (!IsWindows()) {
|
||||
return sys_epoll_wait(epfd, events, maxevents, timeoutms);
|
||||
rc = sys_epoll_wait(epfd, events, maxevents, timeoutms);
|
||||
} else {
|
||||
return sys_epoll_wait_nt(epfd, events, maxevents, timeoutms);
|
||||
rc = sys_epoll_wait_nt(epfd, events, maxevents, timeoutms);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("epoll_wait(%d, %p, %d, %d) → %d% m", epfd, events, maxevents,
|
||||
timeoutms, 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/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -45,6 +46,8 @@
|
|||
* This system call is supported on all platforms. It's like select()
|
||||
* except that it atomically changes the sigprocmask() during the op.
|
||||
*
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
|
@ -60,6 +63,8 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|||
const sigset_t *s;
|
||||
size_t n;
|
||||
} ss;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (nfds < 0) {
|
||||
rc = einval();
|
||||
} else if (IsAsan() &&
|
||||
|
@ -91,6 +96,8 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|||
}
|
||||
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, tvp, sigmask);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
POLLTRACE("pselect(%d, %p, %p, %p, %s, %s) → %d% m", nfds, readfds, writefds,
|
||||
exceptfds, DescribeTimeval(0, timeout), DescribeSigset(0, sigmask),
|
||||
rc);
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
│ 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/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
@ -36,11 +37,14 @@
|
|||
* @return number of bytes received, 0 on remote close, or -1 w/ errno
|
||||
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
|
||||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
ssize_t recv(int fd, void *buf, size_t size, int flags) {
|
||||
ssize_t rc, got;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && !__asan_is_valid(buf, size)) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
|
@ -60,6 +64,8 @@ ssize_t recv(int fd, void *buf, size_t size, int flags) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("recv(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags);
|
||||
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"
|
||||
|
@ -54,6 +55,8 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
|
|||
ssize_t rc;
|
||||
uint32_t sz;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() &&
|
||||
(!__asan_is_valid(buf, size) ||
|
||||
(opt_out_srcaddr &&
|
||||
|
@ -88,6 +91,8 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("recvfrom(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc);
|
||||
return rc;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.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,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
|
|||
struct msghdr msg2;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
|
@ -92,6 +94,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
#if defined(SYSDEBUG) && _DATATRACE
|
||||
if (__strace > 0 && strace_enabled(0) > 0) {
|
||||
|
|
|
@ -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/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -32,6 +33,8 @@
|
|||
* this is polyfilled to translate into poll(). So it's recommended that
|
||||
* poll() be used instead.
|
||||
*
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR if signal was delivered
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
|
@ -42,6 +45,8 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|||
int rc;
|
||||
POLLTRACE("select(%d, %p, %p, %p, %s) → ...", nfds, readfds, writefds,
|
||||
exceptfds, DescribeTimeval(0, timeout));
|
||||
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (nfds < 0) {
|
||||
rc = einval();
|
||||
} else if (IsAsan() &&
|
||||
|
@ -55,6 +60,8 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|||
} else {
|
||||
rc = sys_select_nt(nfds, readfds, writefds, exceptfds, timeout, 0);
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
POLLTRACE("select(%d, %p, %p, %p, [%s]) → %d% m", nfds, readfds, writefds,
|
||||
exceptfds, DescribeTimeval(rc, timeout), rc);
|
||||
return rc;
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
│ 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/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
@ -37,11 +38,14 @@
|
|||
* @return number of bytes transmitted, or -1 w/ errno
|
||||
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
|
||||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
ssize_t send(int fd, const void *buf, size_t size, int flags) {
|
||||
ssize_t rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && !__asan_is_valid(buf, size)) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
|
@ -61,6 +65,8 @@ ssize_t send(int fd, const void *buf, size_t size, int flags) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("send(%d, %#.*hhs%s, %'zu, %#x) → %'ld% lm", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc);
|
||||
return rc;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.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"
|
||||
|
@ -52,6 +53,7 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
|
|||
struct msghdr msg2;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
|
@ -79,6 +81,7 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
|
||||
#if defined(SYSDEBUG) && _DATATRACE
|
||||
if (__strace > 0 && strace_enabled(0) > 0) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.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"
|
||||
|
@ -58,6 +59,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, int flags,
|
|||
ssize_t rc;
|
||||
uint32_t bsdaddrsize;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() && (!__asan_is_valid(buf, size) ||
|
||||
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
|
||||
rc = efault();
|
||||
|
@ -87,6 +90,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, int flags,
|
|||
rc = ebadf();
|
||||
}
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("sendto(%d, %#.*hhs%s, %'zu, %#x, %p, %u) → %'ld% lm", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags,
|
||||
opt_addr, addrsize, rc);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue