Update year range in gprofng copyright notices
[binutils-gdb.git] / gprofng / libcollector / dispatcher.c
blob0075f232cc84a087e769d76de072aebf9f8cccdb
1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
2 Contributed by Oracle.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
22 * Central SIGPROF dispatcher to various module event handlers
23 * (REALPROF profile, HWC check, overview sample, manual sample)
26 #include "config.h"
27 #include <dlfcn.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/param.h>
34 #include <sys/syscall.h>
35 #include <time.h>
36 #include <signal.h>
38 #include "gp-defs.h"
39 #include "gp-experiment.h"
40 #include "collector.h"
41 #include "collector_module.h"
42 #include "tsd.h"
43 #include "hwcdrv.h"
46 /* TprintfT(<level>,...) definitions. Adjust per module as needed */
47 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
48 #define DBG_LTT 0 // for interposition on GLIBC functions
49 #define DBG_LT1 1 // for configuration details, warnings
50 #define DBG_LT2 2
51 #define DBG_LT3 3
53 static void collector_sigprof_dispatcher (int, siginfo_t*, void*);
54 static int init_interposition_intf ();
55 #include "memmgr.h"
56 static int collector_timer_create (timer_t * ptimerid);
57 static int collector_timer_settime (int period, timer_t timerid);
58 static int collector_timer_gettime (timer_t timerid);
59 static volatile int collector_sigprof_entries = 0; /* counter for SIGPROF signals in DISPATCH_TST mode */
60 static timer_t collector_master_thread_timerid = NULL;
61 static collector_mutex_t collector_clone_libc_lock = COLLECTOR_MUTEX_INITIALIZER;
62 static unsigned dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
64 static void *__real_clone = NULL;
65 static void *__real_timer_create = NULL;
66 static void *__real_timer_settime = NULL;
67 static void *__real_timer_delete = NULL;
68 static void *__real_timer_gettime = NULL;
69 #if ARCH(Intel) && WSIZE(32)
70 static void *__real_pthread_create_2_1 = NULL;
71 static void *__real_pthread_create_2_0 = NULL;
72 #elif ARCH(Intel) && WSIZE(64)
73 static void *__real_timer_create_2_3_3 = NULL;
74 static void *__real_timer_create_2_2_5 = NULL;
75 #elif ARCH(SPARC) && WSIZE(64)
76 static void *__real_timer_create_2_3_3 = NULL;
77 static void *__real_timer_create_2_2 = NULL;
78 #endif
80 /* Original SIGPROF handler which will be replaced with the dispatcher. Used
81 * to properly interact with libaio, which uses SIGPROF as its SIGAIOCANCEL. */
82 static struct sigaction original_sigprof_handler;
84 enum
86 DISPATCH_NYI = -1, /* dispatcher not yet installed */
87 DISPATCH_OFF = 0, /* dispatcher installed, but disabled */
88 DISPATCH_ON = 1, /* dispatcher installed, and enabled */
89 DISPATCH_TST = 2 /* dispatcher installed, and enabled in testing mode */
92 static int dispatch_mode = DISPATCH_NYI; /* controls SIGPROF dispatching */
93 static int itimer_period_requested = 0; /* dispatcher itimer period */
94 static int itimer_period_actual = 0; /* actual dispatcher itimer period */
96 #define CALL_REAL(x) (*(int(*)())__real_##x)
97 #define NULL_PTR(x) ( __real_##x == NULL )
99 static void *__real_sigaction = NULL;
100 static void *__real_setitimer = NULL;
101 static void *__real_libc_setitimer = NULL;
102 static void *__real_sigprocmask = NULL;
103 static void *__real_thr_sigsetmask = NULL;
104 static void *__real_pthread_sigmask = NULL;
105 static void *__real_pthread_create = NULL;
108 * void collector_sigprof_dispatcher()
110 * Common SIGPROF event handler which dispatches events to appropriate
111 * module handlers, if they are active for this collection and due.
112 * Dispatch sequence, logic and handlers currently hardcoded in dispatcher.
114 static void
115 collector_sigprof_dispatcher (int sig, siginfo_t *info, void *context)
117 if (info == NULL || (info->si_code <= 0 && info->si_code != SI_TIMER))
119 TprintfT (DBG_LT2, "collector_sigprof_dispatcher signal for %p\n",
120 original_sigprof_handler.sa_handler);
121 /* pass signal to previous handler */
122 /* watch for recursion, SIG_IGN, and SIG_DFL */
123 if (original_sigprof_handler.sa_handler == SIG_DFL)
124 __collector_SIGDFL_handler (SIGPROF);
125 else if (original_sigprof_handler.sa_handler != SIG_IGN &&
126 original_sigprof_handler.sa_sigaction != &collector_sigprof_dispatcher)
128 (original_sigprof_handler.sa_sigaction)(sig, info, context);
129 TprintfT (DBG_LT2, "collector_sigprof_dispatcher handled\n");
132 else if (dispatch_mode == DISPATCH_ON)
134 #if ARCH(SPARC)
135 ucontext_t uctxmem;
136 ucontext_t *uctx = &uctxmem;
137 uctx->uc_link = NULL;
138 /* 23340823 signal handler third argument should point to a ucontext_t */
139 /* Convert sigcontext to ucontext_t on sparc-Linux */
140 struct sigcontext *sctx = (struct sigcontext*) context;
141 #if WSIZE(32)
142 uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
143 __collector_memcpy (&uctx->uc_mcontext.gregs[3],
144 sctx->si_regs.u_regs,
145 sizeof (sctx->si_regs.u_regs));
146 #else
147 uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
148 __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
149 sctx->sigc_regs.u_regs,
150 sizeof (sctx->sigc_regs.u_regs));
151 #endif /* WSIZE() */
153 #else /* not sparc-Linux */
154 ucontext_t *uctx = (ucontext_t*) context;
155 #endif /* ARCH() */
156 TprintfT (DBG_LT3, "collector_sigprof_dispatcher dispatching signal\n");
158 /* XXXX the order of these checks/activities may need adjustment */
159 /* XXXX should also check (first) for a "cached" manual sample */
160 /* HWC check for each LWP: required even if collection is paused */
161 /* This should be first, otherwise it's likely to find the counters
162 * stopped due to an event/overflow during some of the other activities.
164 /* XXXX HWC check performed every time (skipping if HWC profiling inactive)
165 * to avoid complexity of maintaining separate check times for each LWP
167 __collector_ext_hwc_check (info, uctx);
169 /* XXXX if sigemtpending, should perhaps skip __collector_ext_usage_sample
170 * (and get it next time through)
173 /* check for experiment past delay start */
174 if (__collector_delay_start != 0)
176 hrtime_t now = __collector_gethrtime ();
177 if (__collector_delay_start < now)
179 TprintfT (0, "__collector_ext_usage_sample: now (%lld) > delay_start (%lld)\n",
180 (now - __collector_start_time), (__collector_delay_start - __collector_start_time));
182 /* resume the data collection */
183 __collector_delay_start = 0;
184 __collector_resume ();
186 /* don't take a periodic sample, just let the resume sample cover it */
187 if (__collector_sample_period != 0)
189 /* this update should only be done for periodic samples */
190 while (__collector_next_sample < now)
191 __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
193 /* return; */
196 /* check for periodic sampling */
197 if (__collector_gethrtime () > __collector_next_sample)
198 __collector_ext_usage_sample (PERIOD_SMPL, "periodic");
200 /* check for experiment past termination time */
201 if (__collector_exp_active && __collector_terminate_time != 0)
203 hrtime_t now = __collector_gethrtime ();
204 if (__collector_terminate_time < now)
206 TprintfT (0, "__collector_ext_usage_sample: now (%lld) > terminate_time (%lld); closing experiment\n",
207 (now - __collector_start_time), (__collector_terminate_time - __collector_start_time));
208 /* close the experiment */
209 __collector_close_experiment ();
213 /* call the code to process the profile data, and generate the packet */
214 /* (must always be called, otherwise profile data must be aggregated,
215 * but can be left till last, as already have the required data)
217 __collector_ext_profile_handler (info, uctx);
219 else if (dispatch_mode == DISPATCH_TST)
221 collector_sigprof_entries++;
222 return;
227 * __collector_sigprof_install
230 __collector_sigprof_install ()
232 TprintfT (DBG_LT2, "__collector_sigprof_install\n");
233 struct sigaction oact;
234 if (__collector_sigaction (SIGPROF, NULL, &oact) != 0)
235 return COL_ERROR_DISPINIT;
236 if (oact.sa_sigaction == collector_sigprof_dispatcher)
237 /* signal handler is already in place; we are probably in a fork-child */
238 TprintfT (DBG_LT1, "dispatcher: __collector_ext_dispatcher_install() collector_sigprof_dispatcher already installed\n");
239 else
241 struct sigaction c_act;
242 CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
243 sigemptyset (&c_act.sa_mask);
244 sigaddset (&c_act.sa_mask, HWCFUNCS_SIGNAL); /* block SIGEMT delivery in handler */
245 c_act.sa_sigaction = collector_sigprof_dispatcher;
246 c_act.sa_flags = SA_RESTART | SA_SIGINFO;
247 if (__collector_sigaction (SIGPROF, &c_act, &original_sigprof_handler))
248 return COL_ERROR_DISPINIT;
250 dispatch_mode = DISPATCH_OFF; /* don't dispatch yet */
251 TprintfT (DBG_LT2, "__collector_sigprof_install done\n");
252 return COL_ERROR_NONE;
256 * void __collector_ext_dispatcher_tsd_create_key()
258 * create tsd key for dispatcher
260 void
261 __collector_ext_dispatcher_tsd_create_key ()
263 dispatcher_key = __collector_tsd_create_key (sizeof (timer_t), NULL, NULL);
266 * int __collector_ext_dispatcher_install()
268 * installs a common handler/dispatcher (and itimer) for SIGPROF events
271 __collector_ext_dispatcher_install ()
273 int timer_period;
274 TprintfT (DBG_LT2, "__collector_ext_dispatcher_install\n");
276 /* check period set for interval timer, which will be used as the basis
277 * for all timed activities: if not set, no role for SIGPROF dispatcher
279 if (itimer_period_requested <= 0)
281 TprintfT (DBG_LT1, "No interval timer set: skipping dispatcher install!\n");
282 return COL_ERROR_NONE; /* no itimer/dispatcher required */
285 /* check for an existing interval timer */
286 if (collector_master_thread_timerid == NULL)
287 if (collector_timer_create (&collector_master_thread_timerid) < 0)
288 return COL_ERROR_ITMRINIT;
289 timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
290 if (timeridptr != NULL)
291 *timeridptr = collector_master_thread_timerid; // store for per thread timer stop/start
292 TprintfT (DBG_LT3, "__collector_ext_dispatcher_install: collector_master_thread_timerid=%p\n",
293 collector_master_thread_timerid);
294 timer_period = collector_timer_gettime (collector_master_thread_timerid);
295 if (timer_period > 0)
297 TprintfT (DBG_LT1, "Overriding app-set interval timer with period %d\n", timer_period);
298 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d->%d</event>\n",
299 SP_JCMD_CWARN, COL_WARN_ITMRPOVR, timer_period, itimer_period_requested);
301 /* install the interval timer used for all timed activities */
302 if (collector_timer_settime (itimer_period_requested, collector_master_thread_timerid) < 0)
303 return COL_ERROR_ITMRINIT;
304 TprintfT (DBG_LT2, "__collector_ext_dispatcher_install done\n");
305 dispatch_mode = DISPATCH_ON; /* activate SIGPROF dispatch to event handlers */
306 return COL_ERROR_NONE;
310 __collector_sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
312 TprintfT (DBG_LT1, "__collector_sigaction: %d, %p\n", sig, nact ? nact->sa_sigaction : NULL);
313 if (NULL_PTR (sigaction))
314 init_interposition_intf ();
316 /* Whether we change the signal handler in the kernel
317 * or not make sure the real sigaction is aware about
318 * our new handler (6227565)
320 return CALL_REAL (sigaction)(sig, nact, oact);
324 * We have special dispatchers for SIGPROF and HWCFUNCS_SIGNAL to
325 * decide whether the signal was intended for us or for the user.
326 * One special case is SIGDFL, in which case we don't have a
327 * user-function address to call. If the user did indeed set
328 * default disposition for one of these signals and sent that
329 * signal, we honor that action, even though it will lead to
330 * termination.
332 void
333 __collector_SIGDFL_handler (int sig)
335 /* remove our dispatcher, replacing it with the default disposition */
336 struct sigaction act;
337 CALL_UTIL (memset)(&act, 0, sizeof (act));
338 act.sa_handler = SIG_DFL;
339 if (__collector_sigaction (sig, &act, NULL))
341 /* XXXXXX what are we supposed to do here? we're committing suicide anyhow */
343 /* resend the signal we intercepted earlier */
344 // XXXX Bug 18177509 - additional sigprof signal kills target program
345 kill (getpid (), sig);
349 * suspend/resume timer per thread
351 void
352 __collector_ext_dispatcher_thread_timer_suspend ()
354 timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
355 if (timeridptr != NULL && *timeridptr != NULL)
356 (void) collector_timer_settime (0, *timeridptr);
357 return;
361 __collector_ext_dispatcher_thread_timer_resume ()
363 timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
364 if (timeridptr == NULL)
365 return -1;
366 if (*timeridptr == NULL)
367 { // timer id not initialized yet
368 TprintfT (DBG_LT2, "__collector_ext_dispatcher_thread_timer_resume: timer not initialized yet, create it\n");
369 if (collector_timer_create (timeridptr) == -1)
371 TprintfT (0, "__collector_ext_dispatcher_thread_timer_resume(): WARNING: No timer created\n");
372 return -1;
375 return collector_timer_settime (itimer_period_requested, *timeridptr);
378 void
379 __collector_ext_dispatcher_suspend ()
381 TprintfT (DBG_LT2, "__collector_ext_dispatcher_suspend\n");
382 if (dispatch_mode == DISPATCH_NYI)
384 TprintfT (0, "__collector_ext_dispatcher_suspend(): WARNING: No dispatcher installed\n");
385 return;
388 /* disable SIGPROF dispatching */
389 dispatch_mode = DISPATCH_OFF;
391 /* disable the interval timer; ignore any failures */
392 __collector_ext_dispatcher_thread_timer_suspend ();
393 return;
396 void
397 __collector_ext_dispatcher_restart ()
399 TprintfT (DBG_LT2, "__collector_ext_dispatcher_restart(ip=%d)\n", itimer_period_requested);
400 if (dispatch_mode == DISPATCH_NYI)
402 TprintfT (0, "__collector_ext_dispatcher_restart(): WARNING: No dispatcher installed\n");
403 return;
406 /* restart the interval timer used for all timed activities */
407 if (__collector_ext_dispatcher_thread_timer_resume () == 0)
408 dispatch_mode = DISPATCH_ON; /* re-activate SIGPROF dispatch to handlers */
409 return;
412 * void __collector_ext_dispatcher_deinstall()
414 * If installed, disables SIGPROF dispatch and interval timer.
415 * Includes checks for last SIGPROF dispatch time, interval timer period,
416 * and currently installed SIGPROF handler, with appropriate warnings logged.
417 * The dispatcher remains installed to handle pending collector SIGPROFs and
418 * forward non-collector SIGPROFs to the application's handler(s).
419 * If the decision is ever made actually to deinstall the dispatcher,
420 * consider bug 4183714 and what to do about any possible pending
421 * SIGPROFs.
424 void
425 __collector_ext_dispatcher_deinstall ()
427 TprintfT (DBG_LT1, "__collector_ext_dispatcher_deinstall()\n");
428 if (dispatch_mode == DISPATCH_NYI)
430 TprintfT (0, "__collector_ext_dispatcher_deinstall(): WARNING: No dispatcher installed\n");
431 return;
433 dispatch_mode = DISPATCH_OFF; /* disable SIGPROF dispatching */
435 /* verify that interval timer is still installed with expected period */
436 int timer_period = collector_timer_gettime (collector_master_thread_timerid);
437 if (timer_period != itimer_period_actual)
439 TprintfT (DBG_LT2, "dispatcher: Collector interval timer period changed %d -> %d\n",
440 itimer_period_actual, timer_period);
441 if ((itimer_period_actual >= (timer_period + timer_period / 10)) ||
442 (itimer_period_actual <= (timer_period - timer_period / 10)))
443 __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
444 SP_JCMD_CWARN, COL_WARN_ITMRREP,
445 itimer_period_actual, timer_period);
446 else
447 __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
448 SP_JCMD_COMMENT, COL_WARN_PROFRND,
449 itimer_period_actual, timer_period);
452 /* Verify that SIGPROF dispatcher is still installed.
453 * (still required with sigaction interposition and management,
454 * since interposition is not done for attach experiments)
456 struct sigaction curr;
457 if (__collector_sigaction (SIGPROF, NULL, &curr) == -1)
458 TprintfT (0, "ERROR: dispatcher sigaction check failed: errno=%d\n", errno);
459 else if (curr.sa_sigaction != collector_sigprof_dispatcher)
461 TprintfT (0, "ERROR: collector dispatcher replaced by %p!\n", curr.sa_handler);
462 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%p</event>\n",
463 SP_JCMD_CWARN, COL_WARN_SIGPROF, curr.sa_handler);
465 else
466 TprintfT (DBG_LT2, "collector dispatcher integrity verified!\n");
468 /* disable the interval timer; ignore any failures */
469 if (collector_master_thread_timerid != NULL)
471 (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
472 collector_master_thread_timerid = NULL;
474 dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
475 itimer_period_requested = 0;
476 itimer_period_actual = 0;
480 * void __collector_ext_dispatcher_fork_child_cleanup()
482 * delete timer, clear timer interval
484 void
485 __collector_ext_dispatcher_fork_child_cleanup ()
487 if (collector_master_thread_timerid != NULL)
489 (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
490 collector_master_thread_timerid = NULL;
492 __collector_mutex_init (&collector_clone_libc_lock);
493 dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
494 itimer_period_requested = 0;
495 itimer_period_actual = 0;
498 * int __collector_ext_itimer_set (int rperiod)
500 * set itimer period, if not yet set to a positive number of microseconds,
501 * (after rounding to sys_resolution if necessary) and return its value
504 __collector_ext_itimer_set (int rperiod)
506 int period;
507 /* if rperiod is negative, force setting */
508 if (rperiod < 0)
510 itimer_period_actual = 0;
511 period = -rperiod;
513 else
514 period = rperiod;
516 // ignore SIGPROF while testing itimer interval setting
517 int saved = dispatch_mode;
518 dispatch_mode = DISPATCH_OFF;
519 if (collector_timer_create (&collector_master_thread_timerid) == -1)
521 TprintfT (0, "__collector_ext_itimer_set(): WARNING: No timer created\n");
522 return itimer_period_actual;
524 if (collector_timer_settime (period, collector_master_thread_timerid) == 0)
526 itimer_period_actual = collector_timer_gettime (collector_master_thread_timerid);
527 (void) collector_timer_settime (0, collector_master_thread_timerid); /* XXXX unset for now */
528 itimer_period_requested = period;
529 if (itimer_period_requested != itimer_period_actual)
531 TprintfT (DBG_LT2, " itimer period %d adjusted to %d\n",
532 itimer_period_requested, itimer_period_actual);
533 // (void) __collector_log_write("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
534 // SP_JCMD_CWARN, COL_WARN_PROFRND, itimer_period_requested, itimer_period_actual);
536 else
537 TprintfT (DBG_LT2, " itimer period %d accepted\n", period);
540 // restore dispatching SIGPROF handler
541 dispatch_mode = saved;
542 TprintfT (0, "__collector_ext_itimer_set(%d), requested=%d, actual=%d)\n",
543 rperiod, itimer_period_requested, itimer_period_actual);
544 return (itimer_period_actual);
547 static int
548 collector_timer_gettime (timer_t timerid)
550 int timer_period;
551 struct itimerspec itimer;
552 if (timerid == NULL)
553 return (0); // timer was not initialized
554 if (CALL_REAL (timer_gettime)(timerid, &itimer) == -1)
556 /* this should never reasonably fail, so not worth logging */
557 TprintfT (DBG_LT1, "WARNING: timer_gettime failed: errno=%d\n", errno);
558 return (-1);
560 timer_period = ((itimer.it_interval.tv_sec * NANOSEC) +
561 itimer.it_interval.tv_nsec) / 1000;
562 TprintfT (DBG_LT2, "collector_timer_gettime (period=%d)\n", timer_period);
563 return (timer_period);
566 static int
567 collector_timer_create (timer_t * ptimerid)
569 struct sigevent sigev;
570 if (NULL_PTR (timer_create))
571 init_interposition_intf ();
572 TprintfT (DBG_LT2, "collector_timer_settime(): timer_create is %p\n", __real_timer_create);
573 sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
574 sigev.sigev_signo = SIGPROF;
575 sigev.sigev_value.sival_ptr = ptimerid;
576 #if !defined(__MUSL_LIBC)
577 sigev._sigev_un._tid = __collector_gettid ();
578 #endif
579 if (CALL_REAL (timer_create)(CLOCK_THREAD_CPUTIME_ID, &sigev, ptimerid) == -1)
581 TprintfT (DBG_LT2, "collector_timer_settime() failed! errno=%d\n", errno);
582 return -1;
584 return 0;
587 static int
588 collector_timer_settime (int period, timer_t timerid)
590 struct itimerspec itimer;
591 if (NULL_PTR (timer_settime))
592 init_interposition_intf ();
593 TprintfT (DBG_LT2, "collector_timer_settime(period=%d)\n", period);
594 time_t NPM = 1000;
595 itimer.it_interval.tv_sec = NPM * period / NANOSEC;
596 itimer.it_interval.tv_nsec = (NPM * period) % NANOSEC;
597 itimer.it_value = itimer.it_interval;
598 if (CALL_REAL (timer_settime)(timerid, 0, &itimer, NULL) == -1)
600 TprintfT (DBG_LT2, "collector_timer_settime(%d) failed! errno=%d\n", period, errno);
601 return -1;
603 return 0;
606 static void
607 protect_profiling_signals (sigset_t* lset)
609 static unsigned int protected_sigprof = 0;
610 static unsigned int protected_sigemt = 0;
611 // T1 relies on thread signal masking, so best not to mess with it:
612 // T1 users have already been warned about the dangers of its use
613 if (__collector_libthread_T1)
614 return;
615 if (sigismember (lset, SIGPROF) && (dispatch_mode == DISPATCH_ON))
617 TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGPROF");
618 if (protected_sigprof == 0)
619 __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
620 SP_JCMD_CWARN, COL_WARN_SIGMASK, "SIGPROF");
621 sigdelset (lset, SIGPROF);
622 protected_sigprof++;
624 if (sigismember (lset, HWCFUNCS_SIGNAL) && __collector_ext_hwc_active ())
626 TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGEMT");
627 if (protected_sigemt == 0)
628 __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
629 SP_JCMD_CWARN, COL_WARN_SIGMASK, HWCFUNCS_SIGNAL_STRING);
630 sigdelset (lset, HWCFUNCS_SIGNAL);
631 protected_sigemt++;
635 #define SYS_SETITIMER_NAME "setitimer"
636 #define SYS_SIGACTION_NAME "sigaction"
637 #define SYS_SIGPROCMASK_NAME "sigprocmask"
638 #define SYS_PTHREAD_SIGMASK "pthread_sigmask"
639 #define SYS_THR_SIGSETMASK "thr_sigsetmask"
641 static int
642 init_interposition_intf ()
644 if (__collector_dlsym_guard)
645 return 1;
646 void *dlflag;
647 /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
648 void *handle = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD);
650 #if ARCH(SPARC) && WSIZE(64)
651 /* dlopen a bogus path to avoid CR 23608692 */
652 dlopen ("/bogus_path_for_23608692_workaround/", RTLD_LAZY | RTLD_NOLOAD);
653 #endif
654 __real_setitimer = dlsym (RTLD_NEXT, SYS_SETITIMER_NAME);
656 if (__real_setitimer == NULL)
658 __real_setitimer = dlsym (RTLD_DEFAULT, SYS_SETITIMER_NAME);
659 if (__real_setitimer == NULL)
661 TprintfT (DBG_LT2, "init_interposition_intf() setitimer not found\n");
662 return 1;
664 dlflag = RTLD_DEFAULT;
666 else
667 dlflag = RTLD_NEXT;
669 TprintfT (DBG_LT2, "init_interposition_intf() using RTLD_%s\n",
670 (dlflag == RTLD_DEFAULT) ? "DEFAULT" : "NEXT");
671 TprintfT (DBG_LT2, "@%p __real_setitimer\n", __real_setitimer);
673 __real_sigaction = dlsym (dlflag, SYS_SIGACTION_NAME);
674 TprintfT (DBG_LT2, "@%p __real_sigaction\n", __real_sigaction);
676 /* also explicitly get libc.so/setitimer (as a backup) */
677 __real_libc_setitimer = dlsym (handle, SYS_SETITIMER_NAME);
678 TprintfT (DBG_LT2, "@%p __real_libc_setitimer\n", __real_libc_setitimer);
680 __real_sigprocmask = dlsym (dlflag, SYS_SIGPROCMASK_NAME);
681 TprintfT (DBG_LT2, "@%p __real_sigprocmask\n", __real_sigprocmask);
683 __real_thr_sigsetmask = dlsym (dlflag, SYS_THR_SIGSETMASK);
684 TprintfT (DBG_LT2, "@%p __real_thr_sigsetmask\n", __real_thr_sigsetmask);
686 __real_pthread_sigmask = dlsym (dlflag, SYS_PTHREAD_SIGMASK);
687 TprintfT (DBG_LT2, "@%p __real_pthread_sigmask\n", __real_pthread_sigmask);
689 #if ARCH(Aarch64)
690 __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
691 __real_timer_create = dlsym (dlflag, "timer_create");
692 __real_timer_settime = dlsym (dlflag, "timer_settime");
693 __real_timer_delete = dlsym (dlflag, "timer_delete");
694 __real_timer_gettime = dlsym (dlflag, "timer_gettime");
695 #else
696 __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
697 TprintfT (DBG_LT2, "[%s] @%p __real_pthread_create\n", SYS_PTHREAD_CREATE_VERSION, __real_pthread_create);
698 __real_timer_create = dlvsym (dlflag, "timer_create", SYS_TIMER_X_VERSION);
699 TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_create\n", SYS_TIMER_X_VERSION, __real_timer_create);
700 __real_timer_settime = dlvsym (dlflag, "timer_settime", SYS_TIMER_X_VERSION);
701 TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_settime\n", SYS_TIMER_X_VERSION, __real_timer_settime);
702 __real_timer_delete = dlvsym (dlflag, "timer_delete", SYS_TIMER_X_VERSION);
703 TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_delete\n", SYS_TIMER_X_VERSION, __real_timer_delete);
704 __real_timer_gettime = dlvsym (dlflag, "timer_gettime", SYS_TIMER_X_VERSION);
705 TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_gettime\n", SYS_TIMER_X_VERSION, __real_timer_gettime);
706 __real_clone = dlsym (dlflag, "clone");
707 TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
708 #if ARCH(Intel) && WSIZE(32)
709 __real_pthread_create_2_1 = __real_pthread_create;
710 __real_pthread_create_2_0 = dlvsym (dlflag, "pthread_create", "GLIBC_2.0");
711 #elif ARCH(Intel) && WSIZE(64)
712 __real_timer_create_2_3_3 = __real_timer_create;
713 __real_timer_create_2_2_5 = dlvsym (dlflag, "timer_create", "GLIBC_2.2.5");
714 #elif ARCH(SPARC) && WSIZE(64)
715 __real_timer_create_2_3_3 = __real_timer_create;
716 __real_timer_create_2_2 = dlvsym (dlflag, "timer_create", "GLIBC_2.2");
717 #endif /* ARCH() && SIZE() */
718 #endif
719 return 0;
723 /*------------------------------------------------------------- sigaction */
725 /* NB: need a global interposing function called "sigaction" */
727 sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
729 int ret = 0;
730 int err = 0;
731 if (NULL_PTR (sigaction))
732 err = init_interposition_intf ();
733 if (err)
734 return -1;
735 TprintfT (DBG_LT3, "sigaction(sig=%02d, nact=%p) interposing\n", sig, nact);
736 if (sig == SIGPROF && dispatch_mode != DISPATCH_NYI)
738 if (oact != NULL)
740 oact->sa_handler = original_sigprof_handler.sa_handler;
741 oact->sa_mask = original_sigprof_handler.sa_mask;
742 oact->sa_flags = original_sigprof_handler.sa_flags;
744 if (nact != NULL)
746 original_sigprof_handler.sa_handler = nact->sa_handler;
747 original_sigprof_handler.sa_mask = nact->sa_mask;
748 original_sigprof_handler.sa_flags = nact->sa_flags;
749 TprintfT (DBG_LT1, "dispatcher: new sigaction(sig=%02d) set\n", sig);
752 else if (sig == HWCFUNCS_SIGNAL)
753 ret = collector_sigemt_sigaction (nact, oact);
754 else
756 if (sig != SIGCHLD || collector_sigchld_sigaction (nact, oact))
757 ret = CALL_REAL (sigaction)(sig, nact, oact);
758 TprintfT (DBG_LT3, "Real sigaction(sig=%02d) returned %d (oact=%p)\n",
759 sig, ret, oact);
760 /* but check for other important signals */
761 /* check for sample and pause/resume signals; give warning once, if need be */
762 if ((sig == __collector_sample_sig) && (__collector_sample_sig_warn == 0))
764 /* give user a warning */
765 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
766 SP_JCMD_CWARN, COL_WARN_SAMPSIGUSED, __collector_sample_sig);
767 __collector_sample_sig_warn = 1;
769 if ((sig == __collector_pause_sig) && (__collector_pause_sig_warn == 0))
771 /* give user a warning */
772 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
773 SP_JCMD_CWARN, COL_WARN_PAUSESIGUSED, __collector_pause_sig);
774 __collector_pause_sig_warn = 1;
777 TprintfT (DBG_LT3, "sigaction() returning %d (oact=%p)\n", ret, oact);
778 return ret;
782 * In addition to interposing on sigaction(), should we also interpose
783 * on other important signal functions like signal() or sigset()?
784 * - On Solaris, those other functions apparently call sigaction().
785 * So, we only have to interpose on it.
786 * - On Linux, we should perhaps interpose on these other functions,
787 * but they are less portable than sigaction() and deprecated or even obsolete.
788 * So, we interpose, but don't overly worry about doing a good job.
790 sighandler_t
791 signal (int sig, sighandler_t handler)
793 struct sigaction nact;
794 struct sigaction oact;
795 TprintfT (DBG_LT3, "signal(sig=%02d, handler=%p) interposing\n", sig, handler);
796 sigemptyset (&nact.sa_mask);
797 nact.sa_handler = handler;
798 nact.sa_flags = SA_RESTART;
799 if (sigaction (sig, &nact, &oact))
800 return SIG_ERR;
801 TprintfT (DBG_LT3, "signal() returning %p\n", oact.sa_handler);
802 return oact.sa_handler;
805 sighandler_t
806 sigset (int sig, sighandler_t handler)
808 TprintfT (DBG_LT3, "sigset(sig=%02d, handler=%p) interposing\n", sig, handler);
809 return signal (sig, handler);
812 /*------------------------------------------------------------- timer_create */
814 // map interposed symbol versions
815 #if WSIZE(64)
816 #if ARCH(SPARC) || ARCH(Intel)
817 static int
818 __collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid, struct sigevent *sevp,
819 timer_t *timerid);
821 SYMVER_ATTRIBUTE (__collector_timer_create_2_3_3, timer_create@GLIBC_2.3.3)
823 __collector_timer_create_2_3_3 (clockid_t clockid, struct sigevent *sevp,
824 timer_t *timerid)
826 if (NULL_PTR (timer_create))
827 init_interposition_intf ();
828 TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_3_3@%p\n", CALL_REAL (timer_create_2_3_3));
829 return __collector_timer_create_symver (CALL_REAL (timer_create_2_3_3), clockid, sevp, timerid);
831 #endif /* ARCH(SPARC) || ARCH(Intel)*/
833 #if ARCH(SPARC)
835 SYMVER_ATTRIBUTE (__collector_timer_create_2_2, timer_create@GLIBC_2.2)
837 __collector_timer_create_2_2 (clockid_t clockid, struct sigevent *sevp,
838 timer_t *timerid)
840 if (NULL_PTR (timer_create))
841 init_interposition_intf ();
842 TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2@%p\n", CALL_REAL (timer_create_2_2));
843 return __collector_timer_create_symver (CALL_REAL (timer_create_2_2), clockid, sevp, timerid);
846 #elif ARCH(Intel)
848 SYMVER_ATTRIBUTE (__collector_timer_create_2_2_5, timer_create@GLIBC_2.2.5)
850 __collector_timer_create_2_2_5 (clockid_t clockid, struct sigevent *sevp,
851 timer_t *timerid)
853 if (NULL_PTR (timer_create))
854 init_interposition_intf ();
855 TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2_5@%p\n", CALL_REAL (timer_create_2_2_5));
856 return __collector_timer_create_symver (CALL_REAL (timer_create_2_2_5), clockid, sevp, timerid);
858 #endif /* ARCH() */
859 #endif /* WSIZE(64) */
861 #if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
862 int timer_create (clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
863 #else
864 static int
865 __collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid,
866 struct sigevent *sevp, timer_t *timerid)
867 #endif
869 int ret;
871 if (NULL_PTR (timer_create))
872 init_interposition_intf ();
874 /* collector reserves SIGPROF
876 if (sevp == NULL || sevp->sigev_notify != SIGEV_SIGNAL
877 || sevp->sigev_signo != SIGPROF)
879 #if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
880 ret = CALL_REAL (timer_create)(clockid, sevp, timerid);
881 #else
882 ret = (real_timer_create) (clockid, sevp, timerid);
883 #endif
884 TprintfT (DBG_LT2, "Real timer_create(%d) returned %d\n",
885 clockid, ret);
886 return ret;
889 /* log that application's timer_create request is overridden */
890 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
891 SP_JCMD_CWARN, COL_WARN_ITMROVR, -1);
892 ret = -1;
893 errno = EBUSY;
894 TprintfT (DBG_LT2, "timer_create() returning %d\n", ret);
895 return ret;
897 /*------------------------------------------------------------- setitimer */
899 _setitimer (int which, const struct itimerval *nval,
900 struct itimerval *oval)
902 int ret;
903 int period;
905 if (NULL_PTR (setitimer))
906 init_interposition_intf ();
908 if (nval == NULL)
909 period = -1;
910 else
911 period = (nval->it_interval.tv_sec * MICROSEC) +
912 nval->it_interval.tv_usec;
913 TprintfT (DBG_LT1, "setitimer(which=%d,nval=%dus) interposing\n", which, period);
915 /* collector reserves ITIMER_REALPROF for its own use, and ITIMER_PROF
916 * uses the same signal (SIGPROF) so it must also be reserved
918 if (((which != ITIMER_REALPROF) && (which != ITIMER_PROF)) || (nval == NULL))
920 ret = CALL_REAL (setitimer)(which, nval, oval);
921 if (oval == NULL)
922 period = -1;
923 else
924 period = (oval->it_interval.tv_sec * MICROSEC) +
925 oval->it_interval.tv_usec;
926 TprintfT (DBG_LT2, "Real setitimer(%d) returned %d (oval=%dus)\n",
927 which, ret, period);
928 return ret;
930 /* log that application's setitimer request is overridden */
931 (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
932 SP_JCMD_CWARN, COL_WARN_ITMROVR, period);
933 if (oval == NULL)
934 period = -1;
935 else
937 getitimer (which, oval); /* return current itimer setting */
938 period = (oval->it_interval.tv_sec * MICROSEC) +
939 oval->it_interval.tv_usec;
941 ret = -1;
942 errno = EBUSY;
943 TprintfT (DBG_LT2, "setitimer() returning %d (oval=%dus)\n", ret, period);
944 return ret;
947 /*--------------------------------------------------------------- sigprocmask */
949 __collector_sigprocmask (int how, const sigset_t* iset, sigset_t* oset)
951 int err = 0;
952 if (NULL_PTR (sigprocmask))
953 err = init_interposition_intf ();
954 if (err)
955 return -1;
956 TprintfT (DBG_LT2, "__collector_sigprocmask(%d) interposing\n", how);
957 sigset_t lsigset;
958 sigset_t* lset = NULL;
959 if (iset)
961 lsigset = *iset;
962 lset = &lsigset;
963 if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
964 protect_profiling_signals (lset);
966 int ret = CALL_REAL (sigprocmask)(how, lset, oset);
967 TprintfT (DBG_LT2, "__collector_sigprocmask(%d) returning %d\n", how, ret);
968 return ret;
971 /*------------------------------------------------------------ thr_sigsetmask */
973 __collector_thr_sigsetmask (int how, const sigset_t* iset, sigset_t* oset)
975 if (NULL_PTR (thr_sigsetmask))
976 init_interposition_intf ();
977 TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) interposing\n", how);
978 sigset_t lsigset;
979 sigset_t* lset = NULL;
980 if (iset)
982 lsigset = *iset;
983 lset = &lsigset;
984 if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
985 protect_profiling_signals (lset);
987 int ret = CALL_REAL (thr_sigsetmask)(how, lset, oset);
988 TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) returning %d\n", how, ret);
989 return ret;
992 /*----------------------------------------------------------- pthread_sigmask */
995 pthread_sigmask (int how, const sigset_t* iset, sigset_t* oset)
997 if (NULL_PTR (pthread_sigmask))
998 init_interposition_intf ();
999 TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) interposing\n", how);
1000 sigset_t lsigset;
1001 sigset_t* lset = NULL;
1002 if (iset)
1004 lsigset = *iset;
1005 lset = &lsigset;
1006 if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
1007 protect_profiling_signals (lset);
1009 int ret = CALL_REAL (pthread_sigmask)(how, lset, oset);
1010 TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) returning %d\n", how, ret);
1011 return ret;
1013 /*----------------------------------------------------------- pthread_create */
1014 typedef struct _CollectorArgs
1016 void *(*func)(void*);
1017 void *arg;
1018 void *stack;
1019 int isPthread;
1020 } CollectorArgs;
1022 static void *
1023 collector_root (void *cargs)
1025 /* save the real arguments and free cargs */
1026 void *(*func)(void*) = ((CollectorArgs*) cargs)->func;
1027 void *arg = ((CollectorArgs*) cargs)->arg;
1028 void *stack = ((CollectorArgs*) cargs)->stack;
1029 int isPthread = ((CollectorArgs*) cargs)->isPthread;
1030 __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
1032 /* initialize tsd for this thread */
1033 if (__collector_tsd_allocate () == 0)
1034 /* init tsd for unwind, called right after __collector_tsd_allocate()*/
1035 __collector_ext_unwind_key_init (isPthread, stack);
1037 if (!isPthread)
1038 __collector_mutex_lock (&collector_clone_libc_lock);
1040 /* set the profile timer */
1041 timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
1042 timer_t timerid = NULL;
1043 if (timeridptr != NULL)
1045 collector_timer_create (timeridptr);
1046 if (*timeridptr != NULL)
1047 collector_timer_settime (itimer_period_requested, *timeridptr);
1048 timerid = *timeridptr;
1050 int hwc_rc = __collector_ext_hwc_lwp_init ();
1052 if (!isPthread)
1053 __collector_mutex_unlock (&collector_clone_libc_lock);
1054 /* call the real function */
1055 void *ret = func (arg);
1056 if (!isPthread)
1057 __collector_mutex_lock (&collector_clone_libc_lock);
1058 if (timerid != NULL)
1059 CALL_REAL (timer_delete)(timerid);
1060 if (!hwc_rc)
1061 /* pthread_kill not handled here */
1062 __collector_ext_hwc_lwp_fini ();
1064 if (!isPthread)
1065 __collector_mutex_unlock (&collector_clone_libc_lock);
1066 /* if we have this chance, release tsd */
1067 __collector_tsd_release ();
1069 return ret;
1072 // map interposed symbol versions
1073 #if ARCH(Intel) && WSIZE(32)
1074 static int
1075 __collector_pthread_create_symver (int(real_pthread_create) (),
1076 pthread_t *thread,
1077 const pthread_attr_t *attr,
1078 void *(*func)(void*),
1079 void *arg);
1081 SYMVER_ATTRIBUTE (__collector_pthread_create_2_1, pthread_create@GLIBC_2.1)
1083 __collector_pthread_create_2_1 (pthread_t *thread,
1084 const pthread_attr_t *attr,
1085 void *(*func)(void*),
1086 void *arg)
1088 if (NULL_PTR (pthread_create))
1089 init_interposition_intf ();
1090 TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_1@%p\n", CALL_REAL (pthread_create_2_1));
1091 return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_1), thread, attr, func, arg);
1094 SYMVER_ATTRIBUTE (__collector_pthread_create_2_0, pthread_create@GLIBC_2.0)
1096 __collector_pthread_create_2_0 (pthread_t *thread,
1097 const pthread_attr_t *attr,
1098 void *(*func)(void*),
1099 void *arg)
1101 if (NULL_PTR (pthread_create))
1102 init_interposition_intf ();
1103 TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_0@%p\n", CALL_REAL (pthread_create_2_0));
1104 return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_0), thread, attr, func, arg);
1107 #endif
1109 #if ARCH(Intel) && WSIZE(32)
1110 static int
1111 __collector_pthread_create_symver (int(real_pthread_create) (),
1112 pthread_t *thread,
1113 const pthread_attr_t *attr,
1114 void *(*func)(void*),
1115 void *arg)
1116 #else
1118 pthread_create (pthread_t *thread, const pthread_attr_t *attr,
1119 void *(*func)(void*), void *arg)
1120 #endif
1122 if (NULL_PTR (pthread_create))
1123 init_interposition_intf ();
1125 TprintfT (DBG_LT1, "pthread_create interposition called\n");
1127 if (dispatch_mode != DISPATCH_ON)
1129 #if ARCH(Intel) && WSIZE(32)
1130 return (real_pthread_create) (thread, attr, func, arg);
1131 #else
1132 return CALL_REAL (pthread_create)(thread, attr, func, arg);
1133 #endif
1135 CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
1137 if (cargs == NULL)
1139 #if ARCH(Intel) && WSIZE(32)
1140 return (real_pthread_create) (thread, attr, func, arg);
1141 #else
1142 return CALL_REAL (pthread_create)(thread, attr, func, arg);
1143 #endif
1145 cargs->func = func;
1146 cargs->arg = arg;
1147 cargs->stack = NULL;
1148 cargs->isPthread = 1;
1149 int ret = -1;
1150 #if ARCH(Intel) && WSIZE(32)
1151 ret = (real_pthread_create) (thread, attr, &collector_root, cargs);
1152 #else
1153 ret = CALL_REAL (pthread_create)(thread, attr, &collector_root, cargs);
1154 #endif
1155 if (ret)
1156 __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
1157 TprintfT (DBG_LT1, "pthread_create returning %d\n", ret);
1158 return ret;
1162 __collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
1163 va_list va /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
1165 if (NULL_PTR (clone))
1166 init_interposition_intf ();
1167 TprintfT (0, "clone thread interposing\n");
1168 pid_t * ptid = NULL;
1169 struct user_desc * tls = NULL;
1170 pid_t * ctid = NULL;
1171 int num_args = 0;
1172 if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
1174 ptid = va_arg (va, pid_t *);
1175 tls = va_arg (va, struct user_desc*);
1176 ctid = va_arg (va, pid_t *);
1177 num_args = 3;
1179 else if (flags & CLONE_SETTLS)
1181 ptid = va_arg (va, pid_t *);
1182 tls = va_arg (va, struct user_desc*);
1183 num_args = 2;
1185 else if (flags & CLONE_PARENT_SETTID)
1187 ptid = va_arg (va, pid_t *);
1188 num_args = 1;
1190 int ret = 0;
1191 if (dispatch_mode != DISPATCH_ON)
1193 switch (num_args)
1195 case 3:
1196 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1197 break;
1198 case 2:
1199 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1200 break;
1201 case 1:
1202 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1203 break;
1204 default:
1205 ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1206 break;
1208 return ret;
1210 CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
1211 if (cargs == NULL)
1213 switch (num_args)
1215 case 3:
1216 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1217 break;
1218 case 2:
1219 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1220 break;
1221 case 1:
1222 ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1223 break;
1224 default:
1225 ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1226 break;
1228 return ret;
1231 cargs->func = (void *(*)(void*))fn;
1232 cargs->arg = arg;
1233 cargs->stack = child_stack;
1234 cargs->isPthread = 0;
1236 switch (num_args)
1238 case 3:
1239 ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls, ctid);
1240 break;
1241 case 2:
1242 ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls);
1243 break;
1244 case 1:
1245 ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid);
1246 break;
1247 default:
1248 ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs);
1249 break;
1252 if (ret < 0)
1253 __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
1254 TprintfT (DBG_LT1, "clone thread returning %d\n", ret);
1255 return ret;
1258 // weak symbols:
1259 int sigprocmask () __attribute__ ((weak, alias ("__collector_sigprocmask")));
1260 int thr_sigsetmask () __attribute__ ((weak, alias ("__collector_thr_sigsetmask")));
1261 int setitimer () __attribute__ ((weak, alias ("_setitimer")));