mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-24 11:30:29 +00:00
Implement support for POSIX thread cancellations
This change makes some miracle modifications to the System Five system call support, which lets us have safe, correct, and atomic handling of thread cancellations. It all turned out to be cheaper than anticipated because it wasn't necessary to modify the system call veneers. We were able to encode the cancellability of each system call into the magnums found in libc/sysv/syscalls.sh. Since cancellations are so waq, we are also supporting a lovely Musl Libc mask feature for raising ECANCELED.
This commit is contained in:
parent
37d40e087f
commit
2278327eba
145 changed files with 715 additions and 265 deletions
|
@ -32,10 +32,10 @@
|
|||
textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize,
|
||||
int flags) {
|
||||
int64_t h;
|
||||
int client, oflags;
|
||||
int rc, client, oflags;
|
||||
struct SockFd *sockfd, *sockfd2;
|
||||
sockfd = (struct SockFd *)fd->extra;
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
for (;;) {
|
||||
if (!WSAPoll(&(struct sys_pollfd_nt){fd->handle, POLLIN}, 1,
|
||||
__SIG_POLLING_INTERVAL_MS)) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
* @param out_addr will receive the remote address
|
||||
* @param inout_addrsize provides and receives addr's byte length
|
||||
* @return client fd which needs close(), or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
* @param flags can have SOCK_{CLOEXEC,NONBLOCK}, which may apply to
|
||||
* both the newly created socket and the server one
|
||||
* @return client fd which needs close(), or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
* also means getsockname() can be called to retrieve routing details.
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
*/
|
||||
|
|
|
@ -1499,6 +1499,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev) {
|
|||
* @param maxevents is array length of events
|
||||
* @param timeoutms is milliseconds, 0 to not block, or -1 for forever
|
||||
* @return number of events stored, 0 on timeout, or -1 w/ errno
|
||||
* @cancellationpoint
|
||||
* @norestart
|
||||
*/
|
||||
int epoll_wait(int epfd, struct epoll_event *events, int maxevents,
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
│ 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/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -44,6 +44,11 @@
|
|||
*
|
||||
* This system call is supported on all platforms. It's like select()
|
||||
* except that it atomically changes the sigprocmask() during the op.
|
||||
*
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
*/
|
||||
int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
const struct timespec *timeout, const sigset_t *sigmask) {
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
err = errno;
|
||||
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags,
|
||||
&overlapped, NULL)) {
|
||||
|
|
|
@ -35,7 +35,7 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
err = errno;
|
||||
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got,
|
||||
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
* @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)
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
* @return number of bytes received, 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)
|
||||
*/
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
│ 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/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/select.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -31,6 +31,11 @@
|
|||
* This system call is supported on all platforms. However, on Windows,
|
||||
* this is polyfilled to translate into poll(). So it's recommended that
|
||||
* poll() be used instead.
|
||||
*
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @norestart
|
||||
*/
|
||||
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout) {
|
||||
|
|
|
@ -30,7 +30,7 @@ textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent,
|
||||
flags, &overlapped, NULL)) {
|
||||
rc = sent;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
// sendfile() isn't specified as raising eintr
|
||||
static textwindows int SendfileBlock(int64_t handle,
|
||||
struct NtOverlapped *overlapped) {
|
||||
int rc;
|
||||
uint32_t i, got, flags = 0;
|
||||
if (WSAGetLastError() != kNtErrorIoPending &&
|
||||
WSAGetLastError() != WSAEINPROGRESS) {
|
||||
|
@ -56,7 +57,7 @@ static textwindows int SendfileBlock(int64_t handle,
|
|||
NTTRACE("WSAWaitForMultipleEvents failed %lm");
|
||||
return __winsockerr();
|
||||
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
||||
_check_interrupts(true, g_fds.p);
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
#if _NTTRACE
|
||||
POLLTRACE("WSAWaitForMultipleEvents...");
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
* @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)
|
||||
*/
|
||||
|
|
|
@ -31,7 +31,7 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
|
|||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen),
|
||||
&sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
|
||||
rc = sent;
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
* @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)
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
|
||||
uint32_t *flags, bool restartable,
|
||||
uint32_t timeout) {
|
||||
int rc;
|
||||
uint32_t i, got;
|
||||
if (WSAGetLastError() != kNtErrorIoPending) {
|
||||
NTTRACE("sock i/o failed %lm");
|
||||
|
@ -41,7 +42,7 @@ textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
|
|||
return __winsockerr();
|
||||
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
||||
if (_check_interrupts(restartable, g_fds.p)) {
|
||||
return eintr();
|
||||
return -1;
|
||||
}
|
||||
if (timeout) {
|
||||
if (timeout <= __SIG_POLLING_INTERVAL_MS) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue