mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	This patch changes the way cancellation entrypoints are defined to
instead call the macro SYSCALL_CANCEL.  An usual cnacellation definition
is defined as:
  if (SINGLE_THREAD_P)
    return INLINE_SYSCALL (syscall, NARGS, args...)
  int oldtype = LIBC_CANCEL_ASYNC ();
  return INLINE_SYSCALL (syscall, NARGS, args...)
  LIBC_CANCEL_RESET (oldtype);
And it is rewrited as just:
  SYSCALL_CANCEL (syscall, args...)
The idea is to remove LIBC_CANCEL_ASYNC/LIBC_CANCEL_RESET explicit
usage.
Tested on i386, x86_64, powerpc32, powerpc64le, arm, and aarch64.
	* sysdeps/unix/sysdep.h [SYSCALL_CANCEL]: New macro: define
	cancellable syscalls.
	(SYS_ify): Add guard to no redefine it.
	(INLINE_SYSCALL): Likewise.
	* sysdeps/unix/sysv/linux/accept4.c (accept4): Remove
	LIBC_CANCEL_ASYNC/INLINE_SYSCALL/LIBC_CANCEL_RESET and use
	SYSCALL_CANCEL instead.
	* sysdeps/unix/sysv/linux/alpha/fdatasync.c (__fdatasync): Likewise.
	* sysdeps/unix/sysv/linux/arm/pread.c (__libc_pread): Likewise.
	* sysdeps/unix/sysv/linux/arm/pread64.c (__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/arm/pwrite.c (__libc_pwrite): Likewise.
	* sysdeps/unix/sysv/linux/arm/pwrite64.c (__libc_pwrite64): Likewise.
	* sysdeps/unix/sysv/linux/epoll_pwait.c (epoll_pwait): Likewise.
	* sysdeps/unix/sysv/linux/fallocate.c (fallocate): Likewise.
	* sysdeps/unix/sysv/linux/fallocate64.c (fallocate64): Likewise.
	* sysdeps/unix/sysv/linux/generic/open.c (__libc_open): Likewise.
	* sysdeps/unix/sysv/linux/generic/open64.c (__libc_open64): Likewise.
	* sysdeps/unix/sysv/linux/generic/pause.c (__libc_pause): Likewise.
	* sysdeps/unix/sysv/linux/generic/poll.c (__poll): Likewise.
	* sysdeps/unix/sysv/linux/generic/recv.c (__libc_recv): Likewise.
	* sysdeps/unix/sysv/linux/generic/select.c (__select): Likewise.
	* sysdeps/unix/sysv/linux/generic/send.c (__libc_send): Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/pread.c (__libc_pread):
	Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/pread64.c
	(__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/preadv.c
	(__libc_preadv): Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/preadv64.c
	(__libc_readv64): Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/pwrite.c
	(__libc_pwrite): Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/pwrite64.c
	(__libc_pwrite64): Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/pwritev.c
	(__libc_pwritev): Likewise.
	* sysdeps/sysv/linux/generic/wordsize-32/pwritev64.c
	(__libc_pwritev64): Likewise.
	* sysdeps/unix/sysv/linux/i386/fcntl.c (__libc_fcntl): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/sync_file_range.c
	(sync_file_range): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/fallocate.c (fallocate):
	Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/fallocate64.c (fallocate64):
	Likewise.
	* sysdeps/unix/sysv/linux/mips/pread.c (__libc_pread): Likewise.
	* sysdeps/unix/sysv/linux/mips/pread64.c (__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/mips/pwrite.c (__libc_pwrite): Likewise.
	* sysdeps/unix/sysv/linux/mips/pwrite64.c (__libc_pwrite64): Likewise.
	* sysdeps/unix/sysv/linux/msgrcv.c (__libc_msgrcv): Likewise.
	* sysdeps/unix/sysv/linux/msgsnd.c (__libc_msgsnd): Likewise.
	* sysdeps/unix/sysv/linux/open64.c (__libc_open64): Likewise.
	* sysdeps/unix/sysv/linux/openat.c (__libc_openat): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/pread.c (__libc_pread):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/pread64.c
	(__libc_read64): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/pwrite.c (__libc_write):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/pwrite64.c (__libc_write64):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fcntl):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c (__libc_pread):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pread64.c
	(__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite.c (__libc_pwrite):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite64.c
	(__libc_pwrite64): Likewise.
	* sysdeps/sysv/linux/powerpc/powerpc64/sync_file_range.c
	(sync_file_range): Likewise.
	* sysdeps/unix/sysv/linux/ppoll.c (ppoll): Likewise.
	* sysdeps/unix/sysv/linux/pread.c (__libc_pread): Likewise.
	* sysdeps/unix/sysv/linux/pread64.c (__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/preadv.c (__libc_preadv): Likewise.
	* sysdeps/unix/sysv/linux/pselect.c (__pselect): Likewise.
	* sysdeps/unix/sysv/linux/pwrite.c (__libc_pwrite): Likewise.
	* sysdeps/unix/sysv/linux/pwrite64.c (__libc_pwrite64): Likewise.
	* sysdeps/unix/sysv/linux/pwritev.c (PWRITEV): Likewise.
	* sysdeps/unix/sysv/linux/readv.c (__libc_readv): Likewise.
	* sysdeps/unix/sysv/linux/recvmmsg.c (recvmmsg): Likewise.
	* sysdeps/unix/sysv/linux/sendmmsg.c (sendmmsg): Likewise.
	* sysdeps/unix/sysv/linux/sh/pread.c (__libc_pread): Likewise.
	* sysdeps/unix/sysv/linux/sh/pread64.c (__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/sh/pwrite.c (__libc_pwrite): Likewise.
	* sysdeps/unix/sysv/linux/sh/pwrite64.c (__libc_pwrite64): Likewise.
	* sysdeps/unix/sysv/linux/sigsuspend.c (__sigsuspend): Likewise.
	* sysdeps/unix/sysv/linux/sigtimedwait.c (__sigtimedwait): Likewise.
	* sysdeps/unix/sysv/linux/sigwaitinfo.c (__sigwaitinfo): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/msgrcv.c (__libc_msgrcv):
	Likewise.
	* sysdeps/unix/sysv/linux/sync_file_range.c (sync_file_range):
	Likewise.
	* sysdeps/unix/sysv/linux/tcdrain.c (__libc_tcdrain): Likewise.
	* sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
	Likewise.
	* sysdeps/unix/sysv/linux/wait.c (__libc_wait): Likewise.
	* sysdeps/unix/sysv/linux/waitid.c (__waitid): Likewise.
	* sysdeps/unix/sysv/linux/waitpid.c (__libc_waitpid): Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/fallocate.c (fallocate):
	Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/preadv.c (preadv): Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/pwritev.c (pwritev): Likewise.
	* sysdeps/unix/sysv/linux/writev.c (__libc_writev): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/recv.c (__libc_recv): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/send.c (__libc_send): Likewise.
		
	
		
			
				
	
	
		
			192 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 2003-2015 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
|    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
 | |
| 
 | |
|    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; see the file COPYING.LIB.  If
 | |
|    not, see <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <setjmp.h>
 | |
| #include <signal.h>
 | |
| #include <stdbool.h>
 | |
| #include <sysdep-cancel.h>
 | |
| #include <nptl/pthreadP.h>
 | |
| #include "kernel-posix-timers.h"
 | |
| 
 | |
| 
 | |
| /* List of active SIGEV_THREAD timers.  */
 | |
| struct timer *__active_timer_sigev_thread;
 | |
| /* Lock for the __active_timer_sigev_thread.  */
 | |
| pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER;
 | |
| 
 | |
| 
 | |
| struct thread_start_data
 | |
| {
 | |
|   void (*thrfunc) (sigval_t);
 | |
|   sigval_t sival;
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Helper thread to call the user-provided function.  */
 | |
| static void *
 | |
| timer_sigev_thread (void *arg)
 | |
| {
 | |
|   /* The parent thread has all signals blocked.  This is a bit
 | |
|      surprising for user code, although valid.  We unblock all
 | |
|      signals.  */
 | |
|   sigset_t ss;
 | |
|   sigemptyset (&ss);
 | |
|   INTERNAL_SYSCALL_DECL (err);
 | |
|   INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8);
 | |
| 
 | |
|   struct thread_start_data *td = (struct thread_start_data *) arg;
 | |
| 
 | |
|   void (*thrfunc) (sigval_t) = td->thrfunc;
 | |
|   sigval_t sival = td->sival;
 | |
| 
 | |
|   /* The TD object was allocated in timer_helper_thread.  */
 | |
|   free (td);
 | |
| 
 | |
|   /* Call the user-provided function.  */
 | |
|   thrfunc (sival);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Helper function to support starting threads for SIGEV_THREAD.  */
 | |
| static void *
 | |
| timer_helper_thread (void *arg)
 | |
| {
 | |
|   /* Wait for the SIGTIMER signal, allowing the setXid signal, and
 | |
|      none else.  */
 | |
|   sigset_t ss;
 | |
|   sigemptyset (&ss);
 | |
|   __sigaddset (&ss, SIGTIMER);
 | |
| 
 | |
|   /* Endless loop of waiting for signals.  The loop is only ended when
 | |
|      the thread is canceled.  */
 | |
|   while (1)
 | |
|     {
 | |
|       siginfo_t si;
 | |
| 
 | |
|       /* sigwaitinfo cannot be used here, since it deletes
 | |
| 	 SIGCANCEL == SIGTIMER from the set.  */
 | |
| 
 | |
|       /* 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, &ss, &si, NULL, _NSIG / 8);
 | |
| 
 | |
|       if (result > 0)
 | |
| 	{
 | |
| 	  if (si.si_code == SI_TIMER)
 | |
| 	    {
 | |
| 	      struct timer *tk = (struct timer *) si.si_ptr;
 | |
| 
 | |
| 	      /* Check the timer is still used and will not go away
 | |
| 		 while we are reading the values here.  */
 | |
| 	      pthread_mutex_lock (&__active_timer_sigev_thread_lock);
 | |
| 
 | |
| 	      struct timer *runp = __active_timer_sigev_thread;
 | |
| 	      while (runp != NULL)
 | |
| 		if (runp == tk)
 | |
| 		  break;
 | |
| 		else
 | |
| 		  runp = runp->next;
 | |
| 
 | |
| 	      if (runp != NULL)
 | |
| 		{
 | |
| 		  struct thread_start_data *td = malloc (sizeof (*td));
 | |
| 
 | |
| 		  /* There is not much we can do if the allocation fails.  */
 | |
| 		  if (td != NULL)
 | |
| 		    {
 | |
| 		      /* This is the signal we are waiting for.  */
 | |
| 		      td->thrfunc = tk->thrfunc;
 | |
| 		      td->sival = tk->sival;
 | |
| 
 | |
| 		      pthread_t th;
 | |
| 		      (void) pthread_create (&th, &tk->attr,
 | |
| 					     timer_sigev_thread, td);
 | |
| 		    }
 | |
| 		}
 | |
| 
 | |
| 	      pthread_mutex_unlock (&__active_timer_sigev_thread_lock);
 | |
| 	    }
 | |
| 	  else if (si.si_code == SI_TKILL)
 | |
| 	    /* The thread is canceled.  */
 | |
| 	    pthread_exit (NULL);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Control variable for helper thread creation.  */
 | |
| pthread_once_t __helper_once attribute_hidden;
 | |
| 
 | |
| 
 | |
| /* TID of the helper thread.  */
 | |
| pid_t __helper_tid attribute_hidden;
 | |
| 
 | |
| 
 | |
| /* Reset variables so that after a fork a new helper thread gets started.  */
 | |
| static void
 | |
| reset_helper_control (void)
 | |
| {
 | |
|   __helper_once = PTHREAD_ONCE_INIT;
 | |
|   __helper_tid = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| attribute_hidden
 | |
| __start_helper_thread (void)
 | |
| {
 | |
|   /* The helper thread needs only very little resources
 | |
|      and should go away automatically when canceled.  */
 | |
|   pthread_attr_t attr;
 | |
|   (void) pthread_attr_init (&attr);
 | |
|   (void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
 | |
| 
 | |
|   /* Block all signals in the helper thread but SIGSETXID.  To do this
 | |
|      thoroughly we temporarily have to block all signals here.  The
 | |
|      helper can lose wakeups if SIGCANCEL is not blocked throughout,
 | |
|      but sigfillset omits it SIGSETXID.  So, we add SIGCANCEL back
 | |
|      explicitly here.  */
 | |
|   sigset_t ss;
 | |
|   sigset_t oss;
 | |
|   sigfillset (&ss);
 | |
|   __sigaddset (&ss, SIGCANCEL);
 | |
|   INTERNAL_SYSCALL_DECL (err);
 | |
|   INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8);
 | |
| 
 | |
|   /* Create the helper thread for this timer.  */
 | |
|   pthread_t th;
 | |
|   int res = pthread_create (&th, &attr, timer_helper_thread, NULL);
 | |
|   if (res == 0)
 | |
|     /* We managed to start the helper thread.  */
 | |
|     __helper_tid = ((struct pthread *) th)->tid;
 | |
| 
 | |
|   /* Restore the signal mask.  */
 | |
|   INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL,
 | |
| 		    _NSIG / 8);
 | |
| 
 | |
|   /* No need for the attribute anymore.  */
 | |
|   (void) pthread_attr_destroy (&attr);
 | |
| 
 | |
|   /* We have to make sure that after fork()ing a new helper thread can
 | |
|      be created.  */
 | |
|   pthread_atfork (NULL, NULL, reset_helper_control);
 | |
| }
 |