Home | History | Annotate | Line # | Download | only in libcollector
      1  1.1.1.3  christos /* Copyright (C) 2021-2025 Free Software Foundation, Inc.
      2      1.1  christos    Contributed by Oracle.
      3      1.1  christos 
      4      1.1  christos    This file is part of GNU Binutils.
      5      1.1  christos 
      6      1.1  christos    This program is free software; you can redistribute it and/or modify
      7      1.1  christos    it under the terms of the GNU General Public License as published by
      8      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
      9      1.1  christos    any later version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful,
     12      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos    GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program; if not, write to the Free Software
     18      1.1  christos    Foundation, 51 Franklin Street - Fifth Floor, Boston,
     19      1.1  christos    MA 02110-1301, USA.  */
     20      1.1  christos 
     21      1.1  christos /*
     22      1.1  christos  *	Central SIGPROF dispatcher to various module event handlers
     23      1.1  christos  *      (REALPROF profile, HWC check, overview sample, manual sample)
     24      1.1  christos  */
     25      1.1  christos 
     26      1.1  christos #include "config.h"
     27      1.1  christos #include <dlfcn.h>
     28      1.1  christos #include <errno.h>
     29      1.1  christos #include <fcntl.h>
     30      1.1  christos #include <unistd.h>
     31      1.1  christos #include <stdlib.h>
     32      1.1  christos #include <string.h>
     33      1.1  christos #include <sys/param.h>
     34      1.1  christos #include <sys/syscall.h>
     35      1.1  christos #include <time.h>
     36      1.1  christos #include <signal.h>
     37      1.1  christos 
     38      1.1  christos #include "gp-defs.h"
     39      1.1  christos #include "gp-experiment.h"
     40      1.1  christos #include "collector.h"
     41      1.1  christos #include "collector_module.h"
     42      1.1  christos #include "tsd.h"
     43      1.1  christos #include "hwcdrv.h"
     44  1.1.1.2  christos #include "memmgr.h"
     45      1.1  christos 
     46      1.1  christos static void collector_sigprof_dispatcher (int, siginfo_t*, void*);
     47      1.1  christos static int init_interposition_intf ();
     48      1.1  christos static int collector_timer_create (timer_t * ptimerid);
     49      1.1  christos static int collector_timer_settime (int period, timer_t timerid);
     50      1.1  christos static int collector_timer_gettime (timer_t timerid);
     51      1.1  christos static volatile int collector_sigprof_entries = 0; /* counter for SIGPROF signals in DISPATCH_TST mode */
     52      1.1  christos static timer_t collector_master_thread_timerid = NULL;
     53      1.1  christos static collector_mutex_t collector_clone_libc_lock = COLLECTOR_MUTEX_INITIALIZER;
     54      1.1  christos static unsigned dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
     55      1.1  christos 
     56  1.1.1.2  christos static int (*__real_clone) (int (*fn)(void *), void *child_stack, int flags,
     57  1.1.1.2  christos 			    void *arg, ...) = NULL;
     58  1.1.1.2  christos static int (*__real_timer_create) (clockid_t clockid,
     59  1.1.1.2  christos 				struct sigevent *sevp, timer_t *timerid) = NULL;
     60  1.1.1.2  christos static int (*__real_timer_settime) (timer_t timerid, int flags,
     61  1.1.1.2  christos 				    const struct itimerspec *new_value,
     62  1.1.1.2  christos 				    struct itimerspec *old_value) = NULL;
     63  1.1.1.2  christos static int (*__real_timer_delete) (timer_t timerid) = NULL;
     64  1.1.1.2  christos static int (*__real_timer_gettime) (timer_t timerid,
     65  1.1.1.2  christos 				    struct itimerspec *curr_value) = NULL;
     66  1.1.1.2  christos 
     67  1.1.1.2  christos static int (*__real_pthread_create_2_34) (pthread_t *thread,
     68  1.1.1.2  christos 			const pthread_attr_t *attr,
     69  1.1.1.2  christos 			void *(*start_routine) (void *), void *arg) = NULL;
     70  1.1.1.2  christos static int (*__real_pthread_create_2_17) (pthread_t *thread,
     71  1.1.1.2  christos 			const pthread_attr_t *attr,
     72  1.1.1.2  christos 			void *(*start_routine) (void *), void *arg) = NULL;
     73  1.1.1.2  christos static int (*__real_pthread_create_2_2_5) (pthread_t *thread,
     74  1.1.1.2  christos 			const pthread_attr_t *attr,
     75  1.1.1.2  christos 			void *(*start_routine) (void *), void *arg) = NULL;
     76  1.1.1.2  christos static int (*__real_pthread_create_2_1) (pthread_t *thread,
     77  1.1.1.2  christos 			const pthread_attr_t *attr,
     78  1.1.1.2  christos 			void *(*start_routine) (void *), void *arg) = NULL;
     79  1.1.1.2  christos static int (*__real_pthread_create_2_0) (pthread_t *thread,
     80  1.1.1.2  christos 			const pthread_attr_t *attr,
     81  1.1.1.2  christos 			void *(*start_routine) (void *), void *arg) = NULL;
     82  1.1.1.2  christos 
     83  1.1.1.2  christos static int (*__real_timer_create_2_34) (clockid_t clockid,
     84  1.1.1.2  christos 				struct sigevent *sevp, timer_t *timerid) = NULL;
     85  1.1.1.2  christos static int (*__real_timer_create_2_17) (clockid_t clockid,
     86  1.1.1.2  christos 				struct sigevent *sevp, timer_t *timerid) = NULL;
     87  1.1.1.2  christos static int (*__real_timer_create_2_3_3) (clockid_t clockid,
     88  1.1.1.2  christos 				struct sigevent *sevp, timer_t *timerid) = NULL;
     89  1.1.1.2  christos static int (*__real_timer_create_2_2_5) (clockid_t clockid,
     90  1.1.1.2  christos 				struct sigevent *sevp, timer_t *timerid) = NULL;
     91  1.1.1.2  christos static int (*__real_timer_create_2_2) (clockid_t clockid,
     92  1.1.1.2  christos 				struct sigevent *sevp, timer_t *timerid) = NULL;
     93  1.1.1.2  christos 
     94  1.1.1.2  christos int (*__real_pthread_sigmask_2_32) (int, const sigset_t *, sigset_t *) = NULL;
     95  1.1.1.2  christos int (*__real_pthread_sigmask_2_17) (int, const sigset_t *, sigset_t *) = NULL;
     96  1.1.1.2  christos int (*__real_pthread_sigmask_2_2_5) (int, const sigset_t *, sigset_t *) = NULL;
     97  1.1.1.2  christos int (*__real_pthread_sigmask_2_0) (int, const sigset_t *, sigset_t *) = NULL;
     98  1.1.1.2  christos 
     99      1.1  christos 
    100      1.1  christos /* Original SIGPROF handler which will be replaced with the dispatcher.  Used
    101      1.1  christos  * to properly interact with libaio, which uses SIGPROF as its SIGAIOCANCEL. */
    102      1.1  christos static struct sigaction original_sigprof_handler;
    103      1.1  christos 
    104      1.1  christos enum
    105      1.1  christos {
    106      1.1  christos   DISPATCH_NYI = -1,    /* dispatcher not yet installed */
    107      1.1  christos   DISPATCH_OFF = 0,     /* dispatcher installed, but disabled */
    108      1.1  christos   DISPATCH_ON = 1,      /* dispatcher installed, and enabled */
    109      1.1  christos   DISPATCH_TST = 2      /* dispatcher installed, and enabled in testing mode */
    110      1.1  christos };
    111      1.1  christos 
    112  1.1.1.3  christos static struct sigaction sigaction_0;
    113      1.1  christos static int dispatch_mode = DISPATCH_NYI;   /* controls SIGPROF dispatching */
    114      1.1  christos static int itimer_period_requested = 0;    /* dispatcher itimer period */
    115      1.1  christos static int itimer_period_actual = 0;       /* actual dispatcher itimer period */
    116      1.1  christos 
    117  1.1.1.2  christos static int (*__real_sigaction) (int signum, const struct sigaction *act,
    118  1.1.1.2  christos                      struct sigaction *oldact) = NULL;
    119  1.1.1.2  christos static int (*__real_setitimer) (int which, const struct itimerval *new_value,
    120  1.1.1.2  christos                      struct itimerval *old_value) = NULL;
    121  1.1.1.2  christos static int (*__real_libc_setitimer) (int which,
    122  1.1.1.2  christos 	const struct itimerval *new_value, struct itimerval *old_value) = NULL;
    123  1.1.1.2  christos static int (*__real_sigprocmask) (int how, const sigset_t *set,
    124  1.1.1.2  christos 				  sigset_t *oldset) = NULL;
    125  1.1.1.2  christos static int (*__real_thr_sigsetmask) (int how, const sigset_t *iset,
    126  1.1.1.2  christos 				     sigset_t *oset) = NULL;
    127  1.1.1.2  christos static int (*__real_pthread_sigmask) (int how, const sigset_t *set,
    128  1.1.1.2  christos 				      sigset_t *oldset) = NULL;
    129  1.1.1.2  christos static int (*__real_pthread_create) (pthread_t *thread,
    130  1.1.1.2  christos 			const pthread_attr_t *attr,
    131  1.1.1.2  christos 			void *(*start_routine) (void *), void *arg) = NULL;
    132      1.1  christos 
    133      1.1  christos /*
    134      1.1  christos  * void collector_sigprof_dispatcher()
    135      1.1  christos  *
    136      1.1  christos  * Common SIGPROF event handler which dispatches events to appropriate
    137      1.1  christos  * module handlers, if they are active for this collection and due.
    138      1.1  christos  * Dispatch sequence, logic and handlers currently hardcoded in dispatcher.
    139      1.1  christos  */
    140      1.1  christos static void
    141      1.1  christos collector_sigprof_dispatcher (int sig, siginfo_t *info, void *context)
    142      1.1  christos {
    143      1.1  christos   if (info == NULL || (info->si_code <= 0 && info->si_code != SI_TIMER))
    144      1.1  christos     {
    145      1.1  christos       TprintfT (DBG_LT2, "collector_sigprof_dispatcher signal for %p\n",
    146      1.1  christos 		original_sigprof_handler.sa_handler);
    147      1.1  christos       /* pass signal to previous handler */
    148      1.1  christos       /* watch for recursion, SIG_IGN, and SIG_DFL */
    149      1.1  christos       if (original_sigprof_handler.sa_handler == SIG_DFL)
    150      1.1  christos 	__collector_SIGDFL_handler (SIGPROF);
    151      1.1  christos       else if (original_sigprof_handler.sa_handler != SIG_IGN &&
    152      1.1  christos 	       original_sigprof_handler.sa_sigaction != &collector_sigprof_dispatcher)
    153      1.1  christos 	{
    154      1.1  christos 	  (original_sigprof_handler.sa_sigaction)(sig, info, context);
    155      1.1  christos 	  TprintfT (DBG_LT2, "collector_sigprof_dispatcher handled\n");
    156      1.1  christos 	}
    157      1.1  christos     }
    158      1.1  christos   else if (dispatch_mode == DISPATCH_ON)
    159      1.1  christos     {
    160      1.1  christos #if ARCH(SPARC)
    161      1.1  christos       ucontext_t uctxmem;
    162      1.1  christos       ucontext_t *uctx = &uctxmem;
    163      1.1  christos       uctx->uc_link = NULL;
    164      1.1  christos       /* 23340823 signal handler third argument should point to a ucontext_t */
    165      1.1  christos       /* Convert sigcontext to ucontext_t on sparc-Linux */
    166      1.1  christos       struct sigcontext *sctx = (struct sigcontext*) context;
    167      1.1  christos #if WSIZE(32)
    168      1.1  christos       uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
    169      1.1  christos       __collector_memcpy (&uctx->uc_mcontext.gregs[3],
    170      1.1  christos 			  sctx->si_regs.u_regs,
    171      1.1  christos 			  sizeof (sctx->si_regs.u_regs));
    172      1.1  christos #else
    173      1.1  christos       uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
    174      1.1  christos       __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
    175      1.1  christos 			  sctx->sigc_regs.u_regs,
    176      1.1  christos 			  sizeof (sctx->sigc_regs.u_regs));
    177      1.1  christos #endif /* WSIZE() */
    178      1.1  christos 
    179      1.1  christos #else /* not sparc-Linux */
    180      1.1  christos       ucontext_t *uctx = (ucontext_t*) context;
    181      1.1  christos #endif /* ARCH() */
    182      1.1  christos       TprintfT (DBG_LT3, "collector_sigprof_dispatcher dispatching signal\n");
    183      1.1  christos 
    184      1.1  christos       /* XXXX the order of these checks/activities may need adjustment */
    185      1.1  christos       /* XXXX should also check (first) for a "cached" manual sample */
    186      1.1  christos       /* HWC check for each LWP: required even if collection is paused */
    187      1.1  christos       /* This should be first, otherwise it's likely to find the counters
    188      1.1  christos        * stopped due to an event/overflow during some of the other activities.
    189      1.1  christos        */
    190      1.1  christos       /* XXXX HWC check performed every time (skipping if HWC profiling inactive)
    191      1.1  christos        * to avoid complexity of maintaining separate check times for each LWP
    192      1.1  christos        */
    193      1.1  christos       __collector_ext_hwc_check (info, uctx);
    194      1.1  christos 
    195      1.1  christos       /* XXXX if sigemtpending, should perhaps skip __collector_ext_usage_sample
    196      1.1  christos        * (and get it next time through)
    197      1.1  christos        */
    198      1.1  christos 
    199      1.1  christos       /* check for experiment past delay start */
    200      1.1  christos       if (__collector_delay_start != 0)
    201      1.1  christos 	{
    202      1.1  christos 	  hrtime_t now = __collector_gethrtime ();
    203      1.1  christos 	  if (__collector_delay_start < now)
    204      1.1  christos 	    {
    205      1.1  christos 	      TprintfT (0, "__collector_ext_usage_sample: now (%lld) > delay_start (%lld)\n",
    206      1.1  christos 			(now - __collector_start_time), (__collector_delay_start - __collector_start_time));
    207      1.1  christos 
    208      1.1  christos 	      /* resume the data collection */
    209      1.1  christos 	      __collector_delay_start = 0;
    210      1.1  christos 	      __collector_resume ();
    211      1.1  christos 
    212      1.1  christos 	      /* don't take a periodic sample, just let the resume sample cover it */
    213      1.1  christos 	      if (__collector_sample_period != 0)
    214      1.1  christos 		{
    215      1.1  christos 		  /* this update should only be done for periodic samples */
    216      1.1  christos 		  while (__collector_next_sample < now)
    217      1.1  christos 		    __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
    218      1.1  christos 		}
    219      1.1  christos 	      /* return; */
    220      1.1  christos 	    }
    221      1.1  christos 	}
    222      1.1  christos       /* check for periodic sampling */
    223      1.1  christos       if (__collector_gethrtime () > __collector_next_sample)
    224      1.1  christos 	__collector_ext_usage_sample (PERIOD_SMPL, "periodic");
    225      1.1  christos 
    226      1.1  christos       /* check for experiment past termination time */
    227      1.1  christos       if (__collector_exp_active && __collector_terminate_time != 0)
    228      1.1  christos 	{
    229      1.1  christos 	  hrtime_t now = __collector_gethrtime ();
    230      1.1  christos 	  if (__collector_terminate_time < now)
    231      1.1  christos 	    {
    232      1.1  christos 	      TprintfT (0, "__collector_ext_usage_sample: now (%lld) > terminate_time (%lld); closing experiment\n",
    233      1.1  christos 			(now - __collector_start_time), (__collector_terminate_time - __collector_start_time));
    234      1.1  christos 	      /* close the experiment */
    235      1.1  christos 	      __collector_close_experiment ();
    236      1.1  christos 	    }
    237      1.1  christos 	}
    238      1.1  christos 
    239      1.1  christos       /* call the code to process the profile data, and generate the packet */
    240      1.1  christos       /* (must always be called, otherwise profile data must be aggregated,
    241      1.1  christos        * but can be left till last, as already have the required data)
    242      1.1  christos        */
    243      1.1  christos       __collector_ext_profile_handler (info, uctx);
    244      1.1  christos     }
    245      1.1  christos   else if (dispatch_mode == DISPATCH_TST)
    246      1.1  christos     {
    247      1.1  christos       collector_sigprof_entries++;
    248      1.1  christos       return;
    249      1.1  christos     }
    250      1.1  christos }
    251      1.1  christos 
    252      1.1  christos /*
    253      1.1  christos  *  __collector_sigprof_install
    254      1.1  christos  */
    255      1.1  christos int
    256      1.1  christos __collector_sigprof_install ()
    257      1.1  christos {
    258      1.1  christos   TprintfT (DBG_LT2, "__collector_sigprof_install\n");
    259      1.1  christos   struct sigaction oact;
    260      1.1  christos   if (__collector_sigaction (SIGPROF, NULL, &oact) != 0)
    261      1.1  christos     return COL_ERROR_DISPINIT;
    262      1.1  christos   if (oact.sa_sigaction == collector_sigprof_dispatcher)
    263      1.1  christos     /* signal handler is already in place; we are probably in a fork-child */
    264      1.1  christos     TprintfT (DBG_LT1, "dispatcher: __collector_ext_dispatcher_install() collector_sigprof_dispatcher already installed\n");
    265      1.1  christos   else
    266      1.1  christos     {
    267  1.1.1.3  christos       struct sigaction c_act = sigaction_0;
    268      1.1  christos       sigemptyset (&c_act.sa_mask);
    269      1.1  christos       sigaddset (&c_act.sa_mask, HWCFUNCS_SIGNAL); /* block SIGEMT delivery in handler */
    270      1.1  christos       c_act.sa_sigaction = collector_sigprof_dispatcher;
    271      1.1  christos       c_act.sa_flags = SA_RESTART | SA_SIGINFO;
    272      1.1  christos       if (__collector_sigaction (SIGPROF, &c_act, &original_sigprof_handler))
    273      1.1  christos 	return COL_ERROR_DISPINIT;
    274      1.1  christos     }
    275      1.1  christos   dispatch_mode = DISPATCH_OFF; /* don't dispatch yet */
    276      1.1  christos   TprintfT (DBG_LT2, "__collector_sigprof_install done\n");
    277      1.1  christos   return COL_ERROR_NONE;
    278      1.1  christos }
    279      1.1  christos 
    280      1.1  christos /*
    281      1.1  christos  * void __collector_ext_dispatcher_tsd_create_key()
    282      1.1  christos  *
    283      1.1  christos  * create tsd key for dispatcher
    284      1.1  christos  */
    285      1.1  christos void
    286      1.1  christos __collector_ext_dispatcher_tsd_create_key ()
    287      1.1  christos {
    288      1.1  christos   dispatcher_key = __collector_tsd_create_key (sizeof (timer_t), NULL, NULL);
    289      1.1  christos }
    290      1.1  christos /*
    291      1.1  christos  * int __collector_ext_dispatcher_install()
    292      1.1  christos  *
    293      1.1  christos  * installs a common handler/dispatcher (and itimer) for SIGPROF events
    294      1.1  christos  */
    295      1.1  christos int
    296      1.1  christos __collector_ext_dispatcher_install ()
    297      1.1  christos {
    298      1.1  christos   int timer_period;
    299      1.1  christos   TprintfT (DBG_LT2, "__collector_ext_dispatcher_install\n");
    300      1.1  christos 
    301      1.1  christos   /* check period set for interval timer, which will be used as the basis
    302      1.1  christos    * for all timed activities: if not set, no role for SIGPROF dispatcher
    303      1.1  christos    */
    304      1.1  christos   if (itimer_period_requested <= 0)
    305      1.1  christos     {
    306      1.1  christos       TprintfT (DBG_LT1, "No interval timer set: skipping dispatcher install!\n");
    307      1.1  christos       return COL_ERROR_NONE; /* no itimer/dispatcher required */
    308      1.1  christos     }
    309      1.1  christos 
    310      1.1  christos   /* check for an existing interval timer */
    311      1.1  christos   if (collector_master_thread_timerid == NULL)
    312      1.1  christos     if (collector_timer_create (&collector_master_thread_timerid) < 0)
    313      1.1  christos       return COL_ERROR_ITMRINIT;
    314      1.1  christos   timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
    315      1.1  christos   if (timeridptr != NULL)
    316      1.1  christos     *timeridptr = collector_master_thread_timerid; // store for per thread timer stop/start
    317      1.1  christos   TprintfT (DBG_LT3, "__collector_ext_dispatcher_install: collector_master_thread_timerid=%p\n",
    318      1.1  christos 	    collector_master_thread_timerid);
    319      1.1  christos   timer_period = collector_timer_gettime (collector_master_thread_timerid);
    320      1.1  christos   if (timer_period > 0)
    321      1.1  christos     {
    322      1.1  christos       TprintfT (DBG_LT1, "Overriding app-set interval timer with period %d\n", timer_period);
    323      1.1  christos       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d->%d</event>\n",
    324      1.1  christos 				    SP_JCMD_CWARN, COL_WARN_ITMRPOVR, timer_period, itimer_period_requested);
    325      1.1  christos     }
    326      1.1  christos   /* install the interval timer used for all timed activities */
    327      1.1  christos   if (collector_timer_settime (itimer_period_requested, collector_master_thread_timerid) < 0)
    328      1.1  christos     return COL_ERROR_ITMRINIT;
    329      1.1  christos   TprintfT (DBG_LT2, "__collector_ext_dispatcher_install done\n");
    330      1.1  christos   dispatch_mode = DISPATCH_ON; /* activate SIGPROF dispatch to event handlers */
    331      1.1  christos   return COL_ERROR_NONE;
    332      1.1  christos }
    333      1.1  christos 
    334      1.1  christos int
    335      1.1  christos __collector_sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
    336      1.1  christos {
    337      1.1  christos   TprintfT (DBG_LT1, "__collector_sigaction: %d, %p\n", sig, nact ? nact->sa_sigaction : NULL);
    338      1.1  christos   if (NULL_PTR (sigaction))
    339      1.1  christos     init_interposition_intf ();
    340      1.1  christos 
    341      1.1  christos   /* Whether we change the signal handler in the kernel
    342      1.1  christos    * or not make sure the real sigaction is aware about
    343      1.1  christos    * our new handler (6227565)
    344      1.1  christos    */
    345      1.1  christos   return CALL_REAL (sigaction)(sig, nact, oact);
    346      1.1  christos }
    347      1.1  christos 
    348      1.1  christos /*
    349      1.1  christos  * We have special dispatchers for SIGPROF and HWCFUNCS_SIGNAL to
    350      1.1  christos  * decide whether the signal was intended for us or for the user.
    351      1.1  christos  * One special case is SIGDFL, in which case we don't have a
    352      1.1  christos  * user-function address to call.  If the user did indeed set
    353      1.1  christos  * default disposition for one of these signals and sent that
    354      1.1  christos  * signal, we honor that action, even though it will lead to
    355      1.1  christos  * termination.
    356      1.1  christos  */
    357      1.1  christos void
    358      1.1  christos __collector_SIGDFL_handler (int sig)
    359      1.1  christos {
    360      1.1  christos   /* remove our dispatcher, replacing it with the default disposition */
    361  1.1.1.3  christos   struct sigaction act =  sigaction_0;
    362      1.1  christos   act.sa_handler = SIG_DFL;
    363      1.1  christos   if (__collector_sigaction (sig, &act, NULL))
    364      1.1  christos     {
    365      1.1  christos       /* XXXXXX what are we supposed to do here? we're committing suicide anyhow */
    366      1.1  christos     }
    367      1.1  christos   /* resend the signal we intercepted earlier */
    368      1.1  christos   // XXXX Bug 18177509 - additional sigprof signal kills target program
    369      1.1  christos   kill (getpid (), sig);
    370      1.1  christos }
    371      1.1  christos 
    372      1.1  christos /*
    373      1.1  christos  * suspend/resume timer per thread
    374      1.1  christos  */
    375      1.1  christos void
    376      1.1  christos __collector_ext_dispatcher_thread_timer_suspend ()
    377      1.1  christos {
    378      1.1  christos   timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
    379      1.1  christos   if (timeridptr != NULL && *timeridptr != NULL)
    380      1.1  christos     (void) collector_timer_settime (0, *timeridptr);
    381      1.1  christos   return;
    382      1.1  christos }
    383      1.1  christos 
    384      1.1  christos int
    385      1.1  christos __collector_ext_dispatcher_thread_timer_resume ()
    386      1.1  christos {
    387      1.1  christos   timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
    388      1.1  christos   if (timeridptr == NULL)
    389      1.1  christos     return -1;
    390      1.1  christos   if (*timeridptr == NULL)
    391      1.1  christos     { // timer id not initialized yet
    392      1.1  christos       TprintfT (DBG_LT2, "__collector_ext_dispatcher_thread_timer_resume: timer not initialized yet, create it\n");
    393      1.1  christos       if (collector_timer_create (timeridptr) == -1)
    394      1.1  christos 	{
    395      1.1  christos 	  TprintfT (0, "__collector_ext_dispatcher_thread_timer_resume(): WARNING: No timer created\n");
    396      1.1  christos 	  return -1;
    397      1.1  christos 	}
    398      1.1  christos     }
    399      1.1  christos   return collector_timer_settime (itimer_period_requested, *timeridptr);
    400      1.1  christos }
    401      1.1  christos 
    402      1.1  christos void
    403      1.1  christos __collector_ext_dispatcher_suspend ()
    404      1.1  christos {
    405      1.1  christos   TprintfT (DBG_LT2, "__collector_ext_dispatcher_suspend\n");
    406      1.1  christos   if (dispatch_mode == DISPATCH_NYI)
    407      1.1  christos     {
    408      1.1  christos       TprintfT (0, "__collector_ext_dispatcher_suspend(): WARNING: No dispatcher installed\n");
    409      1.1  christos       return;
    410      1.1  christos     }
    411      1.1  christos 
    412      1.1  christos   /* disable SIGPROF dispatching */
    413      1.1  christos   dispatch_mode = DISPATCH_OFF;
    414      1.1  christos 
    415      1.1  christos   /* disable the interval timer; ignore any failures */
    416      1.1  christos   __collector_ext_dispatcher_thread_timer_suspend ();
    417      1.1  christos   return;
    418      1.1  christos }
    419      1.1  christos 
    420      1.1  christos void
    421      1.1  christos __collector_ext_dispatcher_restart ()
    422      1.1  christos {
    423      1.1  christos   TprintfT (DBG_LT2, "__collector_ext_dispatcher_restart(ip=%d)\n", itimer_period_requested);
    424      1.1  christos   if (dispatch_mode == DISPATCH_NYI)
    425      1.1  christos     {
    426      1.1  christos       TprintfT (0, "__collector_ext_dispatcher_restart(): WARNING: No dispatcher installed\n");
    427      1.1  christos       return;
    428      1.1  christos     }
    429      1.1  christos 
    430      1.1  christos   /* restart the interval timer used for all timed activities */
    431      1.1  christos   if (__collector_ext_dispatcher_thread_timer_resume () == 0)
    432      1.1  christos     dispatch_mode = DISPATCH_ON; /* re-activate SIGPROF dispatch to handlers */
    433      1.1  christos   return;
    434      1.1  christos }
    435      1.1  christos /*
    436      1.1  christos  * void __collector_ext_dispatcher_deinstall()
    437      1.1  christos  *
    438      1.1  christos  * If installed, disables SIGPROF dispatch and interval timer.
    439      1.1  christos  * Includes checks for last SIGPROF dispatch time, interval timer period,
    440      1.1  christos  * and currently installed SIGPROF handler, with appropriate warnings logged.
    441      1.1  christos  * The dispatcher remains installed to handle pending collector SIGPROFs and
    442      1.1  christos  * forward non-collector SIGPROFs to the application's handler(s).
    443      1.1  christos  * If the decision is ever made actually to deinstall the dispatcher,
    444      1.1  christos  * consider bug 4183714 and what to do about any possible pending
    445      1.1  christos  * SIGPROFs.
    446      1.1  christos  */
    447      1.1  christos 
    448      1.1  christos void
    449      1.1  christos __collector_ext_dispatcher_deinstall ()
    450      1.1  christos {
    451      1.1  christos   TprintfT (DBG_LT1, "__collector_ext_dispatcher_deinstall()\n");
    452      1.1  christos   if (dispatch_mode == DISPATCH_NYI)
    453      1.1  christos     {
    454      1.1  christos       TprintfT (0, "__collector_ext_dispatcher_deinstall(): WARNING: No dispatcher installed\n");
    455      1.1  christos       return;
    456      1.1  christos     }
    457      1.1  christos   dispatch_mode = DISPATCH_OFF; /* disable SIGPROF dispatching */
    458      1.1  christos 
    459      1.1  christos   /* verify that interval timer is still installed with expected period */
    460      1.1  christos   int timer_period = collector_timer_gettime (collector_master_thread_timerid);
    461      1.1  christos   if (timer_period != itimer_period_actual)
    462      1.1  christos     {
    463      1.1  christos       TprintfT (DBG_LT2, "dispatcher: Collector interval timer period changed %d -> %d\n",
    464      1.1  christos 		itimer_period_actual, timer_period);
    465      1.1  christos       if ((itimer_period_actual >= (timer_period + timer_period / 10)) ||
    466      1.1  christos 	  (itimer_period_actual <= (timer_period - timer_period / 10)))
    467      1.1  christos 	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
    468      1.1  christos 			       SP_JCMD_CWARN, COL_WARN_ITMRREP,
    469      1.1  christos 			       itimer_period_actual, timer_period);
    470      1.1  christos       else
    471      1.1  christos 	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
    472      1.1  christos 			       SP_JCMD_COMMENT, COL_WARN_PROFRND,
    473      1.1  christos 			       itimer_period_actual, timer_period);
    474      1.1  christos     }
    475      1.1  christos 
    476      1.1  christos   /* Verify that SIGPROF dispatcher is still installed.
    477      1.1  christos    * (still required with sigaction interposition and management,
    478      1.1  christos    * since interposition is not done for attach experiments)
    479      1.1  christos    */
    480      1.1  christos   struct sigaction curr;
    481      1.1  christos   if (__collector_sigaction (SIGPROF, NULL, &curr) == -1)
    482      1.1  christos     TprintfT (0, "ERROR: dispatcher sigaction check failed: errno=%d\n", errno);
    483      1.1  christos   else if (curr.sa_sigaction != collector_sigprof_dispatcher)
    484      1.1  christos     {
    485      1.1  christos       TprintfT (0, "ERROR: collector dispatcher replaced by %p!\n", curr.sa_handler);
    486      1.1  christos       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%p</event>\n",
    487      1.1  christos 				    SP_JCMD_CWARN, COL_WARN_SIGPROF, curr.sa_handler);
    488      1.1  christos     }
    489      1.1  christos   else
    490      1.1  christos     TprintfT (DBG_LT2, "collector dispatcher integrity verified!\n");
    491      1.1  christos 
    492      1.1  christos   /* disable the interval timer; ignore any failures */
    493      1.1  christos   if (collector_master_thread_timerid != NULL)
    494      1.1  christos     {
    495      1.1  christos       (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
    496      1.1  christos       collector_master_thread_timerid = NULL;
    497      1.1  christos     }
    498      1.1  christos   dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
    499      1.1  christos   itimer_period_requested = 0;
    500      1.1  christos   itimer_period_actual = 0;
    501      1.1  christos }
    502      1.1  christos 
    503      1.1  christos /*
    504      1.1  christos  * void __collector_ext_dispatcher_fork_child_cleanup()
    505      1.1  christos  *
    506      1.1  christos  * delete timer, clear timer interval
    507      1.1  christos  */
    508      1.1  christos void
    509      1.1  christos __collector_ext_dispatcher_fork_child_cleanup ()
    510      1.1  christos {
    511      1.1  christos   if (collector_master_thread_timerid != NULL)
    512      1.1  christos     {
    513      1.1  christos       (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
    514      1.1  christos       collector_master_thread_timerid = NULL;
    515      1.1  christos     }
    516      1.1  christos   __collector_mutex_init (&collector_clone_libc_lock);
    517      1.1  christos   dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
    518      1.1  christos   itimer_period_requested = 0;
    519      1.1  christos   itimer_period_actual = 0;
    520      1.1  christos }
    521      1.1  christos /*
    522      1.1  christos  * int __collector_ext_itimer_set (int rperiod)
    523      1.1  christos  *
    524      1.1  christos  * set itimer period, if not yet set to a positive number of microseconds,
    525      1.1  christos  * (after rounding to sys_resolution if necessary) and return its value
    526      1.1  christos  */
    527      1.1  christos int
    528      1.1  christos __collector_ext_itimer_set (int rperiod)
    529      1.1  christos {
    530      1.1  christos   int period;
    531      1.1  christos   /* if rperiod is negative, force setting */
    532      1.1  christos   if (rperiod < 0)
    533      1.1  christos     {
    534      1.1  christos       itimer_period_actual = 0;
    535      1.1  christos       period = -rperiod;
    536      1.1  christos     }
    537      1.1  christos   else
    538      1.1  christos     period = rperiod;
    539      1.1  christos 
    540      1.1  christos   // ignore SIGPROF while testing itimer interval setting
    541      1.1  christos   int saved = dispatch_mode;
    542      1.1  christos   dispatch_mode = DISPATCH_OFF;
    543      1.1  christos   if (collector_timer_create (&collector_master_thread_timerid) == -1)
    544      1.1  christos     {
    545      1.1  christos       TprintfT (0, "__collector_ext_itimer_set(): WARNING: No timer created\n");
    546      1.1  christos       return itimer_period_actual;
    547      1.1  christos     }
    548      1.1  christos   if (collector_timer_settime (period, collector_master_thread_timerid) == 0)
    549      1.1  christos     {
    550      1.1  christos       itimer_period_actual = collector_timer_gettime (collector_master_thread_timerid);
    551      1.1  christos       (void) collector_timer_settime (0, collector_master_thread_timerid); /* XXXX unset for now */
    552      1.1  christos       itimer_period_requested = period;
    553      1.1  christos       if (itimer_period_requested != itimer_period_actual)
    554      1.1  christos 	{
    555      1.1  christos 	  TprintfT (DBG_LT2, "    itimer period %d adjusted to %d\n",
    556      1.1  christos 		    itimer_period_requested, itimer_period_actual);
    557      1.1  christos 	  // (void) __collector_log_write("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
    558      1.1  christos 	  //     SP_JCMD_CWARN, COL_WARN_PROFRND, itimer_period_requested, itimer_period_actual);
    559      1.1  christos 	}
    560      1.1  christos       else
    561      1.1  christos 	TprintfT (DBG_LT2, "    itimer period %d accepted\n", period);
    562      1.1  christos     }
    563      1.1  christos 
    564      1.1  christos   // restore dispatching SIGPROF handler
    565      1.1  christos   dispatch_mode = saved;
    566      1.1  christos   TprintfT (0, "__collector_ext_itimer_set(%d), requested=%d, actual=%d)\n",
    567      1.1  christos 	    rperiod, itimer_period_requested, itimer_period_actual);
    568      1.1  christos   return (itimer_period_actual);
    569      1.1  christos }
    570      1.1  christos 
    571      1.1  christos static int
    572      1.1  christos collector_timer_gettime (timer_t timerid)
    573      1.1  christos {
    574      1.1  christos   int timer_period;
    575      1.1  christos   struct itimerspec itimer;
    576      1.1  christos   if (timerid == NULL)
    577      1.1  christos     return (0); // timer was not initialized
    578      1.1  christos   if (CALL_REAL (timer_gettime)(timerid, &itimer) == -1)
    579      1.1  christos     {
    580      1.1  christos       /* this should never reasonably fail, so not worth logging */
    581      1.1  christos       TprintfT (DBG_LT1, "WARNING: timer_gettime failed: errno=%d\n", errno);
    582      1.1  christos       return (-1);
    583      1.1  christos     }
    584      1.1  christos   timer_period = ((itimer.it_interval.tv_sec * NANOSEC) +
    585      1.1  christos 		  itimer.it_interval.tv_nsec) / 1000;
    586      1.1  christos   TprintfT (DBG_LT2, "collector_timer_gettime (period=%d)\n", timer_period);
    587      1.1  christos   return (timer_period);
    588      1.1  christos }
    589      1.1  christos 
    590      1.1  christos static int
    591      1.1  christos collector_timer_create (timer_t * ptimerid)
    592      1.1  christos {
    593      1.1  christos   struct sigevent sigev;
    594      1.1  christos   if (NULL_PTR (timer_create))
    595      1.1  christos     init_interposition_intf ();
    596      1.1  christos   TprintfT (DBG_LT2, "collector_timer_settime(): timer_create is %p\n", __real_timer_create);
    597      1.1  christos   sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
    598      1.1  christos   sigev.sigev_signo = SIGPROF;
    599      1.1  christos   sigev.sigev_value.sival_ptr = ptimerid;
    600  1.1.1.2  christos #if !defined(__MUSL_LIBC)
    601      1.1  christos   sigev._sigev_un._tid = __collector_gettid ();
    602  1.1.1.2  christos #endif
    603      1.1  christos   if (CALL_REAL (timer_create)(CLOCK_THREAD_CPUTIME_ID, &sigev, ptimerid) == -1)
    604      1.1  christos     {
    605      1.1  christos       TprintfT (DBG_LT2, "collector_timer_settime() failed! errno=%d\n", errno);
    606      1.1  christos       return -1;
    607      1.1  christos     }
    608      1.1  christos   return 0;
    609      1.1  christos }
    610      1.1  christos 
    611      1.1  christos static int
    612      1.1  christos collector_timer_settime (int period, timer_t timerid)
    613      1.1  christos {
    614      1.1  christos   struct itimerspec itimer;
    615      1.1  christos   if (NULL_PTR (timer_settime))
    616      1.1  christos     init_interposition_intf ();
    617      1.1  christos   TprintfT (DBG_LT2, "collector_timer_settime(period=%d)\n", period);
    618      1.1  christos   time_t NPM = 1000;
    619      1.1  christos   itimer.it_interval.tv_sec = NPM * period / NANOSEC;
    620      1.1  christos   itimer.it_interval.tv_nsec = (NPM * period) % NANOSEC;
    621      1.1  christos   itimer.it_value = itimer.it_interval;
    622      1.1  christos   if (CALL_REAL (timer_settime)(timerid, 0, &itimer, NULL) == -1)
    623      1.1  christos     {
    624      1.1  christos       TprintfT (DBG_LT2, "collector_timer_settime(%d) failed! errno=%d\n", period, errno);
    625      1.1  christos       return -1;
    626      1.1  christos     }
    627      1.1  christos   return 0;
    628      1.1  christos }
    629      1.1  christos 
    630      1.1  christos static void
    631      1.1  christos protect_profiling_signals (sigset_t* lset)
    632      1.1  christos {
    633      1.1  christos   static unsigned int protected_sigprof = 0;
    634      1.1  christos   static unsigned int protected_sigemt = 0;
    635      1.1  christos   // T1 relies on thread signal masking, so best not to mess with it:
    636      1.1  christos   // T1 users have already been warned about the dangers of its use
    637      1.1  christos   if (__collector_libthread_T1)
    638      1.1  christos     return;
    639      1.1  christos   if (sigismember (lset, SIGPROF) && (dispatch_mode == DISPATCH_ON))
    640      1.1  christos     {
    641      1.1  christos       TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGPROF");
    642      1.1  christos       if (protected_sigprof == 0)
    643      1.1  christos 	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
    644      1.1  christos 			       SP_JCMD_CWARN, COL_WARN_SIGMASK, "SIGPROF");
    645      1.1  christos       sigdelset (lset, SIGPROF);
    646      1.1  christos       protected_sigprof++;
    647      1.1  christos     }
    648      1.1  christos   if (sigismember (lset, HWCFUNCS_SIGNAL) && __collector_ext_hwc_active ())
    649      1.1  christos     {
    650      1.1  christos       TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGEMT");
    651      1.1  christos       if (protected_sigemt == 0)
    652      1.1  christos 	__collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
    653      1.1  christos 			       SP_JCMD_CWARN, COL_WARN_SIGMASK, HWCFUNCS_SIGNAL_STRING);
    654      1.1  christos       sigdelset (lset, HWCFUNCS_SIGNAL);
    655      1.1  christos       protected_sigemt++;
    656      1.1  christos     }
    657      1.1  christos }
    658      1.1  christos 
    659      1.1  christos static int
    660      1.1  christos init_interposition_intf ()
    661      1.1  christos {
    662      1.1  christos   if (__collector_dlsym_guard)
    663      1.1  christos     return 1;
    664      1.1  christos   void *dlflag;
    665      1.1  christos   /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
    666      1.1  christos   void *handle = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD);
    667      1.1  christos 
    668  1.1.1.2  christos   __real_setitimer = dlsym (RTLD_NEXT, "setitimer");
    669      1.1  christos   if (__real_setitimer == NULL)
    670      1.1  christos     {
    671  1.1.1.2  christos       __real_setitimer = dlsym (RTLD_DEFAULT, "setitimer");
    672      1.1  christos       if (__real_setitimer == NULL)
    673      1.1  christos 	{
    674      1.1  christos 	  TprintfT (DBG_LT2, "init_interposition_intf() setitimer not found\n");
    675      1.1  christos 	  return 1;
    676      1.1  christos 	}
    677      1.1  christos       dlflag = RTLD_DEFAULT;
    678      1.1  christos     }
    679      1.1  christos   else
    680      1.1  christos     dlflag = RTLD_NEXT;
    681      1.1  christos 
    682      1.1  christos   TprintfT (DBG_LT2, "init_interposition_intf() using RTLD_%s\n",
    683      1.1  christos 	    (dlflag == RTLD_DEFAULT) ? "DEFAULT" : "NEXT");
    684      1.1  christos 
    685  1.1.1.2  christos   __real_sigaction = dlsym (dlflag, "sigaction");
    686      1.1  christos 
    687      1.1  christos   /* also explicitly get libc.so/setitimer (as a backup) */
    688  1.1.1.2  christos   __real_libc_setitimer = dlsym (handle, "setitimer");
    689      1.1  christos 
    690  1.1.1.2  christos   __real_sigprocmask = dlsym (dlflag, "sigprocmask");
    691  1.1.1.2  christos   __real_thr_sigsetmask = dlsym (dlflag, "thr_sigsetmask");
    692      1.1  christos 
    693  1.1.1.2  christos   __real_pthread_sigmask_2_32 = dlvsym (dlflag, "pthread_sigmask", "GLIBC_2.32");
    694  1.1.1.2  christos   __real_pthread_sigmask_2_17 = dlvsym (dlflag, "pthread_sigmask", "GLIBC_2.17");
    695  1.1.1.2  christos   __real_pthread_sigmask_2_2_5 = dlvsym (dlflag, "pthread_sigmask", "GLIBC_2.2.5");
    696  1.1.1.2  christos   __real_pthread_sigmask_2_0 = dlvsym (dlflag, "pthread_sigmask", "GLIBC_2.0");
    697  1.1.1.2  christos   if (__real_pthread_sigmask_2_32)
    698  1.1.1.2  christos     __real_pthread_sigmask = __real_pthread_sigmask_2_32;
    699  1.1.1.2  christos   else if (__real_pthread_sigmask_2_17)
    700  1.1.1.2  christos     __real_pthread_sigmask = __real_pthread_sigmask_2_17;
    701  1.1.1.2  christos   else if (__real_pthread_sigmask_2_2_5)
    702  1.1.1.2  christos     __real_pthread_sigmask = __real_pthread_sigmask_2_2_5;
    703  1.1.1.2  christos   else if (__real_pthread_sigmask_2_0)
    704  1.1.1.2  christos     __real_pthread_sigmask = __real_pthread_sigmask_2_0;
    705  1.1.1.2  christos   else
    706  1.1.1.2  christos     __real_pthread_sigmask = dlsym (dlflag, "pthread_sigmask");
    707      1.1  christos 
    708  1.1.1.2  christos   __real_pthread_create_2_34 = dlvsym (dlflag, "pthread_create", "GLIBC_2.34");
    709  1.1.1.2  christos   __real_pthread_create_2_17 = dlvsym (dlflag, "pthread_create", "GLIBC_2.17");
    710  1.1.1.2  christos   __real_pthread_create_2_2_5 = dlvsym (dlflag, "pthread_create", "GLIBC_2.2.5");
    711  1.1.1.2  christos   __real_pthread_create_2_1 = dlvsym (dlflag, "pthread_create", "GLIBC_2.1");
    712      1.1  christos   __real_pthread_create_2_0 = dlvsym (dlflag, "pthread_create", "GLIBC_2.0");
    713  1.1.1.2  christos   if (__real_pthread_create_2_34)
    714  1.1.1.2  christos     __real_pthread_create = __real_pthread_create_2_34;
    715  1.1.1.2  christos   else if (__real_pthread_create_2_17)
    716  1.1.1.2  christos     __real_pthread_create = __real_pthread_create_2_17;
    717  1.1.1.2  christos   else if (__real_pthread_create_2_2_5)
    718  1.1.1.2  christos     __real_pthread_create = __real_pthread_create_2_2_5;
    719  1.1.1.2  christos   else if (__real_pthread_create_2_1)
    720  1.1.1.2  christos     __real_pthread_create = __real_pthread_create_2_1;
    721  1.1.1.2  christos   else if (__real_pthread_create_2_0)
    722  1.1.1.2  christos     __real_pthread_create = __real_pthread_create_2_0;
    723  1.1.1.2  christos   else
    724  1.1.1.2  christos     __real_pthread_create = dlsym (dlflag, "pthread_create");
    725  1.1.1.2  christos 
    726  1.1.1.2  christos   __real_timer_create_2_34 = dlvsym (dlflag, "timer_create", "GLIBC_2.34");
    727  1.1.1.2  christos   __real_timer_create_2_17 = dlvsym (dlflag, "timer_create", "GLIBC_2.17");
    728  1.1.1.2  christos   __real_timer_create_2_3_3 = dlvsym (dlflag, "timer_create", "GLIBC_2.3.3");
    729      1.1  christos   __real_timer_create_2_2_5 = dlvsym (dlflag, "timer_create", "GLIBC_2.2.5");
    730      1.1  christos   __real_timer_create_2_2 = dlvsym (dlflag, "timer_create", "GLIBC_2.2");
    731  1.1.1.2  christos   if (__real_timer_create_2_34)
    732  1.1.1.2  christos     __real_timer_create = __real_timer_create_2_34;
    733  1.1.1.2  christos   else if (__real_timer_create_2_17)
    734  1.1.1.2  christos     __real_timer_create = __real_timer_create_2_17;
    735  1.1.1.2  christos   else if (__real_timer_create_2_3_3)
    736  1.1.1.2  christos     __real_timer_create = __real_timer_create_2_3_3;
    737  1.1.1.2  christos   else if (__real_timer_create_2_2_5)
    738  1.1.1.2  christos     __real_timer_create = __real_timer_create_2_2_5;
    739  1.1.1.2  christos   else if (__real_timer_create_2_2)
    740  1.1.1.2  christos     __real_timer_create = __real_timer_create_2_2;
    741  1.1.1.2  christos   else
    742  1.1.1.2  christos     __real_timer_create = dlsym (dlflag, "timer_create");
    743  1.1.1.2  christos 
    744  1.1.1.2  christos   void *t;
    745  1.1.1.2  christos   if ((t = dlvsym (dlflag, "timer_settime", "GLIBC_2.34")) != NULL)
    746  1.1.1.2  christos     __real_timer_settime = t;
    747  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_settime", "GLIBC_2.17")) != NULL)
    748  1.1.1.2  christos     __real_timer_settime = t;
    749  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_settime", "GLIBC_2.3.3")) != NULL)
    750  1.1.1.2  christos     __real_timer_settime = t;
    751  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_settime", "GLIBC_2.2.5")) != NULL)
    752  1.1.1.2  christos     __real_timer_settime = t;
    753  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_settime", "GLIBC_2.0")) != NULL)
    754  1.1.1.2  christos     __real_timer_settime = t;
    755  1.1.1.2  christos   else
    756  1.1.1.2  christos     __real_timer_settime = dlsym (dlflag, "timer_settime");
    757  1.1.1.2  christos 
    758  1.1.1.2  christos   if ((t = dlvsym (dlflag, "timer_delete", "GLIBC_2.34")) != NULL)
    759  1.1.1.2  christos     __real_timer_delete = t;
    760  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_delete", "GLIBC_2.17")) != NULL)
    761  1.1.1.2  christos     __real_timer_delete = t;
    762  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_delete", "GLIBC_2.3.3")) != NULL)
    763  1.1.1.2  christos     __real_timer_delete = t;
    764  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_delete", "GLIBC_2.2.5")) != NULL)
    765  1.1.1.2  christos     __real_timer_delete = t;
    766  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_delete", "GLIBC_2.2")) != NULL)
    767  1.1.1.2  christos     __real_timer_delete = t;
    768  1.1.1.2  christos   else
    769  1.1.1.2  christos     __real_timer_delete = dlsym (dlflag, "timer_delete");
    770  1.1.1.2  christos 
    771  1.1.1.2  christos   if ((t = dlvsym (dlflag, "timer_gettime", "GLIBC_2.34")) != NULL)
    772  1.1.1.2  christos     __real_timer_gettime = t;
    773  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_gettime", "GLIBC_2.17")) != NULL)
    774  1.1.1.2  christos     __real_timer_gettime = t;
    775  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_gettime", "GLIBC_2.3.3")) != NULL)
    776  1.1.1.2  christos     __real_timer_gettime = t;
    777  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_gettime", "GLIBC_2.2.5")) != NULL)
    778  1.1.1.2  christos     __real_timer_gettime = t;
    779  1.1.1.2  christos   else if ((t = dlvsym (dlflag, "timer_gettime", "GLIBC_2.0")) != NULL)
    780  1.1.1.2  christos     __real_timer_gettime = t;
    781  1.1.1.2  christos   else
    782  1.1.1.2  christos     __real_timer_gettime = dlsym (dlflag, "timer_gettime");
    783  1.1.1.2  christos 
    784  1.1.1.2  christos   __real_clone = dlsym (dlflag, "clone");
    785  1.1.1.2  christos 
    786  1.1.1.2  christos #define PR_FUNC(f)  TprintfT (DBG_LT2, " dispetcher.c: " #f ": @%p\n", f)
    787  1.1.1.2  christos   PR_FUNC (__real_clone);
    788  1.1.1.2  christos   PR_FUNC (__real_libc_setitimer);
    789  1.1.1.2  christos   PR_FUNC (__real_pthread_create);
    790  1.1.1.2  christos   PR_FUNC (__real_pthread_create_2_0);
    791  1.1.1.2  christos   PR_FUNC (__real_pthread_create_2_1);
    792  1.1.1.2  christos   PR_FUNC (__real_pthread_create_2_17);
    793  1.1.1.2  christos   PR_FUNC (__real_pthread_create_2_2_5);
    794  1.1.1.2  christos   PR_FUNC (__real_pthread_create_2_34);
    795  1.1.1.2  christos   PR_FUNC (__real_pthread_sigmask);
    796  1.1.1.2  christos   PR_FUNC (__real_pthread_sigmask_2_0);
    797  1.1.1.2  christos   PR_FUNC (__real_pthread_sigmask_2_2_5);
    798  1.1.1.2  christos   PR_FUNC (__real_pthread_sigmask_2_17);
    799  1.1.1.2  christos   PR_FUNC (__real_pthread_sigmask_2_32);
    800  1.1.1.2  christos   PR_FUNC (__real_setitimer);
    801  1.1.1.2  christos   PR_FUNC (__real_sigaction);
    802  1.1.1.2  christos   PR_FUNC (__real_sigprocmask);
    803  1.1.1.2  christos   PR_FUNC (__real_thr_sigsetmask);
    804  1.1.1.2  christos   PR_FUNC (__real_timer_create);
    805  1.1.1.2  christos   PR_FUNC (__real_timer_create_2_17);
    806  1.1.1.2  christos   PR_FUNC (__real_timer_create_2_2);
    807  1.1.1.2  christos   PR_FUNC (__real_timer_create_2_2_5);
    808  1.1.1.2  christos   PR_FUNC (__real_timer_create_2_3_3);
    809  1.1.1.2  christos   PR_FUNC (__real_timer_create_2_34);
    810  1.1.1.2  christos   PR_FUNC (__real_timer_delete);
    811  1.1.1.2  christos   PR_FUNC (__real_timer_gettime);
    812  1.1.1.2  christos   PR_FUNC (__real_timer_settime);
    813  1.1.1.2  christos 
    814      1.1  christos   return 0;
    815      1.1  christos }
    816      1.1  christos 
    817      1.1  christos 
    818      1.1  christos /*------------------------------------------------------------- sigaction */
    819      1.1  christos 
    820      1.1  christos /* NB: need a global interposing function called "sigaction" */
    821      1.1  christos int
    822      1.1  christos sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
    823      1.1  christos {
    824      1.1  christos   int ret = 0;
    825      1.1  christos   int err = 0;
    826      1.1  christos   if (NULL_PTR (sigaction))
    827      1.1  christos     err = init_interposition_intf ();
    828      1.1  christos   if (err)
    829      1.1  christos     return -1;
    830      1.1  christos   TprintfT (DBG_LT3, "sigaction(sig=%02d, nact=%p) interposing\n", sig, nact);
    831      1.1  christos   if (sig == SIGPROF && dispatch_mode != DISPATCH_NYI)
    832      1.1  christos     {
    833      1.1  christos       if (oact != NULL)
    834      1.1  christos 	{
    835      1.1  christos 	  oact->sa_handler = original_sigprof_handler.sa_handler;
    836      1.1  christos 	  oact->sa_mask = original_sigprof_handler.sa_mask;
    837      1.1  christos 	  oact->sa_flags = original_sigprof_handler.sa_flags;
    838      1.1  christos 	}
    839      1.1  christos       if (nact != NULL)
    840      1.1  christos 	{
    841      1.1  christos 	  original_sigprof_handler.sa_handler = nact->sa_handler;
    842      1.1  christos 	  original_sigprof_handler.sa_mask = nact->sa_mask;
    843      1.1  christos 	  original_sigprof_handler.sa_flags = nact->sa_flags;
    844      1.1  christos 	  TprintfT (DBG_LT1, "dispatcher: new sigaction(sig=%02d) set\n", sig);
    845      1.1  christos 	}
    846      1.1  christos     }
    847      1.1  christos   else if (sig == HWCFUNCS_SIGNAL)
    848      1.1  christos     ret = collector_sigemt_sigaction (nact, oact);
    849      1.1  christos   else
    850      1.1  christos     {
    851      1.1  christos       if (sig != SIGCHLD || collector_sigchld_sigaction (nact, oact))
    852      1.1  christos 	ret = CALL_REAL (sigaction)(sig, nact, oact);
    853      1.1  christos       TprintfT (DBG_LT3, "Real sigaction(sig=%02d) returned %d (oact=%p)\n",
    854      1.1  christos 		sig, ret, oact);
    855      1.1  christos       /* but check for other important signals */
    856      1.1  christos       /* check for sample and pause/resume signals; give warning once, if need be */
    857      1.1  christos       if ((sig == __collector_sample_sig) && (__collector_sample_sig_warn == 0))
    858      1.1  christos 	{
    859      1.1  christos 	  /* give user a warning */
    860      1.1  christos 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
    861      1.1  christos 					SP_JCMD_CWARN, COL_WARN_SAMPSIGUSED, __collector_sample_sig);
    862      1.1  christos 	  __collector_sample_sig_warn = 1;
    863      1.1  christos 	}
    864      1.1  christos       if ((sig == __collector_pause_sig) && (__collector_pause_sig_warn == 0))
    865      1.1  christos 	{
    866      1.1  christos 	  /* give user a warning */
    867      1.1  christos 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
    868      1.1  christos 					SP_JCMD_CWARN, COL_WARN_PAUSESIGUSED, __collector_pause_sig);
    869      1.1  christos 	  __collector_pause_sig_warn = 1;
    870      1.1  christos 	}
    871      1.1  christos     }
    872      1.1  christos   TprintfT (DBG_LT3, "sigaction() returning %d (oact=%p)\n", ret, oact);
    873      1.1  christos   return ret;
    874      1.1  christos }
    875      1.1  christos 
    876      1.1  christos /*
    877      1.1  christos  * In addition to interposing on sigaction(), should we also interpose
    878      1.1  christos  * on other important signal functions like signal() or sigset()?
    879      1.1  christos  * - On Solaris, those other functions apparently call sigaction().
    880      1.1  christos  *   So, we only have to interpose on it.
    881      1.1  christos  * - On Linux, we should perhaps interpose on these other functions,
    882      1.1  christos  *   but they are less portable than sigaction() and deprecated or even obsolete.
    883      1.1  christos  *   So, we interpose, but don't overly worry about doing a good job.
    884      1.1  christos  */
    885      1.1  christos sighandler_t
    886      1.1  christos signal (int sig, sighandler_t handler)
    887      1.1  christos {
    888      1.1  christos   struct sigaction nact;
    889      1.1  christos   struct sigaction oact;
    890      1.1  christos   TprintfT (DBG_LT3, "signal(sig=%02d, handler=%p) interposing\n", sig, handler);
    891      1.1  christos   sigemptyset (&nact.sa_mask);
    892      1.1  christos   nact.sa_handler = handler;
    893      1.1  christos   nact.sa_flags = SA_RESTART;
    894      1.1  christos   if (sigaction (sig, &nact, &oact))
    895      1.1  christos     return SIG_ERR;
    896      1.1  christos   TprintfT (DBG_LT3, "signal() returning %p\n", oact.sa_handler);
    897      1.1  christos   return oact.sa_handler;
    898      1.1  christos }
    899      1.1  christos 
    900      1.1  christos sighandler_t
    901      1.1  christos sigset (int sig, sighandler_t handler)
    902      1.1  christos {
    903      1.1  christos   TprintfT (DBG_LT3, "sigset(sig=%02d, handler=%p) interposing\n", sig, handler);
    904      1.1  christos   return signal (sig, handler);
    905      1.1  christos }
    906      1.1  christos 
    907      1.1  christos /*------------------------------------------------------------- timer_create */
    908      1.1  christos 
    909      1.1  christos // map interposed symbol versions
    910      1.1  christos static int
    911  1.1.1.3  christos gprofng_timer_create (int (real_func) (clockid_t, struct sigevent *, timer_t *),
    912  1.1.1.3  christos 		      clockid_t clockid,
    913  1.1.1.3  christos 		      struct sigevent *sevp, timer_t *timerid)
    914      1.1  christos {
    915  1.1.1.2  christos   // collector reserves SIGPROF
    916  1.1.1.2  christos   if (sevp == NULL || sevp->sigev_notify != SIGEV_SIGNAL ||
    917  1.1.1.2  christos       sevp->sigev_signo != SIGPROF)
    918  1.1.1.2  christos     {
    919  1.1.1.2  christos       int ret = real_func (clockid, sevp, timerid);
    920  1.1.1.2  christos       TprintfT (DBG_LT2, "timer_create @%p (%d) ret=%d\n", real_func,
    921  1.1.1.2  christos                 (int) clockid, ret);
    922      1.1  christos       return ret;
    923      1.1  christos     }
    924      1.1  christos 
    925      1.1  christos   /* log that application's timer_create request is overridden */
    926      1.1  christos   (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
    927      1.1  christos 				SP_JCMD_CWARN, COL_WARN_ITMROVR, -1);
    928      1.1  christos   errno = EBUSY;
    929  1.1.1.2  christos   TprintfT (DBG_LT2, "timer_create @%p (%d) ret=%d\n", real_func,
    930  1.1.1.2  christos                 (int) clockid, -1); \
    931  1.1.1.2  christos   return -1;
    932  1.1.1.2  christos }
    933  1.1.1.2  christos 
    934  1.1.1.2  christos #define DCL_TIMER_CREATE(dcl_f) \
    935  1.1.1.2  christos   int dcl_f (clockid_t clockid, struct sigevent *sevp, timer_t *timerid) \
    936  1.1.1.2  christos   { \
    937  1.1.1.2  christos     if (__real_timer_create == NULL) \
    938  1.1.1.2  christos       init_interposition_intf (); \
    939  1.1.1.2  christos     return gprofng_timer_create (__real_timer_create, clockid, sevp, timerid); \
    940  1.1.1.2  christos   }
    941  1.1.1.2  christos 
    942  1.1.1.2  christos DCL_FUNC_VER (DCL_TIMER_CREATE, timer_create_2_34, timer_create@GLIBC_2.34)
    943  1.1.1.2  christos DCL_FUNC_VER (DCL_TIMER_CREATE, timer_create_2_17, timer_create@GLIBC_2.17)
    944  1.1.1.2  christos DCL_FUNC_VER (DCL_TIMER_CREATE, timer_create_2_3_3, timer_create@GLIBC_2.3.3)
    945  1.1.1.2  christos DCL_FUNC_VER (DCL_TIMER_CREATE, timer_create_2_2_5, timer_create@GLIBC_2.2.5)
    946  1.1.1.2  christos DCL_FUNC_VER (DCL_TIMER_CREATE, timer_create_2_2, timer_create@GLIBC_2.2)
    947  1.1.1.2  christos DCL_TIMER_CREATE (timer_create)
    948  1.1.1.2  christos 
    949      1.1  christos /*------------------------------------------------------------- setitimer */
    950      1.1  christos int
    951      1.1  christos _setitimer (int which, const struct itimerval *nval,
    952      1.1  christos 	    struct itimerval *oval)
    953      1.1  christos {
    954      1.1  christos   int ret;
    955      1.1  christos   int period;
    956      1.1  christos 
    957      1.1  christos   if (NULL_PTR (setitimer))
    958      1.1  christos     init_interposition_intf ();
    959      1.1  christos 
    960      1.1  christos   if (nval == NULL)
    961      1.1  christos     period = -1;
    962      1.1  christos   else
    963      1.1  christos     period = (nval->it_interval.tv_sec * MICROSEC) +
    964      1.1  christos     nval->it_interval.tv_usec;
    965      1.1  christos   TprintfT (DBG_LT1, "setitimer(which=%d,nval=%dus) interposing\n", which, period);
    966      1.1  christos 
    967      1.1  christos   /* collector reserves ITIMER_REALPROF for its own use, and ITIMER_PROF
    968      1.1  christos    * uses the same signal (SIGPROF) so it must also be reserved
    969      1.1  christos    */
    970      1.1  christos   if (((which != ITIMER_REALPROF) && (which != ITIMER_PROF)) || (nval == NULL))
    971      1.1  christos     {
    972      1.1  christos       ret = CALL_REAL (setitimer)(which, nval, oval);
    973      1.1  christos       if (oval == NULL)
    974      1.1  christos 	period = -1;
    975      1.1  christos       else
    976      1.1  christos 	period = (oval->it_interval.tv_sec * MICROSEC) +
    977      1.1  christos 	oval->it_interval.tv_usec;
    978      1.1  christos       TprintfT (DBG_LT2, "Real setitimer(%d) returned %d (oval=%dus)\n",
    979      1.1  christos 		which, ret, period);
    980      1.1  christos       return ret;
    981      1.1  christos     }
    982      1.1  christos   /* log that application's setitimer request is overridden */
    983      1.1  christos   (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
    984      1.1  christos 				SP_JCMD_CWARN, COL_WARN_ITMROVR, period);
    985      1.1  christos   if (oval == NULL)
    986      1.1  christos     period = -1;
    987      1.1  christos   else
    988      1.1  christos     {
    989      1.1  christos       getitimer (which, oval); /* return current itimer setting */
    990      1.1  christos       period = (oval->it_interval.tv_sec * MICROSEC) +
    991      1.1  christos 	      oval->it_interval.tv_usec;
    992      1.1  christos     }
    993      1.1  christos   ret = -1;
    994      1.1  christos   errno = EBUSY;
    995      1.1  christos   TprintfT (DBG_LT2, "setitimer() returning %d (oval=%dus)\n", ret, period);
    996      1.1  christos   return ret;
    997      1.1  christos }
    998      1.1  christos 
    999      1.1  christos /*--------------------------------------------------------------- sigprocmask */
   1000      1.1  christos int
   1001      1.1  christos __collector_sigprocmask (int how, const sigset_t* iset, sigset_t* oset)
   1002      1.1  christos {
   1003      1.1  christos   int err = 0;
   1004      1.1  christos   if (NULL_PTR (sigprocmask))
   1005      1.1  christos     err = init_interposition_intf ();
   1006      1.1  christos   if (err)
   1007      1.1  christos     return -1;
   1008      1.1  christos   TprintfT (DBG_LT2, "__collector_sigprocmask(%d) interposing\n", how);
   1009      1.1  christos   sigset_t lsigset;
   1010      1.1  christos   sigset_t* lset = NULL;
   1011      1.1  christos   if (iset)
   1012      1.1  christos     {
   1013      1.1  christos       lsigset = *iset;
   1014      1.1  christos       lset = &lsigset;
   1015      1.1  christos       if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
   1016      1.1  christos 	protect_profiling_signals (lset);
   1017      1.1  christos     }
   1018      1.1  christos   int ret = CALL_REAL (sigprocmask)(how, lset, oset);
   1019      1.1  christos   TprintfT (DBG_LT2, "__collector_sigprocmask(%d) returning %d\n", how, ret);
   1020      1.1  christos   return ret;
   1021      1.1  christos }
   1022      1.1  christos 
   1023      1.1  christos /*------------------------------------------------------------ thr_sigsetmask */
   1024      1.1  christos int
   1025      1.1  christos __collector_thr_sigsetmask (int how, const sigset_t* iset, sigset_t* oset)
   1026      1.1  christos {
   1027      1.1  christos   if (NULL_PTR (thr_sigsetmask))
   1028      1.1  christos     init_interposition_intf ();
   1029      1.1  christos   TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) interposing\n", how);
   1030      1.1  christos   sigset_t lsigset;
   1031      1.1  christos   sigset_t* lset = NULL;
   1032      1.1  christos   if (iset)
   1033      1.1  christos     {
   1034      1.1  christos       lsigset = *iset;
   1035      1.1  christos       lset = &lsigset;
   1036      1.1  christos       if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
   1037      1.1  christos 	protect_profiling_signals (lset);
   1038      1.1  christos     }
   1039      1.1  christos   int ret = CALL_REAL (thr_sigsetmask)(how, lset, oset);
   1040      1.1  christos   TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) returning %d\n", how, ret);
   1041      1.1  christos   return ret;
   1042      1.1  christos }
   1043      1.1  christos 
   1044      1.1  christos /*----------------------------------------------------------- pthread_sigmask */
   1045  1.1.1.2  christos // map interposed symbol versions
   1046      1.1  christos 
   1047  1.1.1.2  christos static int
   1048  1.1.1.3  christos gprofng_pthread_sigmask (int (real_func) (int, const sigset_t *, sigset_t*),
   1049  1.1.1.2  christos                          int how, const sigset_t *iset, sigset_t* oset)
   1050      1.1  christos {
   1051      1.1  christos   sigset_t lsigset;
   1052      1.1  christos   sigset_t* lset = NULL;
   1053      1.1  christos   if (iset)
   1054      1.1  christos     {
   1055      1.1  christos       lsigset = *iset;
   1056      1.1  christos       lset = &lsigset;
   1057  1.1.1.2  christos       if (how == SIG_BLOCK || how == SIG_SETMASK)
   1058  1.1.1.2  christos         protect_profiling_signals (lset);
   1059      1.1  christos     }
   1060  1.1.1.2  christos   int ret = (real_func) (how, lset, oset);
   1061  1.1.1.2  christos   TprintfT (DBG_LT1, "real_pthread_sigmask @%p (%d) ret=%d\n",
   1062  1.1.1.2  christos             real_func, how, ret);
   1063      1.1  christos   return ret;
   1064  1.1.1.2  christos 
   1065      1.1  christos }
   1066  1.1.1.2  christos 
   1067  1.1.1.2  christos #define DCL_PTHREAD_SIGMASK(dcl_f) \
   1068  1.1.1.2  christos   int dcl_f (int how, const sigset_t *iset, sigset_t* oset) \
   1069  1.1.1.2  christos   { \
   1070  1.1.1.2  christos     if (__real_pthread_sigmask == NULL) \
   1071  1.1.1.2  christos       init_interposition_intf (); \
   1072  1.1.1.2  christos     return gprofng_pthread_sigmask (__real_pthread_sigmask, how, iset, oset); \
   1073  1.1.1.2  christos   }
   1074  1.1.1.2  christos 
   1075  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_SIGMASK, pthread_sigmask_2_32, pthread_sigmask@GLIBC_2.32)
   1076  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_SIGMASK, pthread_sigmask_2_17, pthread_sigmask@GLIBC_2.17)
   1077  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_SIGMASK, pthread_sigmask_2_2_5, pthread_sigmask@GLIBC_2.2.5)
   1078  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_SIGMASK, pthread_sigmask_2_0, pthread_sigmask@GLIBC_2.0)
   1079  1.1.1.2  christos DCL_PTHREAD_SIGMASK (pthread_sigmask)
   1080  1.1.1.2  christos 
   1081      1.1  christos /*----------------------------------------------------------- pthread_create */
   1082      1.1  christos typedef struct _CollectorArgs
   1083      1.1  christos {
   1084      1.1  christos   void *(*func)(void*);
   1085      1.1  christos   void *arg;
   1086      1.1  christos   void *stack;
   1087      1.1  christos   int isPthread;
   1088      1.1  christos } CollectorArgs;
   1089      1.1  christos 
   1090      1.1  christos static void *
   1091      1.1  christos collector_root (void *cargs)
   1092      1.1  christos {
   1093      1.1  christos   /* save the real arguments and free cargs */
   1094      1.1  christos   void *(*func)(void*) = ((CollectorArgs*) cargs)->func;
   1095      1.1  christos   void *arg = ((CollectorArgs*) cargs)->arg;
   1096      1.1  christos   void *stack = ((CollectorArgs*) cargs)->stack;
   1097      1.1  christos   int isPthread = ((CollectorArgs*) cargs)->isPthread;
   1098      1.1  christos   __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
   1099      1.1  christos 
   1100      1.1  christos   /* initialize tsd for this thread */
   1101      1.1  christos   if (__collector_tsd_allocate () == 0)
   1102      1.1  christos     /* init tsd for unwind, called right after __collector_tsd_allocate()*/
   1103      1.1  christos     __collector_ext_unwind_key_init (isPthread, stack);
   1104      1.1  christos 
   1105      1.1  christos   if (!isPthread)
   1106      1.1  christos     __collector_mutex_lock (&collector_clone_libc_lock);
   1107      1.1  christos 
   1108      1.1  christos   /* set the profile timer */
   1109      1.1  christos   timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
   1110      1.1  christos   timer_t timerid = NULL;
   1111      1.1  christos   if (timeridptr != NULL)
   1112      1.1  christos     {
   1113      1.1  christos       collector_timer_create (timeridptr);
   1114      1.1  christos       if (*timeridptr != NULL)
   1115      1.1  christos 	collector_timer_settime (itimer_period_requested, *timeridptr);
   1116      1.1  christos       timerid = *timeridptr;
   1117      1.1  christos     }
   1118      1.1  christos   int hwc_rc = __collector_ext_hwc_lwp_init ();
   1119      1.1  christos 
   1120      1.1  christos   if (!isPthread)
   1121      1.1  christos     __collector_mutex_unlock (&collector_clone_libc_lock);
   1122      1.1  christos   /* call the real function */
   1123      1.1  christos   void *ret = func (arg);
   1124      1.1  christos   if (!isPthread)
   1125      1.1  christos     __collector_mutex_lock (&collector_clone_libc_lock);
   1126      1.1  christos   if (timerid != NULL)
   1127      1.1  christos     CALL_REAL (timer_delete)(timerid);
   1128      1.1  christos   if (!hwc_rc)
   1129      1.1  christos     /* pthread_kill not handled here */
   1130      1.1  christos     __collector_ext_hwc_lwp_fini ();
   1131      1.1  christos 
   1132      1.1  christos   if (!isPthread)
   1133      1.1  christos     __collector_mutex_unlock (&collector_clone_libc_lock);
   1134      1.1  christos   /* if we have this chance, release tsd */
   1135      1.1  christos   __collector_tsd_release ();
   1136      1.1  christos 
   1137      1.1  christos   return ret;
   1138      1.1  christos }
   1139      1.1  christos 
   1140      1.1  christos // map interposed symbol versions
   1141      1.1  christos 
   1142      1.1  christos static int
   1143  1.1.1.3  christos gprofng_pthread_create (int (real_func) (pthread_t *, const pthread_attr_t *,
   1144  1.1.1.3  christos 					 void *(*)(void *), void *),
   1145  1.1.1.3  christos 			pthread_t *thread, const pthread_attr_t *attr,
   1146  1.1.1.3  christos 			void *(*func)(void*), void *arg)
   1147      1.1  christos {
   1148  1.1.1.2  christos   TprintfT (DBG_LTT, "gprofng_pthread_create @%p\n", real_func);
   1149      1.1  christos   if (dispatch_mode != DISPATCH_ON)
   1150  1.1.1.2  christos     return (real_func) (thread, attr, func, arg);
   1151  1.1.1.2  christos   CollectorArgs *cargs = __collector_allocCSize (__collector_heap,
   1152  1.1.1.2  christos                                                  sizeof (CollectorArgs), 1);
   1153      1.1  christos   if (cargs == NULL)
   1154  1.1.1.2  christos     return (real_func) (thread, attr, func, arg);
   1155      1.1  christos   cargs->func = func;
   1156      1.1  christos   cargs->arg = arg;
   1157      1.1  christos   cargs->stack = NULL;
   1158      1.1  christos   cargs->isPthread = 1;
   1159  1.1.1.2  christos   int ret = (real_func) (thread, attr, &collector_root, cargs);
   1160      1.1  christos   if (ret)
   1161      1.1  christos     __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
   1162  1.1.1.2  christos   TprintfT (DBG_LT1, "gprofng_pthread_create @%p returns %d\n", real_func, ret);
   1163      1.1  christos   return ret;
   1164      1.1  christos }
   1165      1.1  christos 
   1166  1.1.1.2  christos 
   1167  1.1.1.2  christos #define DCL_PTHREAD_CREATE(dcl_f) \
   1168  1.1.1.2  christos   int dcl_f (pthread_t *thread, const pthread_attr_t *attr, \
   1169  1.1.1.2  christos              void *(*func)(void*), void *arg) \
   1170  1.1.1.2  christos   { \
   1171  1.1.1.2  christos     if (__real_pthread_create == NULL) \
   1172  1.1.1.2  christos       init_interposition_intf (); \
   1173  1.1.1.2  christos      return gprofng_pthread_create (__real_pthread_create, thread, attr, func, arg); \
   1174  1.1.1.2  christos   }
   1175  1.1.1.2  christos 
   1176  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_CREATE, pthread_create_2_34, pthread_create@GLIBC_2.34)
   1177  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_CREATE, pthread_create_2_17, pthread_create@GLIBC_2.17)
   1178  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_CREATE, pthread_create_2_2_5, pthread_create@GLIBC_2.2.5)
   1179  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_CREATE, pthread_create_2_1, pthread_create@GLIBC_2.1)
   1180  1.1.1.2  christos DCL_FUNC_VER (DCL_PTHREAD_CREATE, pthread_create_2_0, pthread_create@GLIBC_2.0)
   1181  1.1.1.2  christos DCL_PTHREAD_CREATE (pthread_create)
   1182  1.1.1.2  christos 
   1183      1.1  christos int
   1184      1.1  christos __collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
   1185      1.1  christos 			       va_list va /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
   1186      1.1  christos {
   1187      1.1  christos   if (NULL_PTR (clone))
   1188      1.1  christos     init_interposition_intf ();
   1189      1.1  christos   TprintfT (0, "clone thread interposing\n");
   1190      1.1  christos   pid_t * ptid = NULL;
   1191      1.1  christos   struct user_desc * tls = NULL;
   1192      1.1  christos   pid_t * ctid = NULL;
   1193      1.1  christos   int num_args = 0;
   1194      1.1  christos   if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
   1195      1.1  christos     {
   1196      1.1  christos       ptid = va_arg (va, pid_t *);
   1197      1.1  christos       tls = va_arg (va, struct user_desc*);
   1198      1.1  christos       ctid = va_arg (va, pid_t *);
   1199      1.1  christos       num_args = 3;
   1200      1.1  christos     }
   1201      1.1  christos   else if (flags & CLONE_SETTLS)
   1202      1.1  christos     {
   1203      1.1  christos       ptid = va_arg (va, pid_t *);
   1204      1.1  christos       tls = va_arg (va, struct user_desc*);
   1205      1.1  christos       num_args = 2;
   1206      1.1  christos     }
   1207      1.1  christos   else if (flags & CLONE_PARENT_SETTID)
   1208      1.1  christos     {
   1209      1.1  christos       ptid = va_arg (va, pid_t *);
   1210      1.1  christos       num_args = 1;
   1211      1.1  christos     }
   1212      1.1  christos   int ret = 0;
   1213      1.1  christos   if (dispatch_mode != DISPATCH_ON)
   1214      1.1  christos     {
   1215      1.1  christos       switch (num_args)
   1216      1.1  christos 	{
   1217      1.1  christos 	case 3:
   1218      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
   1219      1.1  christos 	  break;
   1220      1.1  christos 	case 2:
   1221      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
   1222      1.1  christos 	  break;
   1223      1.1  christos 	case 1:
   1224      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
   1225      1.1  christos 	  break;
   1226      1.1  christos 	default:
   1227      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
   1228      1.1  christos 	  break;
   1229      1.1  christos 	}
   1230      1.1  christos       return ret;
   1231      1.1  christos     }
   1232      1.1  christos   CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
   1233      1.1  christos   if (cargs == NULL)
   1234      1.1  christos     {
   1235      1.1  christos       switch (num_args)
   1236      1.1  christos 	{
   1237      1.1  christos 	case 3:
   1238      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
   1239      1.1  christos 	  break;
   1240      1.1  christos 	case 2:
   1241      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
   1242      1.1  christos 	  break;
   1243      1.1  christos 	case 1:
   1244      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
   1245      1.1  christos 	  break;
   1246      1.1  christos 	default:
   1247      1.1  christos 	  ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
   1248      1.1  christos 	  break;
   1249      1.1  christos 	}
   1250      1.1  christos       return ret;
   1251      1.1  christos     }
   1252      1.1  christos 
   1253      1.1  christos   cargs->func = (void *(*)(void*))fn;
   1254      1.1  christos   cargs->arg = arg;
   1255      1.1  christos   cargs->stack = child_stack;
   1256      1.1  christos   cargs->isPthread = 0;
   1257      1.1  christos 
   1258      1.1  christos   switch (num_args)
   1259      1.1  christos     {
   1260      1.1  christos     case 3:
   1261      1.1  christos       ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls, ctid);
   1262      1.1  christos       break;
   1263      1.1  christos     case 2:
   1264      1.1  christos       ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls);
   1265      1.1  christos       break;
   1266      1.1  christos     case 1:
   1267      1.1  christos       ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid);
   1268      1.1  christos       break;
   1269      1.1  christos     default:
   1270      1.1  christos       ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs);
   1271      1.1  christos       break;
   1272      1.1  christos     }
   1273      1.1  christos 
   1274      1.1  christos   if (ret < 0)
   1275      1.1  christos     __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
   1276      1.1  christos   TprintfT (DBG_LT1, "clone thread returning %d\n", ret);
   1277      1.1  christos   return ret;
   1278      1.1  christos }
   1279      1.1  christos 
   1280      1.1  christos // weak symbols:
   1281  1.1.1.3  christos int sigprocmask (int, const sigset_t*, sigset_t*) __attribute__ ((weak, alias ("__collector_sigprocmask")));
   1282  1.1.1.3  christos int thr_sigsetmask (int, const sigset_t*, sigset_t*) __attribute__ ((weak, alias ("__collector_thr_sigsetmask")));
   1283  1.1.1.3  christos __typeof(setitimer) setitimer __attribute__ ((weak, alias ("_setitimer")));
   1284