[3/3] linux: Fix __NSIG_WORDS and add __NSIG_BYTES

Message ID 20200423192625.21629-3-adhemerval.zanella@linaro.org
State Dropped
Headers
Series [1/3] signal: Add signum-{generic,arch}.h |

Commit Message

Adhemerval Zanella April 23, 2020, 7:26 p.m. UTC
  The __NSIG_WORDS value is based on minimum number of words to hold
the maximum number of signal supported by the architecture.  Maximum
number of signals non multiple of word is rounded up.

This patch also adds __NSIG_BYTES, which is the number of bytes
required to represent the support number of signals.  It is used on
syscall which takes a sigset_t.

Checked on x86_64-linux-gnu and i686-linux-gnu.
---
 include/signal.h                           |  2 ++
 nptl/nptl-init.c                           |  2 +-
 nptl/pthread_create.c                      |  2 +-
 nptl/pthread_sigmask.c                     |  2 +-
 sysdeps/unix/sysv/linux/aio_misc.h         |  9 ++++++---
 sysdeps/unix/sysv/linux/epoll_pwait.c      |  2 +-
 sysdeps/unix/sysv/linux/internal-signals.h | 10 +++++-----
 sysdeps/unix/sysv/linux/ppoll.c            |  7 ++++---
 sysdeps/unix/sysv/linux/pselect.c          |  2 +-
 sysdeps/unix/sysv/linux/sigaction.c        |  3 ++-
 sysdeps/unix/sysv/linux/signalfd.c         |  2 +-
 sysdeps/unix/sysv/linux/sigpending.c       |  2 +-
 sysdeps/unix/sysv/linux/sigsetops.h        | 18 +++++++++++++-----
 sysdeps/unix/sysv/linux/sigsuspend.c       |  2 +-
 sysdeps/unix/sysv/linux/sigtimedwait.c     |  3 ++-
 sysdeps/unix/sysv/linux/x86/setjmpP.h      |  5 ++---
 16 files changed, 44 insertions(+), 29 deletions(-)
  

Patch

diff --git a/include/signal.h b/include/signal.h
index 293258ad65..229b1eb352 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -2,6 +2,8 @@ 
 # include <signal/signal.h>
 
 # ifndef _ISOMAC
+#  include <sigsetops.h>
+
 libc_hidden_proto (sigemptyset)
 libc_hidden_proto (sigfillset)
 libc_hidden_proto (sigaddset)
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index 96b1444a01..ed450a09fd 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -281,7 +281,7 @@  __pthread_initialize_minimal_internal (void)
   __sigaddset (&sa.sa_mask, SIGCANCEL);
   __sigaddset (&sa.sa_mask, SIGSETXID);
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &sa.sa_mask,
-			 NULL, _NSIG / 8);
+			 NULL, __NSIG_BYTES);
 
   /* Get the size of the static and alignment requirements for the TLS
      block.  */
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 7c752d0f99..479675e6a1 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -408,7 +408,7 @@  START_THREAD_DEFN
       __sigemptyset (&mask);
       __sigaddset (&mask, SIGCANCEL);
       INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &mask,
-			     NULL, _NSIG / 8);
+			     NULL, __NSIG_BYTES);
     }
 
   /* This is where the try/finally block should be created.  For
diff --git a/nptl/pthread_sigmask.c b/nptl/pthread_sigmask.c
index d266d296c5..7b65ae1f27 100644
--- a/nptl/pthread_sigmask.c
+++ b/nptl/pthread_sigmask.c
@@ -39,7 +39,7 @@  __pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask)
 
   /* We know that realtime signals are available if NPTL is used.  */
   int result = INTERNAL_SYSCALL_CALL (rt_sigprocmask, how, newmask,
-				      oldmask, _NSIG / 8);
+				      oldmask, __NSIG_BYTES);
 
   return (INTERNAL_SYSCALL_ERROR_P (result)
 	  ? INTERNAL_SYSCALL_ERRNO (result)
diff --git a/sysdeps/unix/sysv/linux/aio_misc.h b/sysdeps/unix/sysv/linux/aio_misc.h
index 30c3cd778e..e31ca8edbe 100644
--- a/sysdeps/unix/sysv/linux/aio_misc.h
+++ b/sysdeps/unix/sysv/linux/aio_misc.h
@@ -31,7 +31,8 @@  __aio_start_notify_thread (void)
 {
   sigset_t ss;
   sigemptyset (&ss);
-  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, NULL, _NSIG / 8);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, NULL,
+			 __NSIG_BYTES);
 }
 
 extern inline int
@@ -52,12 +53,14 @@  __aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
   sigset_t ss;
   sigset_t oss;
   sigfillset (&ss);
-  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, &oss, _NSIG / 8);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, &oss,
+			 __NSIG_BYTES);
 
   int ret = pthread_create (threadp, &attr, tf, arg);
 
   /* Restore the signal mask.  */
-  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &oss, NULL, _NSIG / 8);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &oss, NULL,
+			 __NSIG_BYTES);
 
   (void) pthread_attr_destroy (&attr);
   return ret;
diff --git a/sysdeps/unix/sysv/linux/epoll_pwait.c b/sysdeps/unix/sysv/linux/epoll_pwait.c
index 66f04482c7..af6d0fd713 100644
--- a/sysdeps/unix/sysv/linux/epoll_pwait.c
+++ b/sysdeps/unix/sysv/linux/epoll_pwait.c
@@ -38,6 +38,6 @@  int epoll_pwait (int epfd, struct epoll_event *events,
 		 const sigset_t *set)
 {
   return SYSCALL_CANCEL (epoll_pwait, epfd, events, maxevents,
-			 timeout, set, _NSIG / 8);
+			 timeout, set, __NSIG_BYTES);
 }
 libc_hidden_def (epoll_pwait)
diff --git a/sysdeps/unix/sysv/linux/internal-signals.h b/sysdeps/unix/sysv/linux/internal-signals.h
index 3fbd4807d1..35f2de04c5 100644
--- a/sysdeps/unix/sysv/linux/internal-signals.h
+++ b/sysdeps/unix/sysv/linux/internal-signals.h
@@ -68,7 +68,7 @@  static inline void
 __libc_signal_block_all (sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &sigall_set, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Block all application signals (excluding internal glibc ones).  */
@@ -78,7 +78,7 @@  __libc_signal_block_app (sigset_t *set)
   sigset_t allset = sigall_set;
   __clear_internal_signals (&allset);
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &allset, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Block only SIGTIMER and return the previous set on SET.  */
@@ -86,7 +86,7 @@  static inline void
 __libc_signal_block_sigtimer (sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &sigtimer_set, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Unblock only SIGTIMER and return the previous set on SET.  */
@@ -94,7 +94,7 @@  static inline void
 __libc_signal_unblock_sigtimer (sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &sigtimer_set, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Restore current process signal mask.  */
@@ -102,7 +102,7 @@  static inline void
 __libc_signal_restore_set (const sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, set, NULL,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Used to communicate with signal handler.  */
diff --git a/sysdeps/unix/sysv/linux/ppoll.c b/sysdeps/unix/sysv/linux/ppoll.c
index 4ffb23710e..0f15636cce 100644
--- a/sysdeps/unix/sysv/linux/ppoll.c
+++ b/sysdeps/unix/sysv/linux/ppoll.c
@@ -41,11 +41,12 @@  __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout,
 # ifndef __NR_ppoll_time64
 #  define __NR_ppoll_time64 __NR_ppoll
 # endif
-  return SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask, _NSIG / 8);
+  return SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask,
+			 __NSIG_BYTES);
 #else
 # ifdef __NR_ppoll_time64
   int ret = SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask,
-                            _NSIG / 8);
+                            __NSIG_BYTES);
   if (ret >= 0 || errno != ENOSYS)
     return ret;
 # endif
@@ -62,7 +63,7 @@  __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout,
     }
 
   return SYSCALL_CANCEL (ppoll, fds, nfds, timeout ? &ts32 : NULL, sigmask,
-                         _NSIG / 8);
+                         __NSIG_BYTES);
 #endif
 }
 
diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c
index d7c6ff8fdb..304db03338 100644
--- a/sysdeps/unix/sysv/linux/pselect.c
+++ b/sysdeps/unix/sysv/linux/pselect.c
@@ -43,7 +43,7 @@  __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
   } data;
 
   data.ss = (__syscall_ulong_t) (uintptr_t) sigmask;
-  data.ss_len = _NSIG / 8;
+  data.ss_len = __NSIG_BYTES;
 
   return SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds,
                          timeout, &data);
diff --git a/sysdeps/unix/sysv/linux/sigaction.c b/sysdeps/unix/sysv/linux/sigaction.c
index 4e6d11a6ae..f27349d552 100644
--- a/sysdeps/unix/sysv/linux/sigaction.c
+++ b/sysdeps/unix/sysv/linux/sigaction.c
@@ -57,7 +57,8 @@  __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
      real size of the user-level sigset_t.  */
   result = INLINE_SYSCALL_CALL (rt_sigaction, sig,
 				act ? &kact : NULL,
-				oact ? &koact : NULL, STUB (act, _NSIG / 8));
+				oact ? &koact : NULL, STUB (act,
+							    __NSIG_BYTES));
 
   if (oact && result >= 0)
     {
diff --git a/sysdeps/unix/sysv/linux/signalfd.c b/sysdeps/unix/sysv/linux/signalfd.c
index 64d7bccba9..71d91fdde5 100644
--- a/sysdeps/unix/sysv/linux/signalfd.c
+++ b/sysdeps/unix/sysv/linux/signalfd.c
@@ -24,5 +24,5 @@ 
 int
 signalfd (int fd, const sigset_t *mask, int flags)
 {
-  return INLINE_SYSCALL (signalfd4, 4, fd, mask, _NSIG / 8, flags);
+  return INLINE_SYSCALL (signalfd4, 4, fd, mask, __NSIG_BYTES, flags);
 }
diff --git a/sysdeps/unix/sysv/linux/sigpending.c b/sysdeps/unix/sysv/linux/sigpending.c
index 458a3cf99e..8898fe8b34 100644
--- a/sysdeps/unix/sysv/linux/sigpending.c
+++ b/sysdeps/unix/sysv/linux/sigpending.c
@@ -24,5 +24,5 @@ 
 int
 sigpending (sigset_t *set)
 {
-  return INLINE_SYSCALL (rt_sigpending, 2, set, _NSIG / 8);
+  return INLINE_SYSCALL_CALL (rt_sigpending, set, __NSIG_BYTES);
 }
diff --git a/sysdeps/unix/sysv/linux/sigsetops.h b/sysdeps/unix/sysv/linux/sigsetops.h
index db8f378cf0..3f29ead009 100644
--- a/sysdeps/unix/sysv/linux/sigsetops.h
+++ b/sysdeps/unix/sysv/linux/sigsetops.h
@@ -20,23 +20,31 @@ 
 #define _SIGSETOPS_H 1
 
 #include <signal.h>
+#include <limits.h>
+#include <libc-pointer-arith.h>
 
 /* Return a mask that includes the bit for SIG only.  */
-# define __sigmask(sig) \
-  (((unsigned long int) 1) << (((sig) - 1) % (8 * sizeof (unsigned long int))))
+#define __sigmask(sig) \
+  (1UL << (((sig) - 1) % ULONG_WIDTH))
 
 /* Return the word index for SIG.  */
 static inline unsigned long int
 __sigword (int sig)
 {
-  return (sig - 1) / (8 * sizeof (unsigned long int));
+  return (sig - 1) / ULONG_WIDTH;
 }
 
 /* Linux sig* functions only handle up to __NSIG_WORDS words instead of
    full _SIGSET_NWORDS sigset size.  The signal numbers are 1-based, and
    bit 0 of a signal mask is for signal 1.  */
-
-# define __NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int )))
+#define __NSIG_WORDS (ALIGN_UP ((_NSIG - 1), ULONG_WIDTH) / ULONG_WIDTH)
+_Static_assert (__NSIG_WORDS <= _SIGSET_NWORDS,
+		"__NSIG_WORDS > _SIGSET_WORDS");
+
+/* This macro is used on syscall that takes a sigset_t to specify the expected
+   size in bytes.  As for glibc, kernel sigset is implemented as an array of
+   unsigned long.  */
+#define __NSIG_BYTES (__NSIG_WORDS * (ULONG_WIDTH / UCHAR_WIDTH))
 
 static inline void
 __sigemptyset (sigset_t *set)
diff --git a/sysdeps/unix/sysv/linux/sigsuspend.c b/sysdeps/unix/sysv/linux/sigsuspend.c
index dd5df5af25..b4bf2ec4bc 100644
--- a/sysdeps/unix/sysv/linux/sigsuspend.c
+++ b/sysdeps/unix/sysv/linux/sigsuspend.c
@@ -23,7 +23,7 @@ 
 int
 __sigsuspend (const sigset_t *set)
 {
-  return SYSCALL_CANCEL (rt_sigsuspend, set, _NSIG / 8);
+  return SYSCALL_CANCEL (rt_sigsuspend, set, __NSIG_BYTES);
 }
 libc_hidden_def (__sigsuspend)
 weak_alias (__sigsuspend, sigsuspend)
diff --git a/sysdeps/unix/sysv/linux/sigtimedwait.c b/sysdeps/unix/sysv/linux/sigtimedwait.c
index 6b3d8f705f..f2ef3aad45 100644
--- a/sysdeps/unix/sysv/linux/sigtimedwait.c
+++ b/sysdeps/unix/sysv/linux/sigtimedwait.c
@@ -26,7 +26,8 @@  __sigtimedwait (const sigset_t *set, siginfo_t *info,
 {
   /* XXX The size argument hopefully will have to be changed to the
      real size of the user-level sigset_t.  */
-  int result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, timeout, _NSIG / 8);
+  int result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, timeout,
+			       __NSIG_BYTES);
 
   /* The kernel generates a SI_TKILL code in si_code in case tkill is
      used.  tkill is transparently used in raise().  Since having
diff --git a/sysdeps/unix/sysv/linux/x86/setjmpP.h b/sysdeps/unix/sysv/linux/x86/setjmpP.h
index 1783b8eb78..a5de31bfd6 100644
--- a/sysdeps/unix/sysv/linux/x86/setjmpP.h
+++ b/sysdeps/unix/sysv/linux/x86/setjmpP.h
@@ -21,6 +21,7 @@ 
 
 #include <bits/types/__sigset_t.h>
 #include <libc-pointer-arith.h>
+#include <sigsetops.h>
 
 /* <setjmp/setjmp.h> has
 
@@ -113,11 +114,9 @@  typedef union
 
 #include <signal.h>
 
-#define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
-
 typedef struct
   {
-    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+    unsigned long int __val[__NSIG_WORDS];
   } __sigprocmask_sigset_t;
 
 extern jmp_buf ___buf;