mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Fix flakes in runitd and popen_test
This commit is contained in:
parent
801224df67
commit
2ebc5781a1
18 changed files with 123 additions and 34 deletions
|
@ -34,17 +34,27 @@
|
|||
#include "libc/thread/tls.h"
|
||||
|
||||
textwindows int _check_interrupts(bool restartable, struct Fd *fd) {
|
||||
int rc;
|
||||
int e, rc;
|
||||
e = errno;
|
||||
if (_weaken(pthread_testcancel_np) &&
|
||||
(rc = _weaken(pthread_testcancel_np)())) {
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
if (_weaken(_check_sigalrm)) _weaken(_check_sigalrm)();
|
||||
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (_weaken(_check_sigchld)) _weaken(_check_sigchld)();
|
||||
if (fd && _weaken(_check_sigwinch)) _weaken(_check_sigwinch)(fd);
|
||||
if (_weaken(_check_sigalrm)) {
|
||||
_weaken(_check_sigalrm)();
|
||||
}
|
||||
if (_weaken(__sig_check) && _weaken(__sig_check)(restartable)) return eintr();
|
||||
if (!__tls_enabled || !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
if (_weaken(_check_sigchld)) {
|
||||
_weaken(_check_sigchld)();
|
||||
}
|
||||
if (fd && _weaken(_check_sigwinch)) {
|
||||
_weaken(_check_sigwinch)(fd);
|
||||
}
|
||||
}
|
||||
if (_weaken(__sig_check) && _weaken(__sig_check)(restartable)) {
|
||||
return eintr();
|
||||
}
|
||||
errno = e;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -479,6 +479,15 @@ static int __sigaction(int sig, const struct sigaction *act,
|
|||
* frequently calling sigprocmask() out of an abundance of caution, will
|
||||
* no longer need to pay its outrageous cost.
|
||||
*
|
||||
* Signal handlers should avoid clobbering global variables like `errno`
|
||||
* because most signals are asynchronous, i.e. the signal handler might
|
||||
* be called at any assembly instruction. If something like a `SIGCHLD`
|
||||
* handler doesn't save / restore the `errno` global when calling wait,
|
||||
* then any i/o logic in the main program that checks `errno` will most
|
||||
* likely break. This is rare in practice, since systems usually design
|
||||
* signals to favor delivery from cancellation points before they block
|
||||
* however that's not guaranteed.
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see xsigaction() for a much better api
|
||||
* @asyncsignalsafe
|
||||
|
|
|
@ -17,12 +17,18 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
||||
__msabi extern typeof(CreateFile) *const __imp_CreateFileW;
|
||||
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
|
||||
__msabi extern typeof(Sleep) *const __imp_Sleep;
|
||||
|
||||
/**
|
||||
* Opens file on the New Technology.
|
||||
|
@ -36,9 +42,16 @@ textwindows int64_t CreateFile(
|
|||
int dwCreationDisposition, uint32_t dwFlagsAndAttributes,
|
||||
int64_t opt_hTemplateFile) {
|
||||
int64_t hHandle;
|
||||
uint32_t micros = 1;
|
||||
TryAgain:
|
||||
hHandle = __imp_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode,
|
||||
opt_lpSecurityAttributes, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, opt_hTemplateFile);
|
||||
if (hHandle == -1 && __imp_GetLastError() == kNtErrorPipeBusy) {
|
||||
if (micros >= 1024) __imp_Sleep(micros / 1024);
|
||||
if (micros / 1024 < __SIG_POLLING_INTERVAL_MS) micros <<= 1;
|
||||
goto TryAgain;
|
||||
}
|
||||
if (hHandle == -1) __winerr();
|
||||
NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName,
|
||||
DescribeNtFileAccessFlags(dwDesiredAccess),
|
||||
|
|
|
@ -16,14 +16,20 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/ipc.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
||||
__msabi extern typeof(CreateNamedPipe) *const __imp_CreateNamedPipeW;
|
||||
__msabi extern typeof(GetLastError) *const __imp_GetLastError;
|
||||
__msabi extern typeof(Sleep) *const __imp_Sleep;
|
||||
|
||||
/**
|
||||
* Creates pipe.
|
||||
|
@ -37,9 +43,16 @@ textwindows int64_t CreateNamedPipe(
|
|||
uint32_t nDefaultTimeOutMs,
|
||||
const struct NtSecurityAttributes *opt_lpSecurityAttributes) {
|
||||
int64_t hServer;
|
||||
uint32_t micros = 1;
|
||||
TryAgain:
|
||||
hServer = __imp_CreateNamedPipeW(lpName, dwOpenMode, dwPipeMode,
|
||||
nMaxInstances, nOutBufferSize, nInBufferSize,
|
||||
nDefaultTimeOutMs, opt_lpSecurityAttributes);
|
||||
if (hServer == -1 && __imp_GetLastError() == kNtErrorPipeBusy) {
|
||||
if (micros >= 1024) __imp_Sleep(micros / 1024);
|
||||
if (micros / 1024 < __SIG_POLLING_INTERVAL_MS) micros <<= 1;
|
||||
goto TryAgain;
|
||||
}
|
||||
if (hServer == -1) __winerr();
|
||||
NTTRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m",
|
||||
lpName, DescribeNtPipeOpenFlags(dwOpenMode),
|
||||
|
|
|
@ -131,10 +131,14 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
|
|||
__mmi_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
|
||||
|
||||
// record system provided stack to memory manager
|
||||
// todo: how do we get the real size of the stack
|
||||
// if `y` is too small mmap will destroy it
|
||||
// if `x` is too high, backtraces will fail
|
||||
uintptr_t t = (uintptr_t)__builtin_frame_address(0);
|
||||
uintptr_t s = (uintptr_t)sp;
|
||||
uintptr_t z = GetStackSize() << 1;
|
||||
_mmi.i = 1;
|
||||
_mmi.p->x = (s & -z) >> 16;
|
||||
_mmi.p->x = MIN((s & -z) >> 16, (t & -z) >> 16);
|
||||
_mmi.p->y = MIN(((s & -z) + (z - 1)) >> 16, INT_MAX);
|
||||
_mmi.p->size = z;
|
||||
_mmi.p->prot = PROT_READ | PROT_WRITE;
|
||||
|
|
|
@ -48,12 +48,14 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/signals.h"
|
||||
#include "libc/nt/struct/ntexceptionpointers.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
@ -108,20 +110,36 @@ static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n,
|
|||
|
||||
static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) {
|
||||
bool ok;
|
||||
// kprintf("WriteAll(%ld, %p, %zu);\n", h, buf, n);
|
||||
ok = ForkIo2(h, buf, n, WriteFile, "WriteFile", false);
|
||||
#ifndef NDEBUG
|
||||
if (ok) ok = ForkIo2(h, &n, sizeof(n), WriteFile, "WriteFile", false);
|
||||
#endif
|
||||
#ifdef SYSDEBUG
|
||||
if (!ok) {
|
||||
kprintf("failed to write %zu bytes to forked child: %d\n", n,
|
||||
GetLastError());
|
||||
}
|
||||
#endif
|
||||
// Sleep(10);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
|
||||
// kprintf("ReadOrDie(%ld, %p, %zu);\n", h, buf, n);
|
||||
if (!ForkIo2(h, buf, n, ReadFile, "ReadFile", true)) {
|
||||
AbortFork("ReadFile");
|
||||
AbortFork("ReadFile1");
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
size_t got;
|
||||
if (!ForkIo2(h, &got, sizeof(got), ReadFile, "ReadFile", true)) {
|
||||
AbortFork("ReadFile2");
|
||||
}
|
||||
if (got != n) {
|
||||
AbortFork("ReadFile_SIZE_CHECK");
|
||||
}
|
||||
#endif
|
||||
// Sleep(10);
|
||||
}
|
||||
|
||||
static textwindows int64_t MapOrDie(uint32_t prot, uint64_t size) {
|
||||
|
@ -276,6 +294,7 @@ textwindows void WinMainForked(void) {
|
|||
|
||||
textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
||||
jmp_buf jb;
|
||||
uint32_t op;
|
||||
uint32_t oldprot;
|
||||
char ok, threaded;
|
||||
char **args, **args2;
|
||||
|
@ -290,12 +309,10 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
tib = __tls_enabled ? __get_tls() : 0;
|
||||
if (!setjmp(jb)) {
|
||||
pid = untrackpid = __reservefd_unlocked(-1);
|
||||
reader = CreateNamedPipe(CreatePipeName(pipename),
|
||||
kNtPipeAccessInbound | kNtFileFlagOverlapped,
|
||||
kNtPipeTypeMessage | kNtPipeReadmodeMessage, 1,
|
||||
65536, 65536, 0, &kNtIsInheritable);
|
||||
writer = CreateFile(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting,
|
||||
kNtFileFlagOverlapped, 0);
|
||||
reader = CreateNamedPipe(CreatePipeName(pipename), kNtPipeAccessInbound,
|
||||
kNtPipeTypeByte | kNtPipeReadmodeByte, 1, PIPE_BUF,
|
||||
PIPE_BUF, 0, &kNtIsInheritable);
|
||||
writer = CreateFile(pipename, kNtGenericWrite, 0, 0, kNtOpenExisting, 0, 0);
|
||||
if (pid != -1 && reader != -1 && writer != -1) {
|
||||
p = stpcpy(forkvar, "_FORK=");
|
||||
p = FormatUint64(p, reader);
|
||||
|
@ -331,7 +348,6 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
}
|
||||
for (i = 0; i < _mmi.i && ok; ++i) {
|
||||
if ((_mmi.p[i].flags & MAP_TYPE) != MAP_SHARED) {
|
||||
uint32_t op;
|
||||
char *p = (char *)((uint64_t)_mmi.p[i].x << 16);
|
||||
// XXX: forking destroys thread guard pages currently
|
||||
VirtualProtect(
|
||||
|
|
|
@ -464,6 +464,8 @@ dontasan textstartup void __printargs(const char *prologue) {
|
|||
PRINT(" - stderr");
|
||||
}
|
||||
kprintf(prologue);
|
||||
errno = 0;
|
||||
kprintf(" isatty = %d% m\n", isatty(i));
|
||||
if (!tcgetwinsize(i, &ws)) {
|
||||
kprintf(" ws_row = %d\n", ws.ws_row);
|
||||
kprintf(" ws_col = %d\n", ws.ws_col);
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
||||
__msabi extern typeof(__sys_bind_nt) *const __imp_bind;
|
||||
|
||||
textwindows int sys_bind_nt(struct Fd *fd, const void *addr,
|
||||
uint32_t addrsize) {
|
||||
unassert(fd->kind == kFdSocket);
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
||||
__msabi extern typeof(__sys_closesocket_nt) *const __imp_closesocket;
|
||||
|
||||
/**
|
||||
* Closes socket on Windows.
|
||||
*
|
||||
|
@ -30,7 +33,7 @@ textwindows int sys_closesocket_nt(struct Fd *fd) {
|
|||
struct SockFd *sockfd;
|
||||
sockfd = (struct SockFd *)fd->extra;
|
||||
free(sockfd);
|
||||
int rc = __sys_closesocket_nt(fd->handle);
|
||||
int rc = __imp_closesocket(fd->handle);
|
||||
if (rc != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -19,13 +19,12 @@
|
|||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows struct SockFd *_dupsockfd(struct SockFd *sockfd) {
|
||||
struct SockFd *newsf;
|
||||
if ((newsf = calloc(1, sizeof(struct SockFd)))) {
|
||||
newsf->family = sockfd->family;
|
||||
newsf->type = sockfd->type;
|
||||
newsf->protocol = sockfd->protocol;
|
||||
if ((newsf = malloc(sizeof(struct SockFd)))) {
|
||||
memcpy(newsf, sockfd, sizeof(*sockfd));
|
||||
}
|
||||
return newsf;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/nt/struct/linger.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
@ -29,6 +30,8 @@
|
|||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
__msabi extern typeof(__sys_getsockopt_nt) *const __imp_getsockopt;
|
||||
|
||||
textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
|
||||
void *out_opt_optval,
|
||||
uint32_t *inout_optlen) {
|
||||
|
@ -63,7 +66,7 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
}
|
||||
|
||||
// TODO(jart): Use WSAIoctl?
|
||||
if (__sys_getsockopt_nt(fd->handle, level, optname, out_opt_optval,
|
||||
if (__imp_getsockopt(fd->handle, level, optname, out_opt_optval,
|
||||
inout_optlen) == -1) {
|
||||
return __winsockerr();
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *,
|
|||
size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *, size_t);
|
||||
|
||||
void WinSockInit(void);
|
||||
int64_t __winsockerr(void) nocallback;
|
||||
int64_t __winsockerr(void);
|
||||
int __fixupnewsockfd(int, int);
|
||||
int64_t __winsockblock(int64_t, unsigned, int64_t, uint32_t);
|
||||
struct SockFd *_dupsockfd(struct SockFd *);
|
||||
|
|
|
@ -17,13 +17,16 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
||||
__msabi extern typeof(__sys_listen_nt) *const __imp_listen;
|
||||
|
||||
textwindows int sys_listen_nt(struct Fd *fd, int backlog) {
|
||||
npassert(fd->kind == kFdSocket);
|
||||
if (__sys_listen_nt(fd->handle, backlog) != -1) {
|
||||
if (__imp_listen(fd->handle, backlog) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winsockerr();
|
||||
|
|
|
@ -34,12 +34,15 @@
|
|||
/**
|
||||
* Receives data from network.
|
||||
*
|
||||
* This function blocks unless MSG_DONTWAIT is passed.
|
||||
*
|
||||
* @param fd is the file descriptor returned by socket()
|
||||
* @param buf is where received network data gets copied
|
||||
* @param size is the byte capacity of buf
|
||||
* @param flags can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
* @param flags is a bitmask which may contain any of the following:
|
||||
* - `MSG_DONTWAIT` to force `O_NONBLOCK` behavior for this call
|
||||
* - `MSG_OOB` is broadly supported (untested by cosmo)
|
||||
* - `MSG_PEEK` is broadly supported (untested by cosmo)
|
||||
* - `MSG_WAITALL` is broadly supported (untested by cosmo)
|
||||
* - `MSG_DONTROUTE` is broadly supported (untested by cosmo)
|
||||
* @param opt_out_srcaddr receives the binary ip:port of the data's origin
|
||||
* @param opt_inout_srcaddrsize is srcaddr capacity which gets updated
|
||||
* @return number of bytes received, 0 on remote close, or -1 w/ errno
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/struct/linger.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/struct/linger.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
@ -28,6 +29,8 @@
|
|||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
__msabi extern typeof(__sys_setsockopt_nt) *const __imp_setsockopt;
|
||||
|
||||
textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
|
||||
const void *optval, uint32_t optlen) {
|
||||
int64_t ms, micros;
|
||||
|
@ -70,7 +73,7 @@ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
}
|
||||
}
|
||||
|
||||
if (__sys_setsockopt_nt(fd->handle, level, optname, optval, optlen) != -1) {
|
||||
if (__imp_setsockopt(fd->handle, level, optname, optval, optlen) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winsockerr();
|
||||
|
|
|
@ -40,10 +40,10 @@ static bool setsockopt_polyfill(int *optname) {
|
|||
/**
|
||||
* Modifies socket settings.
|
||||
*
|
||||
* This function is the ultimate rabbit hole. Basic usage:
|
||||
* Basic usage:
|
||||
*
|
||||
* int yes = 1;
|
||||
* setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes));
|
||||
* setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
|
||||
*
|
||||
* @param level can be SOL_SOCKET, SOL_IP, SOL_TCP, etc.
|
||||
* @param optname can be SO_{REUSE{PORT,ADDR},KEEPALIVE,etc.} etc.
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
||||
__msabi extern typeof(__sys_shutdown_nt) *const __imp_shutdown;
|
||||
|
||||
textwindows int sys_shutdown_nt(struct Fd *fd, int how) {
|
||||
if (__sys_shutdown_nt(fd->handle, how) != -1) {
|
||||
if (__imp_shutdown(fd->handle, how) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winsockerr();
|
||||
|
|
|
@ -116,8 +116,9 @@ void OnInterrupt(int sig) {
|
|||
}
|
||||
|
||||
void OnChildTerminated(int sig) {
|
||||
int ws, pid;
|
||||
int e, ws, pid;
|
||||
sigset_t ss, oldss;
|
||||
e = errno; // SIGCHLD can be called asynchronously
|
||||
sigfillset(&ss);
|
||||
sigdelset(&ss, SIGTERM);
|
||||
sigprocmask(SIG_BLOCK, &ss, &oldss);
|
||||
|
@ -140,6 +141,7 @@ void OnChildTerminated(int sig) {
|
|||
}
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &oldss, 0);
|
||||
errno = e;
|
||||
}
|
||||
|
||||
wontreturn void ShowUsage(FILE *f, int rc) {
|
||||
|
|
Loading…
Add table
Reference in a new issue