@@ -35,6 +35,7 @@ pub struct Profiler {
3535 old_sigaction : Option < signal:: SigAction > ,
3636 running : bool ,
3737
38+ on_stack : bool ,
3839 #[ cfg( any(
3940 target_arch = "x86_64" ,
4041 target_arch = "aarch64" ,
@@ -47,6 +48,7 @@ pub struct Profiler {
4748#[ derive( Clone ) ]
4849pub struct ProfilerGuardBuilder {
4950 frequency : c_int ,
51+ on_stack : bool ,
5052 #[ cfg( any(
5153 target_arch = "x86_64" ,
5254 target_arch = "aarch64" ,
@@ -60,6 +62,7 @@ impl Default for ProfilerGuardBuilder {
6062 fn default ( ) -> ProfilerGuardBuilder {
6163 ProfilerGuardBuilder {
6264 frequency : 99 ,
65+ on_stack : false ,
6366
6467 #[ cfg( any(
6568 target_arch = "x86_64" ,
@@ -77,6 +80,14 @@ impl ProfilerGuardBuilder {
7780 Self { frequency, ..self }
7881 }
7982
83+ /// Sets whether to use an alternate signal stack.
84+ ///
85+ /// This should be enabled when the profiler is used in an environment
86+ /// with small stacks (e.g., inside a Go program) to prevent stack overflow.
87+ pub fn on_stack ( self , on_stack : bool ) -> Self {
88+ Self { on_stack, ..self }
89+ }
90+
8091 #[ cfg( any(
8192 target_arch = "x86_64" ,
8293 target_arch = "aarch64" ,
@@ -127,6 +138,7 @@ impl ProfilerGuardBuilder {
127138 Err ( Error :: CreatingError )
128139 }
129140 Ok ( profiler) => {
141+ profiler. on_stack = self . on_stack ;
130142 #[ cfg( any(
131143 target_arch = "x86_64" ,
132144 target_arch = "aarch64" ,
@@ -391,6 +403,7 @@ impl Profiler {
391403 old_sigaction : None ,
392404 running : false ,
393405
406+ on_stack : false ,
394407 #[ cfg( any(
395408 target_arch = "x86_64" ,
396409 target_arch = "aarch64" ,
@@ -452,16 +465,16 @@ impl Profiler {
452465
453466 fn register_signal_handler ( & mut self ) -> Result < ( ) > {
454467 let handler = signal:: SigHandler :: SigAction ( perf_signal_handler) ;
455- let sigaction = signal :: SigAction :: new (
456- handler ,
457- // SA_RESTART will only restart a syscall when it's safe to do so,
458- // e.g. when it's a blocking read(2) or write(2). See man 7 signal.
468+ // SA_RESTART will only restart a syscall when it's safe to do so,
469+ // e.g. when it's a blocking read(2) or write(2). See man 7 signal.
470+ let mut flags = signal :: SaFlags :: SA_SIGINFO | signal :: SaFlags :: SA_RESTART ;
471+ if self . on_stack {
459472 // SA_ONSTACK will deliver the signal on an alternate stack. This is crucial
460473 // to prevent a stack overflow if the signal arrives at a thread with
461474 // a small stack, which is common when use pprof-rs in Go runtimes.
462- signal :: SaFlags :: SA_SIGINFO | signal:: SaFlags :: SA_RESTART | signal :: SaFlags :: SA_ONSTACK ,
463- signal :: SigSet :: empty ( ) ,
464- ) ;
475+ flags |= signal:: SaFlags :: SA_ONSTACK ;
476+ }
477+ let sigaction = signal :: SigAction :: new ( handler , flags , signal :: SigSet :: empty ( ) ) ;
465478 let old_action = unsafe { signal:: sigaction ( signal:: SIGPROF , & sigaction) } ?;
466479 self . old_sigaction = Some ( old_action) ;
467480 Ok ( ( ) )
0 commit comments