1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
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)
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)
33 #include <sys/param.h>
34 #include <sys/syscall.h>
39 #include "gp-experiment.h"
40 #include "collector.h"
41 #include "collector_module.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
53 static void collector_sigprof_dispatcher (int, siginfo_t
*, void*);
54 static int init_interposition_intf ();
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
;
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
;
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.
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
)
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
;
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
));
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
));
153 #else /* not sparc-Linux */
154 ucontext_t
*uctx
= (ucontext_t
*) context
;
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
;
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
++;
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");
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
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 ()
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
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
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
);
361 __collector_ext_dispatcher_thread_timer_resume ()
363 timer_t
* timeridptr
= __collector_tsd_get_by_key (dispatcher_key
);
364 if (timeridptr
== NULL
)
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");
375 return collector_timer_settime (itimer_period_requested
, *timeridptr
);
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");
388 /* disable SIGPROF dispatching */
389 dispatch_mode
= DISPATCH_OFF
;
391 /* disable the interval timer; ignore any failures */
392 __collector_ext_dispatcher_thread_timer_suspend ();
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");
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 */
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
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");
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
);
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
);
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
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
)
507 /* if rperiod is negative, force setting */
510 itimer_period_actual
= 0;
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);
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
);
548 collector_timer_gettime (timer_t timerid
)
551 struct itimerspec itimer
;
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
);
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
);
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 ();
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
);
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
);
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
);
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
)
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
);
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
);
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"
642 init_interposition_intf ()
644 if (__collector_dlsym_guard
)
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
);
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");
664 dlflag
= RTLD_DEFAULT
;
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
);
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");
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() */
723 /*------------------------------------------------------------- sigaction */
725 /* NB: need a global interposing function called "sigaction" */
727 sigaction (int sig
, const struct sigaction
*nact
, struct sigaction
*oact
)
731 if (NULL_PTR (sigaction
))
732 err
= init_interposition_intf ();
735 TprintfT (DBG_LT3
, "sigaction(sig=%02d, nact=%p) interposing\n", sig
, nact
);
736 if (sig
== SIGPROF
&& dispatch_mode
!= DISPATCH_NYI
)
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
;
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
);
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",
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
);
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.
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
))
801 TprintfT (DBG_LT3
, "signal() returning %p\n", oact
.sa_handler
);
802 return oact
.sa_handler
;
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
816 #if ARCH(SPARC) || ARCH(Intel)
818 __collector_timer_create_symver (int(real_timer_create
) (), clockid_t clockid
, struct sigevent
*sevp
,
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
,
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)*/
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
,
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
);
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
,
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
);
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
)
865 __collector_timer_create_symver (int(real_timer_create
) (), clockid_t clockid
,
866 struct sigevent
*sevp
, timer_t
*timerid
)
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
);
882 ret
= (real_timer_create
) (clockid
, sevp
, timerid
);
884 TprintfT (DBG_LT2
, "Real timer_create(%d) returned %d\n",
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);
894 TprintfT (DBG_LT2
, "timer_create() returning %d\n", ret
);
897 /*------------------------------------------------------------- setitimer */
899 _setitimer (int which
, const struct itimerval
*nval
,
900 struct itimerval
*oval
)
905 if (NULL_PTR (setitimer
))
906 init_interposition_intf ();
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
);
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",
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
);
937 getitimer (which
, oval
); /* return current itimer setting */
938 period
= (oval
->it_interval
.tv_sec
* MICROSEC
) +
939 oval
->it_interval
.tv_usec
;
943 TprintfT (DBG_LT2
, "setitimer() returning %d (oval=%dus)\n", ret
, period
);
947 /*--------------------------------------------------------------- sigprocmask */
949 __collector_sigprocmask (int how
, const sigset_t
* iset
, sigset_t
* oset
)
952 if (NULL_PTR (sigprocmask
))
953 err
= init_interposition_intf ();
956 TprintfT (DBG_LT2
, "__collector_sigprocmask(%d) interposing\n", how
);
958 sigset_t
* lset
= NULL
;
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
);
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
);
979 sigset_t
* lset
= NULL
;
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
);
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
);
1001 sigset_t
* lset
= NULL
;
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
);
1013 /*----------------------------------------------------------- pthread_create */
1014 typedef struct _CollectorArgs
1016 void *(*func
)(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
);
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 ();
1053 __collector_mutex_unlock (&collector_clone_libc_lock
);
1054 /* call the real function */
1055 void *ret
= func (arg
);
1057 __collector_mutex_lock (&collector_clone_libc_lock
);
1058 if (timerid
!= NULL
)
1059 CALL_REAL (timer_delete
)(timerid
);
1061 /* pthread_kill not handled here */
1062 __collector_ext_hwc_lwp_fini ();
1065 __collector_mutex_unlock (&collector_clone_libc_lock
);
1066 /* if we have this chance, release tsd */
1067 __collector_tsd_release ();
1072 // map interposed symbol versions
1073 #if ARCH(Intel) && WSIZE(32)
1075 __collector_pthread_create_symver (int(real_pthread_create
) (),
1077 const pthread_attr_t
*attr
,
1078 void *(*func
)(void*),
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*),
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*),
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
);
1109 #if ARCH(Intel) && WSIZE(32)
1111 __collector_pthread_create_symver (int(real_pthread_create
) (),
1113 const pthread_attr_t
*attr
,
1114 void *(*func
)(void*),
1118 pthread_create (pthread_t
*thread
, const pthread_attr_t
*attr
,
1119 void *(*func
)(void*), void *arg
)
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
);
1132 return CALL_REAL (pthread_create
)(thread
, attr
, func
, arg
);
1135 CollectorArgs
*cargs
= __collector_allocCSize (__collector_heap
, sizeof (CollectorArgs
), 1);
1139 #if ARCH(Intel) && WSIZE(32)
1140 return (real_pthread_create
) (thread
, attr
, func
, arg
);
1142 return CALL_REAL (pthread_create
)(thread
, attr
, func
, arg
);
1147 cargs
->stack
= NULL
;
1148 cargs
->isPthread
= 1;
1150 #if ARCH(Intel) && WSIZE(32)
1151 ret
= (real_pthread_create
) (thread
, attr
, &collector_root
, cargs
);
1153 ret
= CALL_REAL (pthread_create
)(thread
, attr
, &collector_root
, cargs
);
1156 __collector_freeCSize (__collector_heap
, cargs
, sizeof (CollectorArgs
));
1157 TprintfT (DBG_LT1
, "pthread_create returning %d\n", 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
;
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
*);
1179 else if (flags
& CLONE_SETTLS
)
1181 ptid
= va_arg (va
, pid_t
*);
1182 tls
= va_arg (va
, struct user_desc
*);
1185 else if (flags
& CLONE_PARENT_SETTID
)
1187 ptid
= va_arg (va
, pid_t
*);
1191 if (dispatch_mode
!= DISPATCH_ON
)
1196 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
, tls
, ctid
);
1199 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
, tls
);
1202 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
);
1205 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
);
1210 CollectorArgs
*cargs
= __collector_allocCSize (__collector_heap
, sizeof (CollectorArgs
), 1);
1216 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
, tls
, ctid
);
1219 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
, tls
);
1222 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
, ptid
);
1225 ret
= CALL_REAL (clone
)(fn
, child_stack
, flags
, arg
);
1231 cargs
->func
= (void *(*)(void*))fn
;
1233 cargs
->stack
= child_stack
;
1234 cargs
->isPthread
= 0;
1239 ret
= CALL_REAL (clone
)((int(*)(void*))collector_root
, child_stack
, flags
, cargs
, ptid
, tls
, ctid
);
1242 ret
= CALL_REAL (clone
)((int(*)(void*))collector_root
, child_stack
, flags
, cargs
, ptid
, tls
);
1245 ret
= CALL_REAL (clone
)((int(*)(void*))collector_root
, child_stack
, flags
, cargs
, ptid
);
1248 ret
= CALL_REAL (clone
)((int(*)(void*))collector_root
, child_stack
, flags
, cargs
);
1253 __collector_freeCSize (__collector_heap
, cargs
, sizeof (CollectorArgs
));
1254 TprintfT (DBG_LT1
, "clone thread returning %d\n", ret
);
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")));