Home | History | Annotate | Line # | Download | only in gdb.threads
      1      1.1  christos /* This testcase is part of GDB, the GNU debugger.
      2      1.1  christos 
      3  1.1.1.4  christos    Copyright 2018-2024 Free Software Foundation, Inc.
      4      1.1  christos 
      5      1.1  christos    This program is free software; you can redistribute it and/or modify
      6      1.1  christos    it under the terms of the GNU General Public License as published by
      7      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      8      1.1  christos    (at your option) any later version.
      9      1.1  christos 
     10      1.1  christos    This program is distributed in the hope that it will be useful,
     11      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13      1.1  christos    GNU General Public License for more details.
     14      1.1  christos 
     15      1.1  christos    You should have received a copy of the GNU General Public License
     16      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17      1.1  christos 
     18      1.1  christos /* This file contains a library that can be preloaded into GDB on Linux
     19      1.1  christos    using the LD_PRELOAD technique.
     20      1.1  christos 
     21      1.1  christos    The library intercepts calls to WAITPID and SIGSUSPEND in order to
     22  1.1.1.5  christos    simulate the behavior of a heavily loaded kernel.
     23      1.1  christos 
     24      1.1  christos    When GDB wants to stop all threads in an inferior each thread is sent a
     25      1.1  christos    SIGSTOP, GDB will then wait for the signal to be received by the thread
     26      1.1  christos    with a waitpid call.
     27      1.1  christos 
     28      1.1  christos    If the kernel is slow in either delivering the signal, or making the
     29      1.1  christos    result available to the waitpid call then GDB will enter a sigsuspend
     30      1.1  christos    call in order to wait for the inferior threads to change state, this is
     31      1.1  christos    signalled to GDB with a SIGCHLD.
     32      1.1  christos 
     33      1.1  christos    A bug in GDB meant that in some cases we would deadlock during this
     34      1.1  christos    process.  This was rarely seen as the kernel is usually quick at
     35      1.1  christos    delivering signals and making the results available to waitpid, so quick
     36      1.1  christos    that GDB would gather the statuses from all inferior threads in the
     37      1.1  christos    original pass.
     38      1.1  christos 
     39      1.1  christos    The idea in this library is to rate limit calls to waitpid (where pid is
     40      1.1  christos    -1 and the WNOHANG option is set) so that only 1 per second can return
     41      1.1  christos    an answer.  Any additional calls will report that no threads are
     42  1.1.1.5  christos    currently ready.  This should match the behavior we see on a slow
     43      1.1  christos    kernel.
     44      1.1  christos 
     45      1.1  christos    However, given that usually when using this library, the kernel does
     46      1.1  christos    have the waitpid result ready this means that the kernel will never send
     47      1.1  christos    GDB a SIGCHLD.  This means that when GDB enters sigsuspend it will block
     48      1.1  christos    forever.  Alternatively, if GDB enters its polling loop the lack of
     49      1.1  christos    SIGCHLD means that we will never see an event on the child threads.  To
     50      1.1  christos    resolve these problems the library intercepts calls to sigsuspend and
     51      1.1  christos    forces the call to exit if there is a pending waitpid result.  Also,
     52      1.1  christos    when we know that there's a waitpid result that we've ignored, we create
     53      1.1  christos    a new thread which, after a short delay, will send GDB a SIGCHLD.  */
     54      1.1  christos 
     55      1.1  christos #define _GNU_SOURCE
     56      1.1  christos 
     57      1.1  christos #include <sys/types.h>
     58      1.1  christos #include <sys/wait.h>
     59      1.1  christos #include <sys/time.h>
     60      1.1  christos #include <stdlib.h>
     61      1.1  christos #include <stdio.h>
     62      1.1  christos #include <dlfcn.h>
     63      1.1  christos #include <string.h>
     64      1.1  christos #include <stdarg.h>
     65      1.1  christos #include <signal.h>
     66      1.1  christos #include <errno.h>
     67      1.1  christos #include <pthread.h>
     68      1.1  christos #include <unistd.h>
     69      1.1  christos 
     70      1.1  christos /* Logging.  */
     71      1.1  christos 
     72      1.1  christos static void
     73      1.1  christos log_msg (const char *fmt, ...)
     74      1.1  christos {
     75      1.1  christos #ifdef LOGGING
     76      1.1  christos   va_list ap;
     77      1.1  christos 
     78      1.1  christos   va_start (ap, fmt);
     79      1.1  christos   vfprintf (stderr, fmt, ap);
     80      1.1  christos   va_end (ap);
     81      1.1  christos #endif /* LOGGING */
     82      1.1  christos }
     83      1.1  christos 
     84      1.1  christos /* Error handling, message and exit.  */
     85      1.1  christos 
     86      1.1  christos static void
     87      1.1  christos error (const char *fmt, ...)
     88      1.1  christos {
     89      1.1  christos   va_list ap;
     90      1.1  christos 
     91      1.1  christos   va_start (ap, fmt);
     92      1.1  christos   vfprintf (stderr, fmt, ap);
     93      1.1  christos   va_end (ap);
     94      1.1  christos 
     95      1.1  christos   exit (EXIT_FAILURE);
     96      1.1  christos }
     97      1.1  christos 
     98      1.1  christos /* Cache the result of a waitpid call that has not been reported back to
     99      1.1  christos    GDB yet.  We only ever cache a single result.  Once we have a result
    100      1.1  christos    cached then later calls to waitpid with the WNOHANG option will return a
    101      1.1  christos    result of 0.  */
    102      1.1  christos 
    103      1.1  christos static struct
    104      1.1  christos {
    105      1.1  christos   /* Flag to indicate when we have a result cached.  */
    106      1.1  christos   int cached_p;
    107      1.1  christos 
    108      1.1  christos   /* The cached result fields from a waitpid call.  */
    109      1.1  christos   pid_t pid;
    110      1.1  christos   int wstatus;
    111      1.1  christos } cached_wait_status;
    112      1.1  christos 
    113      1.1  christos /* Lock to hold when modifying SIGNAL_THREAD_ACTIVE_P.  */
    114      1.1  christos 
    115      1.1  christos static pthread_mutex_t thread_creation_lock_obj = PTHREAD_MUTEX_INITIALIZER;
    116      1.1  christos #define thread_creation_lock (&thread_creation_lock_obj)
    117      1.1  christos 
    118      1.1  christos /* This flag is only modified while holding the THREAD_CREATION_LOCK mutex.
    119      1.1  christos    When this flag is true then there is a signal thread alive that will be
    120      1.1  christos    sending a SIGCHLD at some point in the future.  */
    121      1.1  christos 
    122      1.1  christos static int signal_thread_active_p;
    123      1.1  christos 
    124      1.1  christos /* When we last allowed a waitpid to complete.  */
    125      1.1  christos 
    126      1.1  christos static struct timeval last_waitpid_time = { 0, 0 };
    127      1.1  christos 
    128      1.1  christos /* The number of seconds that must elapse between calls to waitpid where
    129      1.1  christos    the pid is -1 and the WNOHANG option is set.  If calls occur faster than
    130      1.1  christos    this then we force a result of 0 to be returned from waitpid.  */
    131      1.1  christos 
    132      1.1  christos #define WAITPID_MIN_TIME (1)
    133      1.1  christos 
    134      1.1  christos /* Return true (non-zero) if we should skip this call to waitpid, or false
    135      1.1  christos    (zero) if this waitpid call should be handled with a call to the "real"
    136      1.1  christos    waitpid function.  Allows 1 waitpid call per second.  */
    137      1.1  christos 
    138      1.1  christos static int
    139      1.1  christos should_skip_waitpid (void)
    140      1.1  christos {
    141      1.1  christos   struct timeval *tv = &last_waitpid_time;
    142      1.1  christos   if (tv->tv_sec == 0)
    143      1.1  christos     {
    144      1.1  christos       if (gettimeofday (tv, NULL) < 0)
    145      1.1  christos 	error ("error: gettimeofday failed\n");
    146      1.1  christos       return 0; /* Don't skip.  */
    147      1.1  christos     }
    148      1.1  christos   else
    149      1.1  christos     {
    150      1.1  christos       struct timeval new_tv;
    151      1.1  christos 
    152      1.1  christos       if (gettimeofday (&new_tv, NULL) < 0)
    153      1.1  christos 	error ("error: gettimeofday failed\n");
    154      1.1  christos 
    155      1.1  christos       if ((new_tv.tv_sec - tv->tv_sec) < WAITPID_MIN_TIME)
    156      1.1  christos 	return 1; /* Skip.  */
    157      1.1  christos 
    158      1.1  christos       *tv = new_tv;
    159      1.1  christos     }
    160      1.1  christos 
    161      1.1  christos   /* Don't skip.  */
    162      1.1  christos   return 0;
    163      1.1  christos }
    164      1.1  christos 
    165      1.1  christos /* Perform a real waitpid call.  */
    166      1.1  christos 
    167      1.1  christos static pid_t
    168      1.1  christos real_waitpid (pid_t pid, int *wstatus, int options)
    169      1.1  christos {
    170      1.1  christos   typedef pid_t (*fptr_t) (pid_t, int *, int);
    171      1.1  christos   static fptr_t real_func = NULL;
    172      1.1  christos 
    173      1.1  christos   if (real_func == NULL)
    174      1.1  christos     {
    175      1.1  christos       real_func = dlsym (RTLD_NEXT, "waitpid");
    176      1.1  christos       if (real_func == NULL)
    177      1.1  christos 	error ("error: failed to find real waitpid\n");
    178      1.1  christos     }
    179      1.1  christos 
    180      1.1  christos   return (*real_func) (pid, wstatus, options);
    181      1.1  christos }
    182      1.1  christos 
    183      1.1  christos /* Thread worker created when we cache a waitpid result.  Delays for a
    184      1.1  christos    short period of time and then sends SIGCHLD to the GDB process.  This
    185      1.1  christos    should trigger GDB to call waitpid again, at which point we will make
    186      1.1  christos    the cached waitpid result available.  */
    187      1.1  christos 
    188      1.1  christos static void*
    189      1.1  christos send_sigchld_thread (void *arg)
    190      1.1  christos {
    191      1.1  christos   /* Delay one second longer than WAITPID_MIN_TIME so that there can be no
    192      1.1  christos      chance that a call to SHOULD_SKIP_WAITPID will return true once the
    193      1.1  christos      SIGCHLD is delivered and handled.  */
    194      1.1  christos   sleep (WAITPID_MIN_TIME + 1);
    195      1.1  christos 
    196      1.1  christos   pthread_mutex_lock (thread_creation_lock);
    197      1.1  christos   signal_thread_active_p = 0;
    198      1.1  christos 
    199      1.1  christos   if (cached_wait_status.cached_p)
    200      1.1  christos     {
    201      1.1  christos       log_msg ("signal-thread: sending SIGCHLD\n");
    202      1.1  christos       kill (getpid (), SIGCHLD);
    203      1.1  christos     }
    204      1.1  christos 
    205      1.1  christos   pthread_mutex_unlock (thread_creation_lock);
    206      1.1  christos   return NULL;
    207      1.1  christos }
    208      1.1  christos 
    209      1.1  christos /* The waitpid entry point function.  */
    210      1.1  christos 
    211      1.1  christos pid_t
    212      1.1  christos waitpid (pid_t pid, int *wstatus, int options)
    213      1.1  christos {
    214      1.1  christos   log_msg ("waitpid: waitpid (%d, %p, 0x%x)\n", pid, wstatus, options);
    215      1.1  christos 
    216      1.1  christos   if ((options & WNOHANG) != 0
    217      1.1  christos       && pid == -1
    218      1.1  christos       && should_skip_waitpid ())
    219      1.1  christos     {
    220      1.1  christos       if (!cached_wait_status.cached_p)
    221      1.1  christos 	{
    222      1.1  christos 	  /* Do the waitpid call, but hold the result back.  */
    223      1.1  christos 	  pid_t tmp_pid;
    224      1.1  christos 	  int tmp_wstatus;
    225      1.1  christos 
    226      1.1  christos 	  tmp_pid = real_waitpid (-1, &tmp_wstatus, options);
    227      1.1  christos 	  if (tmp_pid > 0)
    228      1.1  christos 	    {
    229      1.1  christos 	      log_msg ("waitpid: delaying waitpid result (pid = %d)\n",
    230      1.1  christos 		       tmp_pid);
    231      1.1  christos 
    232      1.1  christos 	      /* Cache the result.  */
    233      1.1  christos 	      cached_wait_status.pid = tmp_pid;
    234      1.1  christos 	      cached_wait_status.wstatus = tmp_wstatus;
    235      1.1  christos 	      cached_wait_status.cached_p = 1;
    236      1.1  christos 
    237      1.1  christos 	      /* Is there a thread around that will be sending a signal in
    238      1.1  christos 		 the near future?  The prevents us from creating one
    239      1.1  christos 		 thread per call to waitpid when the calls occur in a
    240      1.1  christos 		 sequence.  */
    241      1.1  christos 	      pthread_mutex_lock (thread_creation_lock);
    242      1.1  christos 	      if (!signal_thread_active_p)
    243      1.1  christos 		{
    244      1.1  christos 		  sigset_t old_ss, new_ss;
    245      1.1  christos 		  pthread_t thread_id;
    246      1.1  christos 		  pthread_attr_t attr;
    247      1.1  christos 
    248      1.1  christos 		  /* Create the new signal sending thread in detached
    249      1.1  christos 		     state.  This means that the thread doesn't need to be
    250      1.1  christos 		     pthread_join'ed.  Which is fine as there's no result
    251      1.1  christos 		     we care about.  */
    252      1.1  christos 		  pthread_attr_init (&attr);
    253      1.1  christos 		  pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
    254      1.1  christos 
    255      1.1  christos 		  /* Ensure the signal sending thread has all signals
    256      1.1  christos 		     blocked.  We don't want any signals to GDB to be
    257      1.1  christos 		     handled in that thread.  */
    258      1.1  christos 		  sigfillset (&new_ss);
    259      1.1  christos 		  sigprocmask (SIG_BLOCK, &new_ss, &old_ss);
    260      1.1  christos 
    261      1.1  christos 		  log_msg ("waitpid: spawn thread to signal us\n");
    262      1.1  christos 		  if (pthread_create (&thread_id, &attr,
    263      1.1  christos 				      send_sigchld_thread, NULL) != 0)
    264      1.1  christos 		    error ("error: pthread_create failed\n");
    265      1.1  christos 
    266      1.1  christos 		  signal_thread_active_p = 1;
    267      1.1  christos 		  sigprocmask (SIG_SETMASK, &old_ss, NULL);
    268      1.1  christos 		  pthread_attr_destroy (&attr);
    269      1.1  christos 		}
    270      1.1  christos 
    271      1.1  christos 	      pthread_mutex_unlock (thread_creation_lock);
    272      1.1  christos 	    }
    273      1.1  christos 	}
    274      1.1  christos 
    275      1.1  christos       log_msg ("waitpid: skipping\n");
    276      1.1  christos       return 0;
    277      1.1  christos     }
    278      1.1  christos 
    279      1.1  christos   /* If we have a cached result that is a suitable reply for this call to
    280      1.1  christos      waitpid then send that cached result back now.  */
    281      1.1  christos   if (cached_wait_status.cached_p
    282      1.1  christos       && (pid == -1 || pid == cached_wait_status.pid))
    283      1.1  christos     {
    284      1.1  christos       pid_t pid;
    285      1.1  christos 
    286      1.1  christos       pid = cached_wait_status.pid;
    287      1.1  christos       log_msg ("waitpid: return cached result (%d)\n", pid);
    288      1.1  christos       *wstatus = cached_wait_status.wstatus;
    289      1.1  christos       cached_wait_status.cached_p = 0;
    290      1.1  christos       return pid;
    291      1.1  christos     }
    292      1.1  christos 
    293      1.1  christos   log_msg ("waitpid: real waitpid call\n");
    294      1.1  christos   return real_waitpid (pid, wstatus, options);
    295      1.1  christos }
    296      1.1  christos 
    297      1.1  christos /* Perform a real sigsuspend call.  */
    298      1.1  christos 
    299      1.1  christos static int
    300      1.1  christos real_sigsuspend (const sigset_t *mask)
    301      1.1  christos {
    302      1.1  christos   typedef int (*fptr_t) (const sigset_t *);
    303      1.1  christos   static fptr_t real_func = NULL;
    304      1.1  christos 
    305      1.1  christos   if (real_func == NULL)
    306      1.1  christos     {
    307      1.1  christos       real_func = dlsym (RTLD_NEXT, "sigsuspend");
    308      1.1  christos       if (real_func == NULL)
    309      1.1  christos 	error ("error: failed to find real sigsuspend\n");
    310      1.1  christos     }
    311      1.1  christos 
    312      1.1  christos   return (*real_func) (mask);
    313      1.1  christos }
    314      1.1  christos 
    315      1.1  christos /* The sigsuspend entry point function.  */
    316      1.1  christos 
    317      1.1  christos int
    318      1.1  christos sigsuspend (const sigset_t *mask)
    319      1.1  christos {
    320      1.1  christos   log_msg ("sigsuspend: sigsuspend (0x%p)\n", ((void *) mask));
    321      1.1  christos 
    322      1.1  christos   /* If SIGCHLD is _not_ in MASK, and is therefore deliverable, then if we
    323      1.1  christos      have a pending wait status pretend that a signal arrived.  We will
    324      1.1  christos      have a thread alive that is going to deliver a signal but doing this
    325      1.1  christos      will boost the speed as we don't have to wait for a signal.  If the
    326      1.1  christos      signal ends up being delivered then it should be harmless, we'll just
    327      1.1  christos      perform an additional waitpid call.   */
    328      1.1  christos   if (!sigismember (mask, SIGCHLD))
    329      1.1  christos     {
    330      1.1  christos       if (cached_wait_status.cached_p)
    331      1.1  christos 	{
    332      1.1  christos 	  log_msg ("sigsuspend: interrupt for cached waitstatus\n");
    333      1.1  christos 	  last_waitpid_time.tv_sec = 0;
    334      1.1  christos 	  last_waitpid_time.tv_usec = 0;
    335      1.1  christos 	  errno = EINTR;
    336      1.1  christos 	  return -1;
    337      1.1  christos 	}
    338      1.1  christos     }
    339      1.1  christos 
    340      1.1  christos   log_msg ("sigsuspend: real sigsuspend call\n");
    341      1.1  christos   return real_sigsuspend (mask);
    342      1.1  christos }
    343