Improve cancellations, randomness, and time

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

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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);