mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-08 04:08:32 +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
|
@ -255,14 +255,20 @@ static textwindows dontinline struct dirent *readdir_nt(DIR *dir) {
|
|||
*
|
||||
* @returns newly allocated DIR object, or NULL w/ errno
|
||||
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
|
||||
* @cancellationpoint
|
||||
* @see glob()
|
||||
*/
|
||||
DIR *opendir(const char *name) {
|
||||
int fd;
|
||||
DIR *res;
|
||||
int fd, rc;
|
||||
struct stat st;
|
||||
struct Zipos *zip;
|
||||
struct ZiposUri zipname;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return 0;
|
||||
}
|
||||
if (!name || (IsAsan() && !__asan_is_valid_str(name))) {
|
||||
efault();
|
||||
res = 0;
|
||||
|
@ -271,20 +277,21 @@ DIR *opendir(const char *name) {
|
|||
if (_weaken(__zipos_stat)(&zipname, &st) != -1) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
zip = _weaken(__zipos_get)();
|
||||
res = calloc(1, sizeof(DIR));
|
||||
res->iszip = true;
|
||||
res->fd = -1;
|
||||
res->zip.offset = GetZipCdirOffset(zip->cdir);
|
||||
res->zip.records = GetZipCdirRecords(zip->cdir);
|
||||
res->zip.prefix = malloc(zipname.len + 2);
|
||||
memcpy(res->zip.prefix, zipname.path, zipname.len);
|
||||
if (zipname.len && res->zip.prefix[zipname.len - 1] != '/') {
|
||||
res->zip.prefix[zipname.len++] = '/';
|
||||
if ((res = calloc(1, sizeof(DIR)))) {
|
||||
res->iszip = true;
|
||||
res->fd = -1;
|
||||
res->zip.offset = GetZipCdirOffset(zip->cdir);
|
||||
res->zip.records = GetZipCdirRecords(zip->cdir);
|
||||
res->zip.prefix = malloc(zipname.len + 2);
|
||||
memcpy(res->zip.prefix, zipname.path, zipname.len);
|
||||
if (zipname.len && res->zip.prefix[zipname.len - 1] != '/') {
|
||||
res->zip.prefix[zipname.len++] = '/';
|
||||
}
|
||||
res->zip.prefix[zipname.len] = '\0';
|
||||
res->zip.prefixlen = zipname.len;
|
||||
}
|
||||
res->zip.prefix[zipname.len] = '\0';
|
||||
res->zip.prefixlen = zipname.len;
|
||||
} else {
|
||||
errno = ENOTDIR;
|
||||
enotdir();
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -70,6 +70,7 @@ static bool have_getrandom;
|
|||
* @note this function takes around 900 cycles
|
||||
* @raise EINVAL if `f` is invalid
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @vforksafe
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Spawns subprocess and returns pipe stream.
|
||||
|
@ -35,11 +37,12 @@
|
|||
* Bourne-like syntax on all platforms including Windows.
|
||||
*
|
||||
* @see pclose()
|
||||
* @cancellationpoint
|
||||
* @threadsafe
|
||||
*/
|
||||
FILE *popen(const char *cmdline, const char *mode) {
|
||||
FILE *f;
|
||||
int e, pid, dir, flags, pipefds[2];
|
||||
int e, rc, pid, dir, flags, pipefds[2];
|
||||
flags = fopenflags(mode);
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
dir = 0;
|
||||
|
@ -49,6 +52,11 @@ FILE *popen(const char *cmdline, const char *mode) {
|
|||
einval();
|
||||
return NULL;
|
||||
}
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return 0;
|
||||
}
|
||||
if (pipe2(pipefds, O_CLOEXEC) == -1) return NULL;
|
||||
if ((f = fdopen(pipefds[dir], mode))) {
|
||||
switch ((pid = fork())) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "libc/stdio/posix_spawn.h"
|
||||
#include "libc/stdio/posix_spawn.internal.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
static int RunFileActions(struct _posix_faction *a) {
|
||||
|
@ -67,6 +68,7 @@ static int RunFileActions(struct _posix_faction *a) {
|
|||
* @param envp is environment variables, or `environ` if null
|
||||
* @return 0 on success or error number on failure
|
||||
* @see posix_spawnp() for `$PATH` searching
|
||||
* @cancellationpoint
|
||||
* @tlsrequired
|
||||
* @threadsafe
|
||||
*/
|
||||
|
@ -79,6 +81,9 @@ int posix_spawn(int *pid, const char *path,
|
|||
int s, child, policy;
|
||||
struct sched_param param;
|
||||
struct sigaction dfl = {0};
|
||||
if (_weaken(pthread_testcancel)) {
|
||||
_weaken(pthread_testcancel)();
|
||||
}
|
||||
if (!(child = vfork())) {
|
||||
if (attrp && *attrp) {
|
||||
posix_spawnattr_getflags(attrp, &flags);
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Launches program with system command interpreter.
|
||||
|
@ -37,6 +39,7 @@
|
|||
* @param cmdline is an interpreted Turing-complete command
|
||||
* @return -1 if child process couldn't be created, otherwise a wait
|
||||
* status that can be accessed using macros like WEXITSTATUS(s)
|
||||
* @cancellationpoint
|
||||
* @threadsafe
|
||||
*/
|
||||
int system(const char *cmdline) {
|
||||
|
@ -44,6 +47,9 @@ int system(const char *cmdline) {
|
|||
sigset_t chldmask, savemask;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
if (!cmdline) return 1;
|
||||
if (_weaken(pthread_testcancel)) {
|
||||
_weaken(pthread_testcancel)();
|
||||
}
|
||||
ignore.sa_flags = 0;
|
||||
ignore.sa_handler = SIG_IGN;
|
||||
sigemptyset(&ignore.sa_mask);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue