mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-14 06:59:10 +00:00
Work towards improving signals and processes
This commit is contained in:
parent
de703b182c
commit
d7ac16a9ed
96 changed files with 1474 additions and 427 deletions
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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! */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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! */
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue