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 {