diff options
Diffstat (limited to 'nptl/pthread_sigqueue.c')
-rw-r--r-- | nptl/pthread_sigqueue.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/nptl/pthread_sigqueue.c b/nptl/pthread_sigqueue.c index 7d60e2b98d..64bacfe41b 100644 --- a/nptl/pthread_sigqueue.c +++ b/nptl/pthread_sigqueue.c @@ -1,6 +1,6 @@ -/* Queue a signal (with value) for a specific pthread. Stub version. - Copyright (C) 2014-2021 Free Software Foundation, Inc. +/* Copyright (C) 2009-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,12 +18,17 @@ #include <errno.h> #include <signal.h> +#include <string.h> +#include <unistd.h> #include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> int pthread_sigqueue (pthread_t threadid, int signo, const union sigval value) { +#ifdef __NR_rt_tgsigqueueinfo struct pthread *pd = (struct pthread *) threadid; /* Make sure the descriptor is valid. */ @@ -31,7 +36,36 @@ pthread_sigqueue (pthread_t threadid, int signo, const union sigval value) /* Not a valid thread handle. */ return ESRCH; + /* Force load of pd->tid into local variable or register. Otherwise + if a thread exits between ESRCH test and tgkill, we might return + EINVAL, because pd->tid would be cleared by the kernel. */ + pid_t tid = atomic_forced_read (pd->tid); + if (__glibc_unlikely (tid <= 0)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Disallow sending the signal we use for cancellation, timers, + for the setxid implementation. */ + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + + pid_t pid = getpid (); + + /* Set up the siginfo_t structure. */ + siginfo_t info; + memset (&info, '\0', sizeof (siginfo_t)); + info.si_signo = signo; + info.si_code = SI_QUEUE; + info.si_pid = pid; + info.si_uid = getuid (); + info.si_value = value; + + /* We have a special syscall to do the work. */ + int val = INTERNAL_SYSCALL_CALL (rt_tgsigqueueinfo, pid, tid, signo, + &info); + return (INTERNAL_SYSCALL_ERROR_P (val) + ? INTERNAL_SYSCALL_ERRNO (val) : 0); +#else return ENOSYS; +#endif } - -stub_warning (pthread_sigqueue) |