1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261 |
- /* Copyright (C) 2021 Free Software Foundation, Inc.
- Contributed by Oracle.
- This file is part of GNU Binutils.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- /*
- * Central SIGPROF dispatcher to various module event handlers
- * (REALPROF profile, HWC check, overview sample, manual sample)
- */
- #include "config.h"
- #include <dlfcn.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ucontext.h>
- #include <sys/param.h>
- #include <sys/signal.h>
- #include <sys/syscall.h>
- #include <time.h>
- #include <signal.h>
- #include "gp-defs.h"
- #include "gp-experiment.h"
- #include "collector.h"
- #include "collector_module.h"
- #include "tsd.h"
- #include "hwcdrv.h"
- /* TprintfT(<level>,...) definitions. Adjust per module as needed */
- #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
- #define DBG_LTT 0 // for interposition on GLIBC functions
- #define DBG_LT1 1 // for configuration details, warnings
- #define DBG_LT2 2
- #define DBG_LT3 3
- static void collector_sigprof_dispatcher (int, siginfo_t*, void*);
- static int init_interposition_intf ();
- #include "memmgr.h"
- static int collector_timer_create (timer_t * ptimerid);
- static int collector_timer_settime (int period, timer_t timerid);
- static int collector_timer_gettime (timer_t timerid);
- static volatile int collector_sigprof_entries = 0; /* counter for SIGPROF signals in DISPATCH_TST mode */
- static timer_t collector_master_thread_timerid = NULL;
- static collector_mutex_t collector_clone_libc_lock = COLLECTOR_MUTEX_INITIALIZER;
- static unsigned dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
- static void *__real_clone = NULL;
- static void *__real_timer_create = NULL;
- static void *__real_timer_settime = NULL;
- static void *__real_timer_delete = NULL;
- static void *__real_timer_gettime = NULL;
- #if ARCH(Intel) && WSIZE(32)
- static void *__real_pthread_create_2_1 = NULL;
- static void *__real_pthread_create_2_0 = NULL;
- #elif ARCH(Intel) && WSIZE(64)
- static void *__real_timer_create_2_3_3 = NULL;
- static void *__real_timer_create_2_2_5 = NULL;
- #elif ARCH(SPARC) && WSIZE(64)
- static void *__real_timer_create_2_3_3 = NULL;
- static void *__real_timer_create_2_2 = NULL;
- #endif
- /* Original SIGPROF handler which will be replaced with the dispatcher. Used
- * to properly interact with libaio, which uses SIGPROF as its SIGAIOCANCEL. */
- static struct sigaction original_sigprof_handler;
- enum
- {
- DISPATCH_NYI = -1, /* dispatcher not yet installed */
- DISPATCH_OFF = 0, /* dispatcher installed, but disabled */
- DISPATCH_ON = 1, /* dispatcher installed, and enabled */
- DISPATCH_TST = 2 /* dispatcher installed, and enabled in testing mode */
- };
- static int dispatch_mode = DISPATCH_NYI; /* controls SIGPROF dispatching */
- static int itimer_period_requested = 0; /* dispatcher itimer period */
- static int itimer_period_actual = 0; /* actual dispatcher itimer period */
- #define CALL_REAL(x) (*(int(*)())__real_##x)
- #define NULL_PTR(x) ( __real_##x == NULL )
- static void *__real_sigaction = NULL;
- static void *__real_setitimer = NULL;
- static void *__real_libc_setitimer = NULL;
- static void *__real_sigprocmask = NULL;
- static void *__real_thr_sigsetmask = NULL;
- static void *__real_pthread_sigmask = NULL;
- static void *__real_pthread_create = NULL;
- /*
- * void collector_sigprof_dispatcher()
- *
- * Common SIGPROF event handler which dispatches events to appropriate
- * module handlers, if they are active for this collection and due.
- * Dispatch sequence, logic and handlers currently hardcoded in dispatcher.
- */
- static void
- collector_sigprof_dispatcher (int sig, siginfo_t *info, void *context)
- {
- if (info == NULL || (info->si_code <= 0 && info->si_code != SI_TIMER))
- {
- TprintfT (DBG_LT2, "collector_sigprof_dispatcher signal for %p\n",
- original_sigprof_handler.sa_handler);
- /* pass signal to previous handler */
- /* watch for recursion, SIG_IGN, and SIG_DFL */
- if (original_sigprof_handler.sa_handler == SIG_DFL)
- __collector_SIGDFL_handler (SIGPROF);
- else if (original_sigprof_handler.sa_handler != SIG_IGN &&
- original_sigprof_handler.sa_sigaction != &collector_sigprof_dispatcher)
- {
- (original_sigprof_handler.sa_sigaction)(sig, info, context);
- TprintfT (DBG_LT2, "collector_sigprof_dispatcher handled\n");
- }
- }
- else if (dispatch_mode == DISPATCH_ON)
- {
- #if ARCH(SPARC)
- ucontext_t uctxmem;
- ucontext_t *uctx = &uctxmem;
- uctx->uc_link = NULL;
- /* 23340823 signal handler third argument should point to a ucontext_t */
- /* Convert sigcontext to ucontext_t on sparc-Linux */
- struct sigcontext *sctx = (struct sigcontext*) context;
- #if WSIZE(32)
- uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
- __collector_memcpy (&uctx->uc_mcontext.gregs[3],
- sctx->si_regs.u_regs,
- sizeof (sctx->si_regs.u_regs));
- #else
- uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
- __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
- sctx->sigc_regs.u_regs,
- sizeof (sctx->sigc_regs.u_regs));
- #endif /* WSIZE() */
- #else /* not sparc-Linux */
- ucontext_t *uctx = (ucontext_t*) context;
- #endif /* ARCH() */
- TprintfT (DBG_LT3, "collector_sigprof_dispatcher dispatching signal\n");
- /* XXXX the order of these checks/activities may need adjustment */
- /* XXXX should also check (first) for a "cached" manual sample */
- /* HWC check for each LWP: required even if collection is paused */
- /* This should be first, otherwise it's likely to find the counters
- * stopped due to an event/overflow during some of the other activities.
- */
- /* XXXX HWC check performed every time (skipping if HWC profiling inactive)
- * to avoid complexity of maintaining separate check times for each LWP
- */
- __collector_ext_hwc_check (info, uctx);
- /* XXXX if sigemtpending, should perhaps skip __collector_ext_usage_sample
- * (and get it next time through)
- */
- /* check for experiment past delay start */
- if (__collector_delay_start != 0)
- {
- hrtime_t now = __collector_gethrtime ();
- if (__collector_delay_start < now)
- {
- TprintfT (0, "__collector_ext_usage_sample: now (%lld) > delay_start (%lld)\n",
- (now - __collector_start_time), (__collector_delay_start - __collector_start_time));
- /* resume the data collection */
- __collector_delay_start = 0;
- __collector_resume ();
- /* don't take a periodic sample, just let the resume sample cover it */
- if (__collector_sample_period != 0)
- {
- /* this update should only be done for periodic samples */
- while (__collector_next_sample < now)
- __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
- }
- /* return; */
- }
- }
- /* check for periodic sampling */
- if (__collector_gethrtime () > __collector_next_sample)
- __collector_ext_usage_sample (PERIOD_SMPL, "periodic");
- /* check for experiment past termination time */
- if (__collector_exp_active && __collector_terminate_time != 0)
- {
- hrtime_t now = __collector_gethrtime ();
- if (__collector_terminate_time < now)
- {
- TprintfT (0, "__collector_ext_usage_sample: now (%lld) > terminate_time (%lld); closing experiment\n",
- (now - __collector_start_time), (__collector_terminate_time - __collector_start_time));
- /* close the experiment */
- __collector_close_experiment ();
- }
- }
- /* call the code to process the profile data, and generate the packet */
- /* (must always be called, otherwise profile data must be aggregated,
- * but can be left till last, as already have the required data)
- */
- __collector_ext_profile_handler (info, uctx);
- }
- else if (dispatch_mode == DISPATCH_TST)
- {
- collector_sigprof_entries++;
- return;
- }
- }
- /*
- * __collector_sigprof_install
- */
- int
- __collector_sigprof_install ()
- {
- TprintfT (DBG_LT2, "__collector_sigprof_install\n");
- struct sigaction oact;
- if (__collector_sigaction (SIGPROF, NULL, &oact) != 0)
- return COL_ERROR_DISPINIT;
- if (oact.sa_sigaction == collector_sigprof_dispatcher)
- /* signal handler is already in place; we are probably in a fork-child */
- TprintfT (DBG_LT1, "dispatcher: __collector_ext_dispatcher_install() collector_sigprof_dispatcher already installed\n");
- else
- {
- struct sigaction c_act;
- CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
- sigemptyset (&c_act.sa_mask);
- sigaddset (&c_act.sa_mask, HWCFUNCS_SIGNAL); /* block SIGEMT delivery in handler */
- c_act.sa_sigaction = collector_sigprof_dispatcher;
- c_act.sa_flags = SA_RESTART | SA_SIGINFO;
- if (__collector_sigaction (SIGPROF, &c_act, &original_sigprof_handler))
- return COL_ERROR_DISPINIT;
- }
- dispatch_mode = DISPATCH_OFF; /* don't dispatch yet */
- TprintfT (DBG_LT2, "__collector_sigprof_install done\n");
- return COL_ERROR_NONE;
- }
- /*
- * void __collector_ext_dispatcher_tsd_create_key()
- *
- * create tsd key for dispatcher
- */
- void
- __collector_ext_dispatcher_tsd_create_key ()
- {
- dispatcher_key = __collector_tsd_create_key (sizeof (timer_t), NULL, NULL);
- }
- /*
- * int __collector_ext_dispatcher_install()
- *
- * installs a common handler/dispatcher (and itimer) for SIGPROF events
- */
- int
- __collector_ext_dispatcher_install ()
- {
- int timer_period;
- TprintfT (DBG_LT2, "__collector_ext_dispatcher_install\n");
- /* check period set for interval timer, which will be used as the basis
- * for all timed activities: if not set, no role for SIGPROF dispatcher
- */
- if (itimer_period_requested <= 0)
- {
- TprintfT (DBG_LT1, "No interval timer set: skipping dispatcher install!\n");
- return COL_ERROR_NONE; /* no itimer/dispatcher required */
- }
- /* check for an existing interval timer */
- if (collector_master_thread_timerid == NULL)
- if (collector_timer_create (&collector_master_thread_timerid) < 0)
- return COL_ERROR_ITMRINIT;
- timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
- if (timeridptr != NULL)
- *timeridptr = collector_master_thread_timerid; // store for per thread timer stop/start
- TprintfT (DBG_LT3, "__collector_ext_dispatcher_install: collector_master_thread_timerid=%p\n",
- collector_master_thread_timerid);
- timer_period = collector_timer_gettime (collector_master_thread_timerid);
- if (timer_period > 0)
- {
- TprintfT (DBG_LT1, "Overriding app-set interval timer with period %d\n", timer_period);
- (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d->%d</event>\n",
- SP_JCMD_CWARN, COL_WARN_ITMRPOVR, timer_period, itimer_period_requested);
- }
- /* install the interval timer used for all timed activities */
- if (collector_timer_settime (itimer_period_requested, collector_master_thread_timerid) < 0)
- return COL_ERROR_ITMRINIT;
- TprintfT (DBG_LT2, "__collector_ext_dispatcher_install done\n");
- dispatch_mode = DISPATCH_ON; /* activate SIGPROF dispatch to event handlers */
- return COL_ERROR_NONE;
- }
- int
- __collector_sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
- {
- TprintfT (DBG_LT1, "__collector_sigaction: %d, %p\n", sig, nact ? nact->sa_sigaction : NULL);
- if (NULL_PTR (sigaction))
- init_interposition_intf ();
- /* Whether we change the signal handler in the kernel
- * or not make sure the real sigaction is aware about
- * our new handler (6227565)
- */
- return CALL_REAL (sigaction)(sig, nact, oact);
- }
- /*
- * We have special dispatchers for SIGPROF and HWCFUNCS_SIGNAL to
- * decide whether the signal was intended for us or for the user.
- * One special case is SIGDFL, in which case we don't have a
- * user-function address to call. If the user did indeed set
- * default disposition for one of these signals and sent that
- * signal, we honor that action, even though it will lead to
- * termination.
- */
- void
- __collector_SIGDFL_handler (int sig)
- {
- /* remove our dispatcher, replacing it with the default disposition */
- struct sigaction act;
- CALL_UTIL (memset)(&act, 0, sizeof (act));
- act.sa_handler = SIG_DFL;
- if (__collector_sigaction (sig, &act, NULL))
- {
- /* XXXXXX what are we supposed to do here? we're committing suicide anyhow */
- }
- /* resend the signal we intercepted earlier */
- // XXXX Bug 18177509 - additional sigprof signal kills target program
- kill (getpid (), sig);
- }
- /*
- * suspend/resume timer per thread
- */
- void
- __collector_ext_dispatcher_thread_timer_suspend ()
- {
- timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
- if (timeridptr != NULL && *timeridptr != NULL)
- (void) collector_timer_settime (0, *timeridptr);
- return;
- }
- int
- __collector_ext_dispatcher_thread_timer_resume ()
- {
- timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
- if (timeridptr == NULL)
- return -1;
- if (*timeridptr == NULL)
- { // timer id not initialized yet
- TprintfT (DBG_LT2, "__collector_ext_dispatcher_thread_timer_resume: timer not initialized yet, create it\n");
- if (collector_timer_create (timeridptr) == -1)
- {
- TprintfT (0, "__collector_ext_dispatcher_thread_timer_resume(): WARNING: No timer created\n");
- return -1;
- }
- }
- return collector_timer_settime (itimer_period_requested, *timeridptr);
- }
- void
- __collector_ext_dispatcher_suspend ()
- {
- TprintfT (DBG_LT2, "__collector_ext_dispatcher_suspend\n");
- if (dispatch_mode == DISPATCH_NYI)
- {
- TprintfT (0, "__collector_ext_dispatcher_suspend(): WARNING: No dispatcher installed\n");
- return;
- }
- /* disable SIGPROF dispatching */
- dispatch_mode = DISPATCH_OFF;
- /* disable the interval timer; ignore any failures */
- __collector_ext_dispatcher_thread_timer_suspend ();
- return;
- }
- void
- __collector_ext_dispatcher_restart ()
- {
- TprintfT (DBG_LT2, "__collector_ext_dispatcher_restart(ip=%d)\n", itimer_period_requested);
- if (dispatch_mode == DISPATCH_NYI)
- {
- TprintfT (0, "__collector_ext_dispatcher_restart(): WARNING: No dispatcher installed\n");
- return;
- }
- /* restart the interval timer used for all timed activities */
- if (__collector_ext_dispatcher_thread_timer_resume () == 0)
- dispatch_mode = DISPATCH_ON; /* re-activate SIGPROF dispatch to handlers */
- return;
- }
- /*
- * void __collector_ext_dispatcher_deinstall()
- *
- * If installed, disables SIGPROF dispatch and interval timer.
- * Includes checks for last SIGPROF dispatch time, interval timer period,
- * and currently installed SIGPROF handler, with appropriate warnings logged.
- * The dispatcher remains installed to handle pending collector SIGPROFs and
- * forward non-collector SIGPROFs to the application's handler(s).
- * If the decision is ever made actually to deinstall the dispatcher,
- * consider bug 4183714 and what to do about any possible pending
- * SIGPROFs.
- */
- void
- __collector_ext_dispatcher_deinstall ()
- {
- TprintfT (DBG_LT1, "__collector_ext_dispatcher_deinstall()\n");
- if (dispatch_mode == DISPATCH_NYI)
- {
- TprintfT (0, "__collector_ext_dispatcher_deinstall(): WARNING: No dispatcher installed\n");
- return;
- }
- dispatch_mode = DISPATCH_OFF; /* disable SIGPROF dispatching */
- /* verify that interval timer is still installed with expected period */
- int timer_period = collector_timer_gettime (collector_master_thread_timerid);
- if (timer_period != itimer_period_actual)
- {
- TprintfT (DBG_LT2, "dispatcher: Collector interval timer period changed %d -> %d\n",
- itimer_period_actual, timer_period);
- if ((itimer_period_actual >= (timer_period + timer_period / 10)) ||
- (itimer_period_actual <= (timer_period - timer_period / 10)))
- __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
- SP_JCMD_CWARN, COL_WARN_ITMRREP,
- itimer_period_actual, timer_period);
- else
- __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
- SP_JCMD_COMMENT, COL_WARN_PROFRND,
- itimer_period_actual, timer_period);
- }
- /* Verify that SIGPROF dispatcher is still installed.
- * (still required with sigaction interposition and management,
- * since interposition is not done for attach experiments)
- */
- struct sigaction curr;
- if (__collector_sigaction (SIGPROF, NULL, &curr) == -1)
- TprintfT (0, "ERROR: dispatcher sigaction check failed: errno=%d\n", errno);
- else if (curr.sa_sigaction != collector_sigprof_dispatcher)
- {
- TprintfT (0, "ERROR: collector dispatcher replaced by %p!\n", curr.sa_handler);
- (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%p</event>\n",
- SP_JCMD_CWARN, COL_WARN_SIGPROF, curr.sa_handler);
- }
- else
- TprintfT (DBG_LT2, "collector dispatcher integrity verified!\n");
- /* disable the interval timer; ignore any failures */
- if (collector_master_thread_timerid != NULL)
- {
- (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
- collector_master_thread_timerid = NULL;
- }
- dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
- itimer_period_requested = 0;
- itimer_period_actual = 0;
- }
- /*
- * void __collector_ext_dispatcher_fork_child_cleanup()
- *
- * delete timer, clear timer interval
- */
- void
- __collector_ext_dispatcher_fork_child_cleanup ()
- {
- if (collector_master_thread_timerid != NULL)
- {
- (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
- collector_master_thread_timerid = NULL;
- }
- __collector_mutex_init (&collector_clone_libc_lock);
- dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
- itimer_period_requested = 0;
- itimer_period_actual = 0;
- }
- /*
- * int __collector_ext_itimer_set (int rperiod)
- *
- * set itimer period, if not yet set to a positive number of microseconds,
- * (after rounding to sys_resolution if necessary) and return its value
- */
- int
- __collector_ext_itimer_set (int rperiod)
- {
- int period;
- /* if rperiod is negative, force setting */
- if (rperiod < 0)
- {
- itimer_period_actual = 0;
- period = -rperiod;
- }
- else
- period = rperiod;
- // ignore SIGPROF while testing itimer interval setting
- int saved = dispatch_mode;
- dispatch_mode = DISPATCH_OFF;
- if (collector_timer_create (&collector_master_thread_timerid) == -1)
- {
- TprintfT (0, "__collector_ext_itimer_set(): WARNING: No timer created\n");
- return itimer_period_actual;
- }
- if (collector_timer_settime (period, collector_master_thread_timerid) == 0)
- {
- itimer_period_actual = collector_timer_gettime (collector_master_thread_timerid);
- (void) collector_timer_settime (0, collector_master_thread_timerid); /* XXXX unset for now */
- itimer_period_requested = period;
- if (itimer_period_requested != itimer_period_actual)
- {
- TprintfT (DBG_LT2, " itimer period %d adjusted to %d\n",
- itimer_period_requested, itimer_period_actual);
- // (void) __collector_log_write("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
- // SP_JCMD_CWARN, COL_WARN_PROFRND, itimer_period_requested, itimer_period_actual);
- }
- else
- TprintfT (DBG_LT2, " itimer period %d accepted\n", period);
- }
- // restore dispatching SIGPROF handler
- dispatch_mode = saved;
- TprintfT (0, "__collector_ext_itimer_set(%d), requested=%d, actual=%d)\n",
- rperiod, itimer_period_requested, itimer_period_actual);
- return (itimer_period_actual);
- }
- static int
- collector_timer_gettime (timer_t timerid)
- {
- int timer_period;
- struct itimerspec itimer;
- if (timerid == NULL)
- return (0); // timer was not initialized
- if (CALL_REAL (timer_gettime)(timerid, &itimer) == -1)
- {
- /* this should never reasonably fail, so not worth logging */
- TprintfT (DBG_LT1, "WARNING: timer_gettime failed: errno=%d\n", errno);
- return (-1);
- }
- timer_period = ((itimer.it_interval.tv_sec * NANOSEC) +
- itimer.it_interval.tv_nsec) / 1000;
- TprintfT (DBG_LT2, "collector_timer_gettime (period=%d)\n", timer_period);
- return (timer_period);
- }
- static int
- collector_timer_create (timer_t * ptimerid)
- {
- struct sigevent sigev;
- if (NULL_PTR (timer_create))
- init_interposition_intf ();
- TprintfT (DBG_LT2, "collector_timer_settime(): timer_create is %p\n", __real_timer_create);
- sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
- sigev.sigev_signo = SIGPROF;
- sigev.sigev_value.sival_ptr = ptimerid;
- sigev._sigev_un._tid = __collector_gettid ();
- if (CALL_REAL (timer_create)(CLOCK_THREAD_CPUTIME_ID, &sigev, ptimerid) == -1)
- {
- TprintfT (DBG_LT2, "collector_timer_settime() failed! errno=%d\n", errno);
- return -1;
- }
- return 0;
- }
- static int
- collector_timer_settime (int period, timer_t timerid)
- {
- struct itimerspec itimer;
- if (NULL_PTR (timer_settime))
- init_interposition_intf ();
- TprintfT (DBG_LT2, "collector_timer_settime(period=%d)\n", period);
- time_t NPM = 1000;
- itimer.it_interval.tv_sec = NPM * period / NANOSEC;
- itimer.it_interval.tv_nsec = (NPM * period) % NANOSEC;
- itimer.it_value = itimer.it_interval;
- if (CALL_REAL (timer_settime)(timerid, 0, &itimer, NULL) == -1)
- {
- TprintfT (DBG_LT2, "collector_timer_settime(%d) failed! errno=%d\n", period, errno);
- return -1;
- }
- return 0;
- }
- static void
- protect_profiling_signals (sigset_t* lset)
- {
- static unsigned int protected_sigprof = 0;
- static unsigned int protected_sigemt = 0;
- // T1 relies on thread signal masking, so best not to mess with it:
- // T1 users have already been warned about the dangers of its use
- if (__collector_libthread_T1)
- return;
- if (sigismember (lset, SIGPROF) && (dispatch_mode == DISPATCH_ON))
- {
- TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGPROF");
- if (protected_sigprof == 0)
- __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
- SP_JCMD_CWARN, COL_WARN_SIGMASK, "SIGPROF");
- sigdelset (lset, SIGPROF);
- protected_sigprof++;
- }
- if (sigismember (lset, HWCFUNCS_SIGNAL) && __collector_ext_hwc_active ())
- {
- TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGEMT");
- if (protected_sigemt == 0)
- __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
- SP_JCMD_CWARN, COL_WARN_SIGMASK, HWCFUNCS_SIGNAL_STRING);
- sigdelset (lset, HWCFUNCS_SIGNAL);
- protected_sigemt++;
- }
- }
- #define SYS_SETITIMER_NAME "setitimer"
- #define SYS_SIGACTION_NAME "sigaction"
- #define SYS_SIGPROCMASK_NAME "sigprocmask"
- #define SYS_PTHREAD_SIGMASK "pthread_sigmask"
- #define SYS_THR_SIGSETMASK "thr_sigsetmask"
- static int
- init_interposition_intf ()
- {
- if (__collector_dlsym_guard)
- return 1;
- void *dlflag;
- /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
- void *handle = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD);
- #if ARCH(SPARC) && WSIZE(64)
- /* dlopen a bogus path to avoid CR 23608692 */
- dlopen ("/bogus_path_for_23608692_workaround/", RTLD_LAZY | RTLD_NOLOAD);
- #endif
- __real_setitimer = dlsym (RTLD_NEXT, SYS_SETITIMER_NAME);
- if (__real_setitimer == NULL)
- {
- __real_setitimer = dlsym (RTLD_DEFAULT, SYS_SETITIMER_NAME);
- if (__real_setitimer == NULL)
- {
- TprintfT (DBG_LT2, "init_interposition_intf() setitimer not found\n");
- return 1;
- }
- dlflag = RTLD_DEFAULT;
- }
- else
- dlflag = RTLD_NEXT;
- TprintfT (DBG_LT2, "init_interposition_intf() using RTLD_%s\n",
- (dlflag == RTLD_DEFAULT) ? "DEFAULT" : "NEXT");
- TprintfT (DBG_LT2, "@%p __real_setitimer\n", __real_setitimer);
- __real_sigaction = dlsym (dlflag, SYS_SIGACTION_NAME);
- TprintfT (DBG_LT2, "@%p __real_sigaction\n", __real_sigaction);
- /* also explicitly get libc.so/setitimer (as a backup) */
- __real_libc_setitimer = dlsym (handle, SYS_SETITIMER_NAME);
- TprintfT (DBG_LT2, "@%p __real_libc_setitimer\n", __real_libc_setitimer);
- __real_sigprocmask = dlsym (dlflag, SYS_SIGPROCMASK_NAME);
- TprintfT (DBG_LT2, "@%p __real_sigprocmask\n", __real_sigprocmask);
- __real_thr_sigsetmask = dlsym (dlflag, SYS_THR_SIGSETMASK);
- TprintfT (DBG_LT2, "@%p __real_thr_sigsetmask\n", __real_thr_sigsetmask);
- __real_pthread_sigmask = dlsym (dlflag, SYS_PTHREAD_SIGMASK);
- TprintfT (DBG_LT2, "@%p __real_pthread_sigmask\n", __real_pthread_sigmask);
- #if ARCH(Aarch64)
- __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
- __real_timer_create = dlsym (dlflag, "timer_create");
- __real_timer_settime = dlsym (dlflag, "timer_settime");
- __real_timer_delete = dlsym (dlflag, "timer_delete");
- __real_timer_gettime = dlsym (dlflag, "timer_gettime");
- #else
- __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
- TprintfT (DBG_LT2, "[%s] @%p __real_pthread_create\n", SYS_PTHREAD_CREATE_VERSION, __real_pthread_create);
- __real_timer_create = dlvsym (dlflag, "timer_create", SYS_TIMER_X_VERSION);
- TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_create\n", SYS_TIMER_X_VERSION, __real_timer_create);
- __real_timer_settime = dlvsym (dlflag, "timer_settime", SYS_TIMER_X_VERSION);
- TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_settime\n", SYS_TIMER_X_VERSION, __real_timer_settime);
- __real_timer_delete = dlvsym (dlflag, "timer_delete", SYS_TIMER_X_VERSION);
- TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_delete\n", SYS_TIMER_X_VERSION, __real_timer_delete);
- __real_timer_gettime = dlvsym (dlflag, "timer_gettime", SYS_TIMER_X_VERSION);
- TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_gettime\n", SYS_TIMER_X_VERSION, __real_timer_gettime);
- __real_clone = dlsym (dlflag, "clone");
- TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
- #if ARCH(Intel) && WSIZE(32)
- __real_pthread_create_2_1 = __real_pthread_create;
- __real_pthread_create_2_0 = dlvsym (dlflag, "pthread_create", "GLIBC_2.0");
- #elif ARCH(Intel) && WSIZE(64)
- __real_timer_create_2_3_3 = __real_timer_create;
- __real_timer_create_2_2_5 = dlvsym (dlflag, "timer_create", "GLIBC_2.2.5");
- #elif ARCH(SPARC) && WSIZE(64)
- __real_timer_create_2_3_3 = __real_timer_create;
- __real_timer_create_2_2 = dlvsym (dlflag, "timer_create", "GLIBC_2.2");
- #endif /* ARCH() && SIZE() */
- #endif
- return 0;
- }
- /*------------------------------------------------------------- sigaction */
- /* NB: need a global interposing function called "sigaction" */
- int
- sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
- {
- int ret = 0;
- int err = 0;
- if (NULL_PTR (sigaction))
- err = init_interposition_intf ();
- if (err)
- return -1;
- TprintfT (DBG_LT3, "sigaction(sig=%02d, nact=%p) interposing\n", sig, nact);
- if (sig == SIGPROF && dispatch_mode != DISPATCH_NYI)
- {
- if (oact != NULL)
- {
- oact->sa_handler = original_sigprof_handler.sa_handler;
- oact->sa_mask = original_sigprof_handler.sa_mask;
- oact->sa_flags = original_sigprof_handler.sa_flags;
- }
- if (nact != NULL)
- {
- original_sigprof_handler.sa_handler = nact->sa_handler;
- original_sigprof_handler.sa_mask = nact->sa_mask;
- original_sigprof_handler.sa_flags = nact->sa_flags;
- TprintfT (DBG_LT1, "dispatcher: new sigaction(sig=%02d) set\n", sig);
- }
- }
- else if (sig == HWCFUNCS_SIGNAL)
- ret = collector_sigemt_sigaction (nact, oact);
- else
- {
- if (sig != SIGCHLD || collector_sigchld_sigaction (nact, oact))
- ret = CALL_REAL (sigaction)(sig, nact, oact);
- TprintfT (DBG_LT3, "Real sigaction(sig=%02d) returned %d (oact=%p)\n",
- sig, ret, oact);
- /* but check for other important signals */
- /* check for sample and pause/resume signals; give warning once, if need be */
- if ((sig == __collector_sample_sig) && (__collector_sample_sig_warn == 0))
- {
- /* give user a warning */
- (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
- SP_JCMD_CWARN, COL_WARN_SAMPSIGUSED, __collector_sample_sig);
- __collector_sample_sig_warn = 1;
- }
- if ((sig == __collector_pause_sig) && (__collector_pause_sig_warn == 0))
- {
- /* give user a warning */
- (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
- SP_JCMD_CWARN, COL_WARN_PAUSESIGUSED, __collector_pause_sig);
- __collector_pause_sig_warn = 1;
- }
- }
- TprintfT (DBG_LT3, "sigaction() returning %d (oact=%p)\n", ret, oact);
- return ret;
- }
- /*
- * In addition to interposing on sigaction(), should we also interpose
- * on other important signal functions like signal() or sigset()?
- * - On Solaris, those other functions apparently call sigaction().
- * So, we only have to interpose on it.
- * - On Linux, we should perhaps interpose on these other functions,
- * but they are less portable than sigaction() and deprecated or even obsolete.
- * So, we interpose, but don't overly worry about doing a good job.
- */
- sighandler_t
- signal (int sig, sighandler_t handler)
- {
- struct sigaction nact;
- struct sigaction oact;
- TprintfT (DBG_LT3, "signal(sig=%02d, handler=%p) interposing\n", sig, handler);
- sigemptyset (&nact.sa_mask);
- nact.sa_handler = handler;
- nact.sa_flags = SA_RESTART;
- if (sigaction (sig, &nact, &oact))
- return SIG_ERR;
- TprintfT (DBG_LT3, "signal() returning %p\n", oact.sa_handler);
- return oact.sa_handler;
- }
- sighandler_t
- sigset (int sig, sighandler_t handler)
- {
- TprintfT (DBG_LT3, "sigset(sig=%02d, handler=%p) interposing\n", sig, handler);
- return signal (sig, handler);
- }
- /*------------------------------------------------------------- timer_create */
- // map interposed symbol versions
- #if WSIZE(64)
- #if ARCH(SPARC) || ARCH(Intel)
- static int
- __collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid, struct sigevent *sevp,
- timer_t *timerid);
- SYMVER_ATTRIBUTE (__collector_timer_create_2_3_3, timer_create@@GLIBC_2.3.3)
- int
- __collector_timer_create_2_3_3 (clockid_t clockid, struct sigevent *sevp,
- timer_t *timerid)
- {
- if (NULL_PTR (timer_create))
- init_interposition_intf ();
- TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_3_3@%p\n", CALL_REAL (timer_create_2_3_3));
- return __collector_timer_create_symver (CALL_REAL (timer_create_2_3_3), clockid, sevp, timerid);
- }
- #endif /* ARCH(SPARC) || ARCH(Intel)*/
- #if ARCH(SPARC)
- SYMVER_ATTRIBUTE (__collector_timer_create_2_2, timer_create@GLIBC_2.2)
- int
- __collector_timer_create_2_2 (clockid_t clockid, struct sigevent *sevp,
- timer_t *timerid)
- {
- if (NULL_PTR (timer_create))
- init_interposition_intf ();
- TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2@%p\n", CALL_REAL (timer_create_2_2));
- return __collector_timer_create_symver (CALL_REAL (timer_create_2_2), clockid, sevp, timerid);
- }
- #elif ARCH(Intel)
- SYMVER_ATTRIBUTE (__collector_timer_create_2_2_5, timer_create@GLIBC_2.2.5)
- int
- __collector_timer_create_2_2_5 (clockid_t clockid, struct sigevent *sevp,
- timer_t *timerid)
- {
- if (NULL_PTR (timer_create))
- init_interposition_intf ();
- TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2_5@%p\n", CALL_REAL (timer_create_2_2_5));
- return __collector_timer_create_symver (CALL_REAL (timer_create_2_2_5), clockid, sevp, timerid);
- }
- #endif /* ARCH() */
- #endif /* WSIZE(64) */
- #if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
- int timer_create (clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
- #else
- static int
- __collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid,
- struct sigevent *sevp, timer_t *timerid)
- #endif
- {
- int ret;
- if (NULL_PTR (timer_create))
- init_interposition_intf ();
- /* collector reserves SIGPROF
- */
- if (sevp == NULL || sevp->sigev_notify != SIGEV_SIGNAL
- || sevp->sigev_signo != SIGPROF)
- {
- #if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
- ret = CALL_REAL (timer_create)(clockid, sevp, timerid);
- #else
- ret = (real_timer_create) (clockid, sevp, timerid);
- #endif
- TprintfT (DBG_LT2, "Real timer_create(%d) returned %d\n",
- clockid, ret);
- return ret;
- }
- /* log that application's timer_create request is overridden */
- (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
- SP_JCMD_CWARN, COL_WARN_ITMROVR, -1);
- ret = -1;
- errno = EBUSY;
- TprintfT (DBG_LT2, "timer_create() returning %d\n", ret);
- return ret;
- }
- /*------------------------------------------------------------- setitimer */
- int
- _setitimer (int which, const struct itimerval *nval,
- struct itimerval *oval)
- {
- int ret;
- int period;
- if (NULL_PTR (setitimer))
- init_interposition_intf ();
- if (nval == NULL)
- period = -1;
- else
- period = (nval->it_interval.tv_sec * MICROSEC) +
- nval->it_interval.tv_usec;
- TprintfT (DBG_LT1, "setitimer(which=%d,nval=%dus) interposing\n", which, period);
- /* collector reserves ITIMER_REALPROF for its own use, and ITIMER_PROF
- * uses the same signal (SIGPROF) so it must also be reserved
- */
- if (((which != ITIMER_REALPROF) && (which != ITIMER_PROF)) || (nval == NULL))
- {
- ret = CALL_REAL (setitimer)(which, nval, oval);
- if (oval == NULL)
- period = -1;
- else
- period = (oval->it_interval.tv_sec * MICROSEC) +
- oval->it_interval.tv_usec;
- TprintfT (DBG_LT2, "Real setitimer(%d) returned %d (oval=%dus)\n",
- which, ret, period);
- return ret;
- }
- /* log that application's setitimer request is overridden */
- (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
- SP_JCMD_CWARN, COL_WARN_ITMROVR, period);
- if (oval == NULL)
- period = -1;
- else
- {
- getitimer (which, oval); /* return current itimer setting */
- period = (oval->it_interval.tv_sec * MICROSEC) +
- oval->it_interval.tv_usec;
- }
- ret = -1;
- errno = EBUSY;
- TprintfT (DBG_LT2, "setitimer() returning %d (oval=%dus)\n", ret, period);
- return ret;
- }
- /*--------------------------------------------------------------- sigprocmask */
- int
- __collector_sigprocmask (int how, const sigset_t* iset, sigset_t* oset)
- {
- int err = 0;
- if (NULL_PTR (sigprocmask))
- err = init_interposition_intf ();
- if (err)
- return -1;
- TprintfT (DBG_LT2, "__collector_sigprocmask(%d) interposing\n", how);
- sigset_t lsigset;
- sigset_t* lset = NULL;
- if (iset)
- {
- lsigset = *iset;
- lset = &lsigset;
- if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
- protect_profiling_signals (lset);
- }
- int ret = CALL_REAL (sigprocmask)(how, lset, oset);
- TprintfT (DBG_LT2, "__collector_sigprocmask(%d) returning %d\n", how, ret);
- return ret;
- }
- /*------------------------------------------------------------ thr_sigsetmask */
- int
- __collector_thr_sigsetmask (int how, const sigset_t* iset, sigset_t* oset)
- {
- if (NULL_PTR (thr_sigsetmask))
- init_interposition_intf ();
- TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) interposing\n", how);
- sigset_t lsigset;
- sigset_t* lset = NULL;
- if (iset)
- {
- lsigset = *iset;
- lset = &lsigset;
- if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
- protect_profiling_signals (lset);
- }
- int ret = CALL_REAL (thr_sigsetmask)(how, lset, oset);
- TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) returning %d\n", how, ret);
- return ret;
- }
- /*----------------------------------------------------------- pthread_sigmask */
- int
- pthread_sigmask (int how, const sigset_t* iset, sigset_t* oset)
- {
- if (NULL_PTR (pthread_sigmask))
- init_interposition_intf ();
- TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) interposing\n", how);
- sigset_t lsigset;
- sigset_t* lset = NULL;
- if (iset)
- {
- lsigset = *iset;
- lset = &lsigset;
- if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
- protect_profiling_signals (lset);
- }
- int ret = CALL_REAL (pthread_sigmask)(how, lset, oset);
- TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) returning %d\n", how, ret);
- return ret;
- }
- /*----------------------------------------------------------- pthread_create */
- typedef struct _CollectorArgs
- {
- void *(*func)(void*);
- void *arg;
- void *stack;
- int isPthread;
- } CollectorArgs;
- static void *
- collector_root (void *cargs)
- {
- /* save the real arguments and free cargs */
- void *(*func)(void*) = ((CollectorArgs*) cargs)->func;
- void *arg = ((CollectorArgs*) cargs)->arg;
- void *stack = ((CollectorArgs*) cargs)->stack;
- int isPthread = ((CollectorArgs*) cargs)->isPthread;
- __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
- /* initialize tsd for this thread */
- if (__collector_tsd_allocate () == 0)
- /* init tsd for unwind, called right after __collector_tsd_allocate()*/
- __collector_ext_unwind_key_init (isPthread, stack);
- if (!isPthread)
- __collector_mutex_lock (&collector_clone_libc_lock);
- /* set the profile timer */
- timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
- timer_t timerid = NULL;
- if (timeridptr != NULL)
- {
- collector_timer_create (timeridptr);
- if (*timeridptr != NULL)
- collector_timer_settime (itimer_period_requested, *timeridptr);
- timerid = *timeridptr;
- }
- int hwc_rc = __collector_ext_hwc_lwp_init ();
- if (!isPthread)
- __collector_mutex_unlock (&collector_clone_libc_lock);
- /* call the real function */
- void *ret = func (arg);
- if (!isPthread)
- __collector_mutex_lock (&collector_clone_libc_lock);
- if (timerid != NULL)
- CALL_REAL (timer_delete)(timerid);
- if (!hwc_rc)
- /* pthread_kill not handled here */
- __collector_ext_hwc_lwp_fini ();
- if (!isPthread)
- __collector_mutex_unlock (&collector_clone_libc_lock);
- /* if we have this chance, release tsd */
- __collector_tsd_release ();
- return ret;
- }
- // map interposed symbol versions
- #if ARCH(Intel) && WSIZE(32)
- static int
- __collector_pthread_create_symver (int(real_pthread_create) (),
- pthread_t *thread,
- const pthread_attr_t *attr,
- void *(*func)(void*),
- void *arg);
- SYMVER_ATTRIBUTE (__collector_pthread_create_2_1, pthread_create@@GLIBC_2.1)
- int
- __collector_pthread_create_2_1 (pthread_t *thread,
- const pthread_attr_t *attr,
- void *(*func)(void*),
- void *arg)
- {
- if (NULL_PTR (pthread_create))
- init_interposition_intf ();
- TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_1@%p\n", CALL_REAL (pthread_create_2_1));
- return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_1), thread, attr, func, arg);
- }
- SYMVER_ATTRIBUTE (__collector_pthread_create_2_0, pthread_create@GLIBC_2.0)
- int
- __collector_pthread_create_2_0 (pthread_t *thread,
- const pthread_attr_t *attr,
- void *(*func)(void*),
- void *arg)
- {
- if (NULL_PTR (pthread_create))
- init_interposition_intf ();
- TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_0@%p\n", CALL_REAL (pthread_create_2_0));
- return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_0), thread, attr, func, arg);
- }
- #endif
- #if ARCH(Intel) && WSIZE(32)
- static int
- __collector_pthread_create_symver (int(real_pthread_create) (),
- pthread_t *thread,
- const pthread_attr_t *attr,
- void *(*func)(void*),
- void *arg)
- #else
- int
- pthread_create (pthread_t *thread, const pthread_attr_t *attr,
- void *(*func)(void*), void *arg)
- #endif
- {
- if (NULL_PTR (pthread_create))
- init_interposition_intf ();
- TprintfT (DBG_LT1, "pthread_create interposition called\n");
- if (dispatch_mode != DISPATCH_ON)
- {
- #if ARCH(Intel) && WSIZE(32)
- return (real_pthread_create) (thread, attr, func, arg);
- #else
- return CALL_REAL (pthread_create)(thread, attr, func, arg);
- #endif
- }
- CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
- if (cargs == NULL)
- {
- #if ARCH(Intel) && WSIZE(32)
- return (real_pthread_create) (thread, attr, func, arg);
- #else
- return CALL_REAL (pthread_create)(thread, attr, func, arg);
- #endif
- }
- cargs->func = func;
- cargs->arg = arg;
- cargs->stack = NULL;
- cargs->isPthread = 1;
- int ret = -1;
- #if ARCH(Intel) && WSIZE(32)
- ret = (real_pthread_create) (thread, attr, &collector_root, cargs);
- #else
- ret = CALL_REAL (pthread_create)(thread, attr, &collector_root, cargs);
- #endif
- if (ret)
- __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
- TprintfT (DBG_LT1, "pthread_create returning %d\n", ret);
- return ret;
- }
- int
- __collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
- va_list va /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
- {
- if (NULL_PTR (clone))
- init_interposition_intf ();
- TprintfT (0, "clone thread interposing\n");
- pid_t * ptid = NULL;
- struct user_desc * tls = NULL;
- pid_t * ctid = NULL;
- int num_args = 0;
- if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
- {
- ptid = va_arg (va, pid_t *);
- tls = va_arg (va, struct user_desc*);
- ctid = va_arg (va, pid_t *);
- num_args = 3;
- }
- else if (flags & CLONE_SETTLS)
- {
- ptid = va_arg (va, pid_t *);
- tls = va_arg (va, struct user_desc*);
- num_args = 2;
- }
- else if (flags & CLONE_PARENT_SETTID)
- {
- ptid = va_arg (va, pid_t *);
- num_args = 1;
- }
- int ret = 0;
- if (dispatch_mode != DISPATCH_ON)
- {
- switch (num_args)
- {
- case 3:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
- break;
- case 2:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
- break;
- case 1:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
- break;
- default:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
- break;
- }
- return ret;
- }
- CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
- if (cargs == NULL)
- {
- switch (num_args)
- {
- case 3:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
- break;
- case 2:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
- break;
- case 1:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
- break;
- default:
- ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
- break;
- }
- return ret;
- }
- cargs->func = (void *(*)(void*))fn;
- cargs->arg = arg;
- cargs->stack = child_stack;
- cargs->isPthread = 0;
- switch (num_args)
- {
- case 3:
- ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls, ctid);
- break;
- case 2:
- ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls);
- break;
- case 1:
- ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid);
- break;
- default:
- ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs);
- break;
- }
- if (ret < 0)
- __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
- TprintfT (DBG_LT1, "clone thread returning %d\n", ret);
- return ret;
- }
- // weak symbols:
- int sigprocmask () __attribute__ ((weak, alias ("__collector_sigprocmask")));
- int thr_sigsetmask () __attribute__ ((weak, alias ("__collector_thr_sigsetmask")));
- int setitimer () __attribute__ ((weak, alias ("_setitimer")));
|