@@ -126,6 +126,9 @@ static struct {
126126
127127 VALUE fake_frame_names [TOTAL_FAKE_FRAMES ];
128128 VALUE empty_string ;
129+
130+ int buffer_count ;
131+ sample_time_t buffer_time ;
129132 VALUE frames_buffer [BUF_SIZE ];
130133 int lines_buffer [BUF_SIZE ];
131134} _stackprof ;
@@ -594,9 +597,17 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti
594597 }
595598}
596599
600+ // buffer the current profile frames
601+ // This must be async-signal-safe
602+ // Returns immediately if another set of frames are already in the buffer
597603void
598- stackprof_record_sample ( )
604+ stackprof_buffer_sample ( void )
599605{
606+ if (_stackprof .buffer_count > 0 ) {
607+ // Another sample is already pending
608+ return ;
609+ }
610+
600611 uint64_t start_timestamp = 0 ;
601612 int64_t timestamp_delta = 0 ;
602613 int num ;
@@ -606,12 +617,16 @@ stackprof_record_sample()
606617 start_timestamp = timestamp_usec (& t );
607618 timestamp_delta = delta_usec (& t , & _stackprof .last_sample_at );
608619 }
620+
609621 num = rb_profile_frames (0 , sizeof (_stackprof .frames_buffer ) / sizeof (VALUE ), _stackprof .frames_buffer , _stackprof .lines_buffer );
610- stackprof_record_sample_for_stack (num , start_timestamp , timestamp_delta );
622+
623+ _stackprof .buffer_count = num ;
624+ _stackprof .buffer_time .timestamp_usec = start_timestamp ;
625+ _stackprof .buffer_time .delta_usec = timestamp_delta ;
611626}
612627
613628void
614- stackprof_record_gc_samples ()
629+ stackprof_record_gc_samples (void )
615630{
616631 int64_t delta_to_first_unrecorded_gc_sample = 0 ;
617632 uint64_t start_timestamp = 0 ;
@@ -661,20 +676,47 @@ stackprof_record_gc_samples()
661676 _stackprof .unrecorded_gc_sweeping_samples = 0 ;
662677}
663678
679+ // record the sample previously buffered by stackprof_buffer_sample
664680static void
665- stackprof_gc_job_handler (void * data )
681+ stackprof_record_buffer (void )
682+ {
683+ stackprof_record_sample_for_stack (_stackprof .buffer_count , _stackprof .buffer_time .timestamp_usec , _stackprof .buffer_time .delta_usec );
684+
685+ // reset the buffer
686+ _stackprof .buffer_count = 0 ;
687+ }
688+
689+ static void
690+ stackprof_sample_and_record (void )
691+ {
692+ stackprof_buffer_sample ();
693+ stackprof_record_buffer ();
694+ }
695+
696+ static void
697+ stackprof_job_record_gc (void * data )
666698{
667699 if (!_stackprof .running ) return ;
668700
669701 stackprof_record_gc_samples ();
670702}
671703
704+ #ifdef USE_POSTPONED_JOB
705+ static void
706+ stackprof_job_sample_and_record (void * data )
707+ {
708+ if (!_stackprof .running ) return ;
709+
710+ stackprof_sample_and_record ();
711+ }
712+ #endif
713+
672714static void
673- stackprof_job_handler (void * data )
715+ stackprof_job_record_buffer (void * data )
674716{
675717 if (!_stackprof .running ) return ;
676718
677- stackprof_record_sample ();
719+ stackprof_record_buffer ();
678720}
679721
680722static void
@@ -696,12 +738,16 @@ stackprof_signal_handler(int sig, siginfo_t *sinfo, void *ucontext)
696738 _stackprof .unrecorded_gc_sweeping_samples ++ ;
697739 }
698740 _stackprof .unrecorded_gc_samples ++ ;
699- rb_postponed_job_register_one (0 , stackprof_gc_job_handler , (void * )0 );
741+ rb_postponed_job_register_one (0 , stackprof_job_record_gc , (void * )0 );
700742 } else {
701743#ifdef USE_POSTPONED_JOB
702- rb_postponed_job_register_one (0 , stackprof_job_handler , (void * )0 );
744+ rb_postponed_job_register_one (0 , stackprof_job_sample_and_record , (void * )0 );
703745#else
704- stackprof_job_handler (0 );
746+ // Buffer a sample immediately, if an existing sample exists this will
747+ // return immediately
748+ stackprof_buffer_sample ();
749+ // Enqueue a job to record the sample
750+ rb_postponed_job_register_one (0 , stackprof_job_record_buffer , (void * )0 );
705751#endif
706752 }
707753 pthread_mutex_unlock (& lock );
@@ -713,7 +759,7 @@ stackprof_newobj_handler(VALUE tpval, void *data)
713759 _stackprof .overall_signals ++ ;
714760 if (RTEST (_stackprof .interval ) && _stackprof .overall_signals % NUM2LONG (_stackprof .interval ))
715761 return ;
716- stackprof_job_handler ( 0 );
762+ stackprof_sample_and_record ( );
717763}
718764
719765static VALUE
@@ -723,7 +769,7 @@ stackprof_sample(VALUE self)
723769 return Qfalse ;
724770
725771 _stackprof .overall_signals ++ ;
726- stackprof_job_handler ( 0 );
772+ stackprof_sample_and_record ( );
727773 return Qtrue ;
728774}
729775
0 commit comments