aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nptl/pthreadP.h2
-rw-r--r--nptl/pthread_sigmask.c1
-rw-r--r--sysdeps/unix/sysv/linux/sigprocmask.c20
-rw-r--r--sysdeps/unix/sysv/linux/test-errno-linux.c19
4 files changed, 27 insertions, 15 deletions
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 06fb0d74c5..c4e72f57a9 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -482,6 +482,8 @@ extern void __pthread_testcancel (void);
extern int __pthread_clockjoin_ex (pthread_t, void **, clockid_t,
const struct timespec *, bool)
attribute_hidden;
+extern int __pthread_sigmask (int, const sigset_t *, sigset_t *);
+libc_hidden_proto (__pthread_sigmask);
#if IS_IN (libpthread)
diff --git a/nptl/pthread_sigmask.c b/nptl/pthread_sigmask.c
index 035104453f..c6c6e83c08 100644
--- a/nptl/pthread_sigmask.c
+++ b/nptl/pthread_sigmask.c
@@ -46,6 +46,7 @@ __pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask)
? INTERNAL_SYSCALL_ERRNO (result)
: 0);
}
+libc_hidden_def (__pthread_sigmask)
versioned_symbol (libc, __pthread_sigmask, pthread_sigmask, GLIBC_2_32);
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_32)
diff --git a/sysdeps/unix/sysv/linux/sigprocmask.c b/sysdeps/unix/sysv/linux/sigprocmask.c
index eb9e4d5e83..59bf6fd660 100644
--- a/sysdeps/unix/sysv/linux/sigprocmask.c
+++ b/sysdeps/unix/sysv/linux/sigprocmask.c
@@ -22,21 +22,11 @@
int
__sigprocmask (int how, const sigset_t *set, sigset_t *oset)
{
- sigset_t local_newmask;
-
- /* The only thing we have to make sure here is that SIGCANCEL and
- SIGSETXID are not blocked. */
- if (set != NULL
- && __glibc_unlikely (__sigismember (set, SIGCANCEL)
- || __glibc_unlikely (__sigismember (set, SIGSETXID))))
- {
- local_newmask = *set;
- __sigdelset (&local_newmask, SIGCANCEL);
- __sigdelset (&local_newmask, SIGSETXID);
- set = &local_newmask;
- }
-
- return INLINE_SYSCALL_CALL (rt_sigprocmask, how, set, oset, _NSIG / 8);
+ int result = __pthread_sigmask (how, set, oset);
+ if (result == 0)
+ return 0;
+ __set_errno (result);
+ return -1;
}
libc_hidden_def (__sigprocmask)
weak_alias (__sigprocmask, sigprocmask)
diff --git a/sysdeps/unix/sysv/linux/test-errno-linux.c b/sysdeps/unix/sysv/linux/test-errno-linux.c
index b748f8f2a0..838ccf026f 100644
--- a/sysdeps/unix/sysv/linux/test-errno-linux.c
+++ b/sysdeps/unix/sysv/linux/test-errno-linux.c
@@ -121,6 +121,17 @@ check_error_in_list (int code, int *codes, size_t count)
test_wrp_rv(int, "%d", LIST_FORWARD (experr), syscall, __VA_ARGS__)
static int
+invalid_sigprocmask_how (void)
+{
+ int n = 0;
+ const int how[] = { SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK };
+ for (int i = 0; i < array_length (how); i++)
+ if (how[i] == n)
+ n++;
+ return n;
+}
+
+static int
do_test (void)
{
fd_set rs, ws, es;
@@ -133,10 +144,13 @@ do_test (void)
struct sched_param sch_param;
struct timespec ts;
struct timeval tv;
+ sigset_t sigs;
unsigned char vec[16];
ss.ss_flags = ~SS_DISABLE;
ts.tv_sec = -1;
+ sigemptyset (&sigs);
+
int fails = 0;
fails |= test_wrp (EINVAL, epoll_create, -1);
fails |= test_wrp (EINVAL, epoll_create1, EPOLL_CLOEXEC + 1);
@@ -175,6 +189,11 @@ do_test (void)
fails |= test_wrp (EBADF, sendfile, -1, -1, &off, 0);
fails |= test_wrp (EINVAL, sigaltstack, &ss, NULL);
fails |= test_wrp (ECHILD, wait4, -1, &status, 0, NULL);
+ /* Austin Group issue #1132 states EINVAL should be returned for invalid
+ how argument iff the new set mask is non-null. And Linux follows the
+ standard on this regard. */
+ fails |= test_wrp (EINVAL, sigprocmask, invalid_sigprocmask_how (), &sigs,
+ NULL);
return fails;
}