mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-08 17:42:12 +03:00
nptl: Implement raise in terms of pthread_kill
Now that pthread_kill is provided by libc.so it is possible to implement the generic POSIX implementation as 'pthread_kill(pthread_self(), sig)'. For Linux implementation, pthread_kill read the targeting TID from the TCB. For raise, this it not possible because it would make raise fail when issue after vfork (where creates the resulting process has a different TID from the parent, but its TCB is not updated as for pthread_create). To make raise use pthread_kill, it is make usable from vfork by getting the target thread id through gettid syscall. Checked on x86_64-linux-gnu and aarch64-linux-gnu.
This commit is contained in:
@@ -16,4 +16,9 @@ extern int __pthread_barrier_wait (pthread_barrier_t *__barrier)
|
|||||||
|
|
||||||
/* This function is called to initialize the pthread library. */
|
/* This function is called to initialize the pthread library. */
|
||||||
extern void __pthread_initialize (void) __attribute__ ((weak));
|
extern void __pthread_initialize (void) __attribute__ ((weak));
|
||||||
|
|
||||||
|
extern int __pthread_kill (pthread_t threadid, int signo);
|
||||||
|
|
||||||
|
extern pthread_t __pthread_self (void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -251,6 +251,7 @@ CFLAGS-pthread_clockjoin.c += -fexceptions -fasynchronous-unwind-tables
|
|||||||
CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \
|
CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \
|
||||||
-fasynchronous-unwind-tables
|
-fasynchronous-unwind-tables
|
||||||
CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables
|
CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables
|
||||||
|
CFLAGS-pthread_kill.c = -fexceptions -fasynchronous-unwind-tables
|
||||||
CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables
|
CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables
|
||||||
CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables
|
CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables
|
||||||
CFLAGS-sem_clockwait.c = -fexceptions -fasynchronous-unwind-tables
|
CFLAGS-sem_clockwait.c = -fexceptions -fasynchronous-unwind-tables
|
||||||
|
@@ -508,11 +508,13 @@ extern int __pthread_once (pthread_once_t *once_control,
|
|||||||
libc_hidden_proto (__pthread_once)
|
libc_hidden_proto (__pthread_once)
|
||||||
extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void),
|
extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void),
|
||||||
void (*child) (void));
|
void (*child) (void));
|
||||||
extern pthread_t __pthread_self (void);
|
libc_hidden_proto (__pthread_self)
|
||||||
extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
|
extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
|
||||||
extern int __pthread_detach (pthread_t th);
|
extern int __pthread_detach (pthread_t th);
|
||||||
libc_hidden_proto (__pthread_detach)
|
libc_hidden_proto (__pthread_detach)
|
||||||
extern int __pthread_kill (pthread_t threadid, int signo);
|
extern int __pthread_kill (pthread_t threadid, int signo);
|
||||||
|
libc_hidden_proto (__pthread_kill)
|
||||||
|
extern int __pthread_cancel (pthread_t th);
|
||||||
extern void __pthread_exit (void *value) __attribute__ ((__noreturn__));
|
extern void __pthread_exit (void *value) __attribute__ ((__noreturn__));
|
||||||
libc_hidden_proto (__pthread_exit)
|
libc_hidden_proto (__pthread_exit)
|
||||||
extern int __pthread_join (pthread_t threadid, void **thread_return);
|
extern int __pthread_join (pthread_t threadid, void **thread_return);
|
||||||
|
@@ -28,24 +28,40 @@ __pthread_kill (pthread_t threadid, int signo)
|
|||||||
if (__is_internal_signal (signo))
|
if (__is_internal_signal (signo))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/* Force load of pd->tid into local variable or register. Otherwise
|
pid_t tid;
|
||||||
if a thread exits between ESRCH test and tgkill, we might return
|
|
||||||
EINVAL, because pd->tid would be cleared by the kernel. */
|
|
||||||
struct pthread *pd = (struct pthread *) threadid;
|
struct pthread *pd = (struct pthread *) threadid;
|
||||||
pid_t tid = atomic_forced_read (pd->tid);
|
|
||||||
if (__glibc_unlikely (tid <= 0))
|
|
||||||
/* Not a valid thread handle. */
|
|
||||||
return ESRCH;
|
|
||||||
|
|
||||||
/* We have a special syscall to do the work. */
|
if (pd == THREAD_SELF)
|
||||||
pid_t pid = __getpid ();
|
/* It is a special case to handle raise() implementation after a vfork
|
||||||
|
call (which does not update the PD tid field). */
|
||||||
|
tid = INLINE_SYSCALL_CALL (gettid);
|
||||||
|
else
|
||||||
|
/* 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. */
|
||||||
|
tid = atomic_forced_read (pd->tid);
|
||||||
|
|
||||||
int val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo);
|
int val;
|
||||||
return (INTERNAL_SYSCALL_ERROR_P (val)
|
if (__glibc_likely (tid > 0))
|
||||||
? INTERNAL_SYSCALL_ERRNO (val) : 0);
|
{
|
||||||
|
pid_t pid = __getpid ();
|
||||||
|
|
||||||
|
val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo);
|
||||||
|
val = (INTERNAL_SYSCALL_ERROR_P (val)
|
||||||
|
? INTERNAL_SYSCALL_ERRNO (val) : 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
val = ESRCH;
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
/* Some architectures (for instance arm) might pull raise through libgcc, so
|
||||||
|
avoid the symbol version if it ends up being used on ld.so. */
|
||||||
|
#if !IS_IN(rtld)
|
||||||
|
libc_hidden_def (__pthread_kill)
|
||||||
versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);
|
versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);
|
||||||
|
|
||||||
#if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
|
# if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
|
||||||
compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
|
compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@@ -20,7 +20,9 @@
|
|||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
|
|
||||||
pthread_t
|
pthread_t
|
||||||
pthread_self (void)
|
__pthread_self (void)
|
||||||
{
|
{
|
||||||
return (pthread_t) THREAD_SELF;
|
return (pthread_t) THREAD_SELF;
|
||||||
}
|
}
|
||||||
|
libc_hidden_def (__pthread_self)
|
||||||
|
weak_alias (__pthread_self, pthread_self)
|
||||||
|
@@ -31,8 +31,6 @@ extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
|
|||||||
|
|
||||||
/* These represent the interface used by glibc itself. */
|
/* These represent the interface used by glibc itself. */
|
||||||
|
|
||||||
extern pthread_t __pthread_self (void);
|
|
||||||
extern int __pthread_kill (pthread_t threadid, int signo);
|
|
||||||
extern struct __pthread **__pthread_threads;
|
extern struct __pthread **__pthread_threads;
|
||||||
|
|
||||||
extern int __pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__attr);
|
extern int __pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__attr);
|
||||||
|
@@ -16,13 +16,20 @@
|
|||||||
<https://www.gnu.org/licenses/>. */
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
/* Raise the signal SIG. */
|
/* Raise the signal SIG. */
|
||||||
int
|
int
|
||||||
raise (int sig)
|
raise (int sig)
|
||||||
{
|
{
|
||||||
return __kill (__getpid (), sig);
|
int ret = __pthread_kill (__pthread_self (), sig);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
__set_errno (ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
libc_hidden_def (raise)
|
libc_hidden_def (raise)
|
||||||
weak_alias (raise, gsignal)
|
weak_alias (raise, gsignal)
|
||||||
|
@@ -1,52 +0,0 @@
|
|||||||
/* Copyright (C) 2002-2021 Free Software Foundation, Inc.
|
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with the GNU C Library; if not, see
|
|
||||||
<https://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sysdep.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <internal-signals.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
raise (int sig)
|
|
||||||
{
|
|
||||||
/* rt_sigprocmask may fail if:
|
|
||||||
|
|
||||||
1. sigsetsize != sizeof (sigset_t) (EINVAL)
|
|
||||||
2. a failure in copy from/to user space (EFAULT)
|
|
||||||
3. an invalid 'how' operation (EINVAL)
|
|
||||||
|
|
||||||
The first case is already handle in glibc syscall call by using the arch
|
|
||||||
defined _NSIG. Second case is handled by using a stack allocated mask.
|
|
||||||
The last one should be handled by the block/unblock functions. */
|
|
||||||
|
|
||||||
sigset_t set;
|
|
||||||
__libc_signal_block_app (&set);
|
|
||||||
|
|
||||||
pid_t pid = INTERNAL_SYSCALL_CALL (getpid);
|
|
||||||
pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
|
|
||||||
|
|
||||||
int ret = INLINE_SYSCALL_CALL (tgkill, pid, tid, sig);
|
|
||||||
|
|
||||||
__libc_signal_restore_set (&set);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
libc_hidden_def (raise)
|
|
||||||
weak_alias (raise, gsignal)
|
|
Reference in New Issue
Block a user