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:
@@ -28,24 +28,40 @@ __pthread_kill (pthread_t threadid, int signo)
|
||||
if (__is_internal_signal (signo))
|
||||
return EINVAL;
|
||||
|
||||
/* 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;
|
||||
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. */
|
||||
pid_t pid = __getpid ();
|
||||
if (pd == THREAD_SELF)
|
||||
/* 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);
|
||||
return (INTERNAL_SYSCALL_ERROR_P (val)
|
||||
? INTERNAL_SYSCALL_ERRNO (val) : 0);
|
||||
int val;
|
||||
if (__glibc_likely (tid > 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);
|
||||
|
||||
#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);
|
||||
# endif
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user