Skip to content

Commit a849a63

Browse files
authored
Implement sigpending for sysv and nt (#597)
1 parent 4339d9f commit a849a63

File tree

9 files changed

+186
-3
lines changed

9 files changed

+186
-3
lines changed

libc/calls/sig.internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ int __sig_add(int, int) hidden;
3232
int __sig_mask(int, const sigset_t *, sigset_t *) hidden;
3333
int __sig_raise(int, int) hidden;
3434
void __sig_check_ignore(const int, const unsigned) hidden;
35+
void __sig_pending(sigset_t *) hidden;
3536

3637
COSMOPOLITAN_C_END_
3738
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

libc/calls/sig2.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,25 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
298298
__sig_unlock();
299299
}
300300
}
301+
302+
/**
303+
* Determines the pending signals on New Technology.
304+
*
305+
* @param pending is to hold the pending signals
306+
* @threadsafe
307+
*/
308+
textwindows void __sig_pending(sigset_t *pending) {
309+
struct Signal *cur;
310+
sigemptyset(pending);
311+
if (__sig.queue) {
312+
__sig_lock();
313+
for (cur = __sig.queue; cur; cur = cur->next) {
314+
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
315+
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
316+
} else {
317+
STRACE("%G is ignored", cur->sig);
318+
}
319+
}
320+
__sig_unlock();
321+
}
322+
}

libc/calls/sigpending.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2020 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/calls/sig.internal.h"
20+
#include "libc/calls/strace.internal.h"
21+
#include "libc/calls/struct/sigset.h"
22+
#include "libc/calls/struct/sigset.internal.h"
23+
#include "libc/dce.h"
24+
#include "libc/intrin/asan.internal.h"
25+
#include "libc/intrin/describeflags.internal.h"
26+
#include "libc/sysv/errfuns.h"
27+
28+
/**
29+
* Determines the blocked pending signals
30+
*
31+
* @param pending is where the bitset of pending signals is returned,
32+
* may not be NULL.
33+
* @return -1 w/ EFAULT
34+
* @asyncsignalsafe
35+
*/
36+
int sigpending(sigset_t *pending) {
37+
int rc;
38+
if (IsAsan() && !__asan_is_valid(pending, sizeof(*pending))) {
39+
rc = efault();
40+
} else if (IsLinux() || IsNetbsd() || IsOpenbsd() || IsFreebsd() || IsXnu()) {
41+
rc = sys_sigpending(pending, 8);
42+
// 128 signals on NetBSD and FreeBSD, 64 on Linux, 32 on OpenBSD and XNU.
43+
if (IsOpenbsd()) {
44+
pending->__bits[0] = (unsigned)rc;
45+
rc = 0;
46+
} else if (IsXnu()) {
47+
pending->__bits[0] &= 0xFFFFFFFF;
48+
}
49+
if (IsLinux() || IsOpenbsd() || IsXnu()) {
50+
pending->__bits[1] = 0;
51+
}
52+
} else if (IsWindows()) {
53+
sigemptyset(pending);
54+
__sig_pending(pending);
55+
rc = 0;
56+
} else {
57+
rc = enosys();
58+
}
59+
STRACE("sigpending([%s]) → %d% m", DescribeSigset(rc, pending), rc);
60+
return rc;
61+
}

libc/calls/struct/sigset.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ int sigfillset(sigset_t *) paramsnonnull();
1414
int sigismember(const sigset_t *, int) paramsnonnull() nosideeffect;
1515
int sigprocmask(int, const sigset_t *, sigset_t *);
1616
int sigsuspend(const sigset_t *);
17+
int sigpending(sigset_t *) paramsnonnull() nosideeffect;
1718
int pthread_sigmask(int, const sigset_t *, sigset_t *);
1819

1920
COSMOPOLITAN_C_END_

libc/calls/struct/sigset.internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ int __sys_sigprocmask(int, const struct sigset *, struct sigset *,
99
uint64_t) hidden;
1010
int sys_sigprocmask(int, const struct sigset *, struct sigset *) hidden;
1111
int sys_sigsuspend(const struct sigset *, uint64_t) hidden;
12+
int sys_sigpending(struct sigset *, size_t) hidden;
1213

1314
const char *DescribeSigset(char[128], int, const sigset_t *);
1415
#define DescribeSigset(rc, ss) DescribeSigset(alloca(128), rc, ss)

libc/sysv/calls/sigpending.s

Lines changed: 0 additions & 2 deletions
This file was deleted.

libc/sysv/calls/sys_sigpending.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.include "o/libc/sysv/macros.internal.inc"
2+
.scall sys_sigpending,0x124034157203407f,globl,hidden

libc/sysv/syscalls.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ scall sys_setresuid 0xfff11a137ffff075 globl hidden # polyfilled for xnu
161161
scall sys_setresgid 0xfff11c138ffff077 globl hidden # polyfilled for xnu
162162
scall sys_getresuid 0xfff119168ffff076 globl hidden # semantics aren't well-defined
163163
scall sys_getresgid 0xfff11b169ffff078 globl hidden # semantics aren't well-defined
164-
scall sigpending 0x124034034203407f globl # a.k.a. rt_sigpending on linux
164+
scall sys_sigpending 0x124034157203407f globl hidden # a.k.a. rt_sigpending on linux
165165
scall sys_sigsuspend 0x12606f155206f082 globl hidden # a.k.a. rt_sigsuspend on Linux; openbsd:byvalue, sigsuspend_nocancel on XNU
166166
scall sys_sigaltstack 0x1191200352035083 globl hidden
167167
scall sys_mknod 0x1c200e00e200e085 globl hidden

test/libc/calls/sigpending_test.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2022 Gavin Arthur Hayes │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/calls/calls.h"
20+
#include "libc/calls/struct/sigaction.h"
21+
#include "libc/calls/struct/siginfo.h"
22+
#include "libc/calls/struct/sigset.h"
23+
#include "libc/sysv/consts/sa.h"
24+
#include "libc/sysv/consts/sig.h"
25+
#include "libc/testlib/testlib.h"
26+
27+
static unsigned OnSignalCnt = 0;
28+
void OnSignal(int sig, siginfo_t *si, void *ctx) {
29+
OnSignalCnt++;
30+
EXPECT_EQ(SIGUSR1, sig);
31+
}
32+
33+
TEST(sigpending, test) {
34+
sigset_t pending;
35+
sigfillset(&pending);
36+
EXPECT_EQ(0, sigpending(&pending));
37+
unsigned cnt = 0;
38+
for (unsigned sig = 1; sig < NSIG; sig++) {
39+
if (sigismember(&pending, sig)) {
40+
cnt++;
41+
}
42+
}
43+
EXPECT_EQ(0, cnt);
44+
45+
struct sigaction sa = {.sa_sigaction = OnSignal, .sa_flags = SA_SIGINFO};
46+
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
47+
sigset_t blocked;
48+
sigemptyset(&blocked);
49+
sigaddset(&blocked, SIGUSR1);
50+
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &blocked, NULL));
51+
ASSERT_EQ(0, raise(SIGUSR1));
52+
sigfillset(&pending);
53+
EXPECT_EQ(0, sigpending(&pending));
54+
cnt = 0;
55+
for (unsigned sig = 1; sig < NSIG; sig++) {
56+
if (sigismember(&pending, sig)) {
57+
cnt++;
58+
}
59+
}
60+
EXPECT_EQ(1, cnt);
61+
EXPECT_EQ(1, sigismember(&pending, SIGUSR1));
62+
63+
ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_IGN));
64+
sigemptyset(&pending);
65+
EXPECT_EQ(0, sigpending(&pending));
66+
cnt = 0;
67+
for (unsigned sig = 1; sig < NSIG; sig++) {
68+
if (sigismember(&pending, sig)) {
69+
cnt++;
70+
}
71+
}
72+
EXPECT_EQ(0, cnt);
73+
74+
ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
75+
ASSERT_EQ(0, raise(SIGUSR1));
76+
EXPECT_EQ(0, sigpending(&pending));
77+
cnt = 0;
78+
for (unsigned sig = 1; sig < NSIG; sig++) {
79+
if (sigismember(&pending, sig)) {
80+
cnt++;
81+
}
82+
}
83+
EXPECT_EQ(1, cnt);
84+
EXPECT_EQ(1, sigismember(&pending, SIGUSR1));
85+
86+
sigemptyset(&blocked);
87+
ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &blocked, NULL));
88+
EXPECT_EQ(0, sigpending(&pending));
89+
cnt = 0;
90+
for (unsigned sig = 1; sig < NSIG; sig++) {
91+
if (sigismember(&pending, sig)) {
92+
cnt++;
93+
}
94+
}
95+
EXPECT_EQ(0, cnt);
96+
EXPECT_EQ(1, OnSignalCnt);
97+
}

0 commit comments

Comments
 (0)