@@ -531,53 +531,84 @@ fn enumerate_task_tids(pid: libc::pid_t) -> Vec<libc::pid_t> {
531531
532532/// Emit thread blocks for all threads other than the crashing thread.
533533///
534- /// Called from the collector child (after fork), so std::fs is safe to use.
534+ /// Called from the collector child (after fork), so std::fs and ptrace are safe to use.
535+ /// Uses a streaming approach to avoid allocating vectors or hashmaps.
535536/// For each thread:
537+ /// - Uses ptrace to capture thread context (registers + stack)
536538/// - Reads name and state from /proc/<ppid>/task/<tid>/
537- /// - If a ucontext was captured (collect_all_threads), emits the stack trace.
538- /// - Otherwise emits an empty (incomplete) stack trace.
539+ /// - Immediately emits the thread block without intermediate storage
539540#[ cfg( target_os = "linux" ) ]
540541fn emit_all_threads (
541542 w : & mut impl Write ,
542543 config : & CrashtrackerConfiguration ,
543544 ppid : libc:: pid_t ,
544545 crashing_tid : libc:: pid_t ,
545546) -> Result < ( ) , EmitterError > {
546- use crate :: collector:: thread_context_buffer:: iter_collected_contexts;
547-
548- // Build a map from TID to captured ucontext pointer (may be empty if buffer
549- // was not initialised or the thread did not respond in time).
550- let contexts: std:: collections:: HashMap < libc:: pid_t , * const ucontext_t > =
551- iter_collected_contexts ( )
552- . map ( |c| ( c. tid , c. ucontext ) )
553- . collect ( ) ;
554-
555- let tids = enumerate_task_tids ( ppid) ;
556- let max = config. max_threads ( ) ;
557- let mut emitted = 0 ;
558-
559- for tid in tids {
560- if tid == crashing_tid {
561- continue ;
562- }
563- if emitted >= max {
564- break ;
565- }
547+ use crate :: collector:: ptrace_collector:: stream_thread_contexts;
548+ use std:: time:: Duration ;
549+
550+ // Calculate timeout for ptrace operations
551+ let context_timeout = Duration :: from_millis ( ( config. timeout ( ) . as_millis ( ) / 2 ) . min ( 200 ) as u64 ) ;
552+
553+ let result = stream_thread_contexts (
554+ ppid,
555+ crashing_tid,
556+ config. max_threads ( ) ,
557+ context_timeout,
558+ |tid, captured_context| {
559+ // Read thread metadata from /proc
560+ let name = read_thread_name ( ppid, tid) . unwrap_or_else ( || tid. to_string ( ) ) ;
561+ let state = read_thread_state ( ppid, tid) ;
562+
563+ // Get ucontext pointer if we captured context for this thread
564+ let ucontext = captured_context. map ( |ctx| & ctx. ucontext as * const _ ) ;
565+
566+ // Immediately emit the thread block
567+ match emit_thread_block (
568+ w,
569+ tid,
570+ false ,
571+ & name,
572+ state. as_deref ( ) ,
573+ config. resolve_frames ( ) ,
574+ ucontext,
575+ ) {
576+ Ok ( ( ) ) => true , // Continue with next thread
577+ Err ( _) => false , // Stop iteration on write error
578+ }
579+ } ,
580+ ) ;
581+
582+ // Handle the case where ptrace setup fails entirely
583+ if result. is_err ( ) {
584+ // Fall back to thread enumeration without context capture
585+ // This provides basic thread information even when ptrace fails
586+ let tids = enumerate_task_tids ( ppid) ;
587+ let max = config. max_threads ( ) ;
588+ let mut emitted = 0 ;
589+
590+ for tid in tids {
591+ if tid == crashing_tid {
592+ continue ;
593+ }
594+ if emitted >= max {
595+ break ;
596+ }
566597
567- let name = read_thread_name ( ppid, tid) . unwrap_or_else ( || tid. to_string ( ) ) ;
568- let state = read_thread_state ( ppid, tid) ;
569- let ucontext = contexts . get ( & tid ) . copied ( ) ;
570-
571- emit_thread_block (
572- w ,
573- tid ,
574- false ,
575- & name ,
576- state . as_deref ( ) ,
577- config . resolve_frames ( ) ,
578- ucontext ,
579- ) ? ;
580- emitted += 1 ;
598+ let name = read_thread_name ( ppid, tid) . unwrap_or_else ( || tid. to_string ( ) ) ;
599+ let state = read_thread_state ( ppid, tid) ;
600+
601+ emit_thread_block (
602+ w ,
603+ tid ,
604+ false ,
605+ & name ,
606+ state . as_deref ( ) ,
607+ config . resolve_frames ( ) ,
608+ None , // No context available
609+ ) ? ;
610+ emitted += 1 ;
611+ }
581612 }
582613
583614 Ok ( ( ) )
0 commit comments