mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Implement sigpending for sysv and nt (#597)
This commit is contained in:
parent
4339d9f15e
commit
a849a63771
9 changed files with 186 additions and 3 deletions
|
@ -32,6 +32,7 @@ int __sig_add(int, int) hidden;
|
|||
int __sig_mask(int, const sigset_t *, sigset_t *) hidden;
|
||||
int __sig_raise(int, int) hidden;
|
||||
void __sig_check_ignore(const int, const unsigned) hidden;
|
||||
void __sig_pending(sigset_t *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -298,3 +298,25 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
|||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *cur;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (cur = __sig.queue; cur; cur = cur->next) {
|
||||
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
|
||||
} else {
|
||||
STRACE("%G is ignored", cur->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
|
|
61
libc/calls/sigpending.c
Normal file
61
libc/calls/sigpending.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*-*- 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/sig.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Determines the blocked pending signals
|
||||
*
|
||||
* @param pending is where the bitset of pending signals is returned,
|
||||
* may not be NULL.
|
||||
* @return -1 w/ EFAULT
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigpending(sigset_t *pending) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(pending, sizeof(*pending))) {
|
||||
rc = efault();
|
||||
} else if (IsLinux() || IsNetbsd() || IsOpenbsd() || IsFreebsd() || IsXnu()) {
|
||||
rc = sys_sigpending(pending, 8);
|
||||
// 128 signals on NetBSD and FreeBSD, 64 on Linux, 32 on OpenBSD and XNU.
|
||||
if (IsOpenbsd()) {
|
||||
pending->__bits[0] = (unsigned)rc;
|
||||
rc = 0;
|
||||
} else if (IsXnu()) {
|
||||
pending->__bits[0] &= 0xFFFFFFFF;
|
||||
}
|
||||
if (IsLinux() || IsOpenbsd() || IsXnu()) {
|
||||
pending->__bits[1] = 0;
|
||||
}
|
||||
} else if (IsWindows()) {
|
||||
sigemptyset(pending);
|
||||
__sig_pending(pending);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("sigpending([%s]) → %d% m", DescribeSigset(rc, pending), rc);
|
||||
return rc;
|
||||
}
|
|
@ -14,6 +14,7 @@ int sigfillset(sigset_t *) paramsnonnull();
|
|||
int sigismember(const sigset_t *, int) paramsnonnull() nosideeffect;
|
||||
int sigprocmask(int, const sigset_t *, sigset_t *);
|
||||
int sigsuspend(const sigset_t *);
|
||||
int sigpending(sigset_t *) paramsnonnull() nosideeffect;
|
||||
int pthread_sigmask(int, const sigset_t *, sigset_t *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -9,6 +9,7 @@ int __sys_sigprocmask(int, const struct sigset *, struct sigset *,
|
|||
uint64_t) hidden;
|
||||
int sys_sigprocmask(int, const struct sigset *, struct sigset *) hidden;
|
||||
int sys_sigsuspend(const struct sigset *, uint64_t) hidden;
|
||||
int sys_sigpending(struct sigset *, size_t) hidden;
|
||||
|
||||
const char *DescribeSigset(char[128], int, const sigset_t *);
|
||||
#define DescribeSigset(rc, ss) DescribeSigset(alloca(128), rc, ss)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sigpending,0x124034034203407f,globl
|
2
libc/sysv/calls/sys_sigpending.s
Normal file
2
libc/sysv/calls/sys_sigpending.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_sigpending,0x124034157203407f,globl,hidden
|
|
@ -161,7 +161,7 @@ scall sys_setresuid 0xfff11a137ffff075 globl hidden # polyfilled for xnu
|
|||
scall sys_setresgid 0xfff11c138ffff077 globl hidden # polyfilled for xnu
|
||||
scall sys_getresuid 0xfff119168ffff076 globl hidden # semantics aren't well-defined
|
||||
scall sys_getresgid 0xfff11b169ffff078 globl hidden # semantics aren't well-defined
|
||||
scall sigpending 0x124034034203407f globl # a.k.a. rt_sigpending on linux
|
||||
scall sys_sigpending 0x124034157203407f globl hidden # a.k.a. rt_sigpending on linux
|
||||
scall sys_sigsuspend 0x12606f155206f082 globl hidden # a.k.a. rt_sigsuspend on Linux; openbsd:byvalue, sigsuspend_nocancel on XNU
|
||||
scall sys_sigaltstack 0x1191200352035083 globl hidden
|
||||
scall sys_mknod 0x1c200e00e200e085 globl hidden
|
||||
|
|
97
test/libc/calls/sigpending_test.c
Normal file
97
test/libc/calls/sigpending_test.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*-*- 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 2022 Gavin Arthur Hayes │
|
||||
│ │
|
||||
│ 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/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
static unsigned OnSignalCnt = 0;
|
||||
void OnSignal(int sig, siginfo_t *si, void *ctx) {
|
||||
OnSignalCnt++;
|
||||
EXPECT_EQ(SIGUSR1, sig);
|
||||
}
|
||||
|
||||
TEST(sigpending, test) {
|
||||
sigset_t pending;
|
||||
sigfillset(&pending);
|
||||
EXPECT_EQ(0, sigpending(&pending));
|
||||
unsigned cnt = 0;
|
||||
for (unsigned sig = 1; sig < NSIG; sig++) {
|
||||
if (sigismember(&pending, sig)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(0, cnt);
|
||||
|
||||
struct sigaction sa = {.sa_sigaction = OnSignal, .sa_flags = SA_SIGINFO};
|
||||
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
|
||||
sigset_t blocked;
|
||||
sigemptyset(&blocked);
|
||||
sigaddset(&blocked, SIGUSR1);
|
||||
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &blocked, NULL));
|
||||
ASSERT_EQ(0, raise(SIGUSR1));
|
||||
sigfillset(&pending);
|
||||
EXPECT_EQ(0, sigpending(&pending));
|
||||
cnt = 0;
|
||||
for (unsigned sig = 1; sig < NSIG; sig++) {
|
||||
if (sigismember(&pending, sig)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(1, cnt);
|
||||
EXPECT_EQ(1, sigismember(&pending, SIGUSR1));
|
||||
|
||||
ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_IGN));
|
||||
sigemptyset(&pending);
|
||||
EXPECT_EQ(0, sigpending(&pending));
|
||||
cnt = 0;
|
||||
for (unsigned sig = 1; sig < NSIG; sig++) {
|
||||
if (sigismember(&pending, sig)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(0, cnt);
|
||||
|
||||
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
|
||||
ASSERT_EQ(0, raise(SIGUSR1));
|
||||
EXPECT_EQ(0, sigpending(&pending));
|
||||
cnt = 0;
|
||||
for (unsigned sig = 1; sig < NSIG; sig++) {
|
||||
if (sigismember(&pending, sig)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(1, cnt);
|
||||
EXPECT_EQ(1, sigismember(&pending, SIGUSR1));
|
||||
|
||||
sigemptyset(&blocked);
|
||||
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &blocked, NULL));
|
||||
EXPECT_EQ(0, sigpending(&pending));
|
||||
cnt = 0;
|
||||
for (unsigned sig = 1; sig < NSIG; sig++) {
|
||||
if (sigismember(&pending, sig)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(0, cnt);
|
||||
EXPECT_EQ(1, OnSignalCnt);
|
||||
}
|
Loading…
Add table
Reference in a new issue