Work towards improving signals and processes

This commit is contained in:
Justine Tunney
2021-01-27 19:34:02 -08:00
parent de703b182c
commit d7ac16a9ed
96 changed files with 1474 additions and 427 deletions

View File

@@ -16,12 +16,13 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/bits.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
static struct AtFork {
size_t i;
volatile size_t i;
struct AtForkCallback {
void (*fn)(void *);
void *arg;
@@ -33,17 +34,25 @@ static struct AtFork {
*
* @return 0 on success, or -1 w/ errno
* @note vfork() won't invoke callbacks
* @asyncsignalsafe
*/
int atfork(void *fn, void *arg) {
if (g_atfork.i == ARRAYLEN(g_atfork.p)) return enomem();
g_atfork.p[g_atfork.i++] = (struct AtForkCallback){.fn = fn, .arg = arg};
return 0;
size_t i;
for (;;) {
i = g_atfork.i;
if (i == ARRAYLEN(g_atfork.p)) return enomem();
if (cmpxchg(&g_atfork.i, i, i + 1)) {
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
return 0;
}
}
}
/**
* Triggers callbacks registered by atfork().
*
* @note only fork() should call this
* @asyncsignalsafe
*/
void __onfork(void) {
size_t i;

View File

@@ -17,6 +17,9 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/files.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
@@ -30,7 +33,22 @@ textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
case F_GETFL:
return g_fds.p[fd].flags;
case F_SETFL:
return (g_fds.p[fd].flags = arg);
if (ReOpenFile(
g_fds.p[fd].handle,
(arg & O_APPEND)
? kNtFileAppendData
: (arg & O_ACCMODE) == O_RDONLY
? kNtGenericExecute | kNtFileGenericRead
: kNtGenericExecute | kNtFileGenericRead |
kNtFileGenericWrite,
(arg & O_EXCL) == O_EXCL
? kNtFileShareExclusive
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal)) {
return (g_fds.p[fd].flags = arg);
} else {
return __winerr();
}
case F_GETFD:
if (g_fds.p[fd].flags & O_CLOEXEC) {
return FD_CLOEXEC;
@@ -38,7 +56,7 @@ textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
return 0;
}
case F_SETFD:
if (arg & O_CLOEXEC) {
if (arg & FD_CLOEXEC) {
g_fds.p[fd].flags |= O_CLOEXEC;
return FD_CLOEXEC;
} else {

View File

@@ -17,15 +17,16 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
#include "libc/runtime/runtime.h"
static int g_pid;
static int __pid;
static int __get_pid(void) {
static int __getpid(void) {
if (!IsWindows()) {
return getpid$sysv();
} else {
@@ -33,20 +34,25 @@ static int __get_pid(void) {
}
}
static void __update_pid(void) {
g_pid = __get_pid();
static void __updatepid(void) {
__pid = __getpid();
}
/**
* Returns process id.
* @asyncsignalsafe
* @vforksafe
*/
int getpid(void) {
static bool once;
if (!once) {
__update_pid();
atfork(__update_pid, NULL);
once = true;
if (__vforked) {
return getpid$sysv();
}
return g_pid;
if (!once) {
__updatepid();
if (cmpxchg(&once, false, true)) {
atfork(__updatepid, NULL);
}
}
return __pid;
}

View File

@@ -27,6 +27,9 @@
/ call read() safely but you can call pread(). Call _exit() but
/ don't call exit(). Look for the vforksafe function annotation
/
/ Do not make the assumption that the parent is suspended until
/ the child terminates since this impl calls fork() on Windows.
/
/ @return pid of child process or 0 if forked process
/ @returnstwice
/ @vforksafe

View File

@@ -70,8 +70,14 @@ hidden extern const struct NtSecurityAttributes kNtIsInheritable;
ssize_t __getemptyfd(void) hidden;
int __ensurefds(int) hidden;
void __removefd(int) hidden;
bool __isfdopen(int) hidden nosideeffect;
bool __isfdkind(int, enum FdKind) hidden nosideeffect;
forceinline bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
}
forceinline bool __isfdkind(int fd, enum FdKind kind) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind == kind;
}
forceinline size_t clampio(size_t size) {
if (!IsTrustworthy()) {
@@ -214,46 +220,46 @@ void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│*/
int gettimeofday$nt(struct timeval *, struct timezone *) hidden;
bool32 isatty$nt(int) hidden;
char *getcwd$nt(char *, size_t) hidden;
int fork$nt(void) hidden;
i64 lseek$nt(int, i64, int) hidden;
int chdir$nt(const char *) hidden;
int close$nt(int) hidden;
int dup$nt(int, int, int) hidden;
int execve$nt(const char *, char *const[], char *const[]) hidden;
int faccessat$nt(int, const char *, int, uint32_t) hidden;
int fadvise$nt(int, u64, u64, int) hidden;
int fcntl$nt(int, int, unsigned) hidden;
int getpriority$nt(int) hidden;
int setpriority$nt(int) hidden;
int fdatasync$nt(int) hidden;
int flock$nt(int, int) hidden;
int fork$nt(void) hidden;
int fstat$nt(i64, struct stat *) hidden;
int ftruncate$nt(int, u64) hidden;
int kill$nt(i64, int) hidden;
int getpriority$nt(int) hidden;
int getrusage$nt(int, struct rusage *) hidden;
int gettimeofday$nt(struct timeval *, struct timezone *) hidden;
int kill$nt(int, int) hidden;
int link$nt(const char *, const char *) hidden;
int lstat$nt(const char *, struct stat *) hidden;
int madvise$nt(void *, size_t, int) hidden;
int msync$nt(void *, size_t, int) hidden;
ssize_t open$nt(const char *, u32, i32) nodiscard hidden;
int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
int pipe$nt(int[hasatleast 2], unsigned) hidden;
int rename$nt(const char *, const char *) hidden;
int rmdir$nt(const char *) hidden;
int sched_yield$nt(void) hidden;
int setitimer$nt(int, const struct itimerval *, struct itimerval *) hidden;
int setpriority$nt(int) hidden;
int stat$nt(const char *, struct stat *) hidden;
int sync$nt(void) hidden;
int symlink$nt(const char *, const char *) hidden;
int sync$nt(void) hidden;
int sysinfo$nt(struct sysinfo *) hidden;
int truncate$nt(const char *, u64) hidden;
int unlink$nt(const char *) hidden;
i64 lseek$nt(int, i64, int) hidden;
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
ssize_t open$nt(const char *, u32, i32) nodiscard hidden;
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
int getrusage$nt(int, struct rusage *) hidden;
int setitimer$nt(int, const struct itimerval *, struct itimerval *) hidden;
int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
int faccessat$nt(int, const char *, int, uint32_t) hidden;
int execve$nt(const char *, char *const[], char *const[]) hidden;
/*───────────────────────────────────────────────────────────────────────────│─╗
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
@@ -266,7 +272,6 @@ int getsetpriority$nt(int, unsigned, int, int (*)(int));
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
bool32 ntsetprivilege(i64, const char16_t *, u32) hidden;
bool32 onntconsoleevent$nt(u32) hidden;
void __winalarm(void *, uint32_t, uint32_t) hidden;
int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
int64_t __winerr(void) nocallback privileged;

View File

@@ -1,23 +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 2020 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/internal.h"
bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
}

View File

@@ -1,7 +1,7 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Copyright 2021 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
@@ -17,7 +17,40 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/ctrlevent.h"
#include "libc/nt/process.h"
#include "libc/sysv/errfuns.h"
bool __isfdkind(int fd, enum FdKind kind) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind == kind;
textwindows int kill$nt(int pid, int sig) {
int target;
uint32_t event;
if (!pid) return raise(sig);
if ((pid > 0 && __isfdkind(pid, kFdProcess)) ||
(pid < 0 && __isfdkind(-pid, kFdProcess))) {
target = GetProcessId(g_fds.p[ABS(pid)].handle);
} else {
target = pid;
}
if (target == GetCurrentProcessId()) {
return raise(sig);
} else {
switch (sig) {
case SIGINT:
event = kNtCtrlCEvent;
case SIGHUP:
event = kNtCtrlCloseEvent;
case SIGQUIT:
event = kNtCtrlBreakEvent;
default:
return einval();
}
if (GenerateConsoleCtrlEvent(event, target)) {
return 0;
} else {
return __winerr();
}
}
}

View File

@@ -19,7 +19,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Sends signal to process.
@@ -39,15 +38,9 @@
* @asyncsignalsafe
*/
int kill(int pid, int sig) {
int me;
if (!IsWindows()) {
return kill$sysv(pid, sig, 1);
} else {
me = getpid();
if (!pid || pid == me || pid == -me) {
return raise(sig);
} else {
return enosys();
}
return kill$nt(pid, sig);
}
}

View File

@@ -84,7 +84,8 @@ textwindows int ntspawn(
mkntenvblock(block->envvars, envp) != -1) {
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,
dwCreationFlags | kNtCreateUnicodeEnvironment,
dwCreationFlags | kNtCreateNewProcessGroup |
kNtCreateUnicodeEnvironment,
block->envvars, opt_lpCurrentDirectory, lpStartupInfo,
opt_out_lpProcessInformation)) {
rc = 0;

View File

@@ -23,7 +23,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
textwindows bool32 onntconsoleevent(uint32_t CtrlType) {
textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
int sig;
siginfo_t info;
switch (CtrlType) {

View File

@@ -20,7 +20,7 @@
.source __FILE__
.init.start 300,_init_onntconsoleevent
ezlea onntconsoleevent$nt,cx
ezlea __onntconsoleevent$nt,cx
pushpop 1,%rdx
ntcall __imp_SetConsoleCtrlHandler
.init.end 300,_init_onntconsoleevent,globl,hidden

View File

@@ -45,10 +45,12 @@ static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
(flags & 0xf000000f) |
(/* this is needed if we mmap(rwx+cow)
nt is choosy about open() access */
(flags & O_ACCMODE) == O_RDONLY
? kNtGenericExecute | kNtFileGenericRead
: kNtGenericExecute | kNtFileGenericRead |
kNtFileGenericWrite),
(flags & O_APPEND)
? kNtFileAppendData
: (flags & O_ACCMODE) == O_RDONLY
? kNtGenericExecute | kNtFileGenericRead
: kNtGenericExecute | kNtFileGenericRead |
kNtFileGenericWrite),
(flags & O_EXCL)
? kNtFileShareExclusive
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,

View File

@@ -25,15 +25,18 @@
/**
* Waits for signal.
*
* @return should be -1 w/ EINTR
* This suspends execution until an unmasked signal is delivered
* and its callback function has been called. It's a better idea
* to use sigsuspend() w/ sigprocmask() to avoid race conditions
*
* @return should always be -1 w/ EINTR
* @see sigsuspend()
*/
int pause(void) {
int rc, olderr;
sigset_t oldmask;
olderr = errno;
rc = pause$sysv();
if (rc == -1 && errno == ENOSYS) {
if ((rc = pause$sysv()) == -1 && errno == ENOSYS) {
errno = olderr;
if (sigprocmask(SIG_BLOCK, NULL, &oldmask) == -1) return -1;
rc = sigsuspend(&oldmask);

View File

@@ -23,7 +23,7 @@
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/sig.h"
static uint32_t GetCtrlEvent(int sig) {
static textwindows uint32_t GetCtrlEvent(int sig) {
switch (sig) {
case SIGINT:
return kNtCtrlCEvent;

View File

@@ -34,11 +34,12 @@
* @param oldset will receive the old mask (optional) and can't overlap
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
* @vforksafe
*/
int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
if (!IsWindows()) {
return sigprocmask$sysv(how, opt_set, opt_out_oldset, 8);
} else {
return enosys(); /* TODO(jart): Implement me! */
return 0; /* TODO(jart): Implement me! */
}
}

View File

@@ -25,14 +25,14 @@
/**
* Blocks until SIG ∉ MASK is delivered to process.
*
* @param mask is a bitset of signals to block temporarily
* @param ignore is a bitset of signals to block temporarily
* @return -1 w/ EINTR
* @asyncsignalsafe
*/
int sigsuspend(const sigset_t *mask) {
if (!mask) return efault();
int sigsuspend(const sigset_t *ignore) {
if (!ignore) return efault();
if (!IsWindows()) {
return sigsuspend$sysv(mask, 8);
return sigsuspend$sysv(ignore, 8);
} else {
return enosys(); /* TODO(jart): Implement me! */
}

View File

@@ -20,7 +20,7 @@
.text.windows
.source __FILE__
onntconsoleevent$nt:
ezlea onntconsoleevent,ax
__onntconsoleevent$nt:
ezlea __onntconsoleevent,ax
jmp __nt2sysv
.endfn onntconsoleevent$nt,globl,hidden
.endfn __onntconsoleevent$nt,globl,hidden

View File

@@ -17,9 +17,6 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/wait4.h"
#include "libc/dce.h"
/**
* Waits for status to change on process.
@@ -33,9 +30,5 @@
* @asyncsignalsafe
*/
int waitpid(int pid, int *opt_out_wstatus, int options) {
if (!IsWindows()) {
return wait4$sysv(pid, opt_out_wstatus, options, NULL);
} else {
return wait4$nt(pid, opt_out_wstatus, options, NULL);
}
return wait4(pid, opt_out_wstatus, options, NULL);
}

View File

@@ -41,7 +41,7 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
if (WriteFile(fd->handle, iovlen ? iov[0].iov_base : NULL,
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
offset2overlap(opt_offset, &overlap))) {
if (!wrote) assert(SumIovecLen(iov, iovlen) > 0);
if (!wrote) assert(!SumIovecLen(iov, iovlen));
FlushFileBuffers(fd->handle);
return wrote;
} else {