1- use super :: kernel_error:: { self , IntoResult , KernelError } ;
2- use super :: proc_maps:: { DyldInfo , DyldInfoManager , Modification } ;
3- use super :: thread_profiler:: ThreadProfiler ;
1+ use crate :: error:: SamplingError ;
2+ use crate :: kernel_error:: { IntoResult , KernelError } ;
3+ use crate :: proc_maps:: { DyldInfo , DyldInfoManager , Modification } ;
4+ use crate :: thread_profiler:: ThreadProfiler ;
45use gecko_profile:: debugid:: DebugId ;
56use mach:: mach_types:: thread_act_port_array_t;
67use mach:: mach_types:: thread_act_t;
@@ -31,6 +32,7 @@ pub struct TaskProfiler {
3132 libs : Vec < DyldInfo > ,
3233 executable_lib : Option < DyldInfo > ,
3334 command_name : String ,
35+ ignored_errors : Vec < SamplingError > ,
3436}
3537
3638impl TaskProfiler {
@@ -41,17 +43,17 @@ impl TaskProfiler {
4143 now_system : SystemTime ,
4244 command_name : & str ,
4345 interval : Duration ,
44- ) -> kernel_error :: Result < Self > {
45- let thread_acts = get_thread_list ( task) ?;
46+ ) -> Option < Self > {
47+ let thread_acts = get_thread_list ( task) . ok ( ) ?;
4648 let mut live_threads = HashMap :: new ( ) ;
4749 for ( i, thread_act) in thread_acts. into_iter ( ) . enumerate ( ) {
4850 // Pretend that the first thread is the main thread. Might not be true.
4951 let is_main = i == 0 ;
50- if let Some ( thread) = ThreadProfiler :: new ( task, pid, thread_act, now, is_main) ? {
52+ if let Some ( thread) = ThreadProfiler :: new ( task, pid, thread_act, now, is_main) {
5153 live_threads. insert ( thread_act, thread) ;
5254 }
5355 }
54- Ok ( TaskProfiler {
56+ Some ( TaskProfiler {
5557 task,
5658 pid,
5759 interval,
@@ -64,20 +66,34 @@ impl TaskProfiler {
6466 libs : Vec :: new ( ) ,
6567 command_name : command_name. to_owned ( ) ,
6668 executable_lib : None ,
69+ ignored_errors : Vec :: new ( ) ,
6770 } )
6871 }
6972
70- pub fn sample ( & mut self , now : Instant ) -> kernel_error :: Result < bool > {
73+ pub fn sample ( & mut self , now : Instant ) -> Result < bool , SamplingError > {
7174 let result = self . sample_impl ( now) ;
7275 match result {
7376 Ok ( ( ) ) => Ok ( true ) ,
74- Err ( KernelError :: MachSendInvalidDest ) => Ok ( false ) ,
75- Err ( KernelError :: Terminated ) => Ok ( false ) ,
77+ Err ( SamplingError :: ProcessTerminated ( _, _) ) => Ok ( false ) ,
78+ Err ( err @ SamplingError :: Ignorable ( _, _) ) => {
79+ self . ignored_errors . push ( err) ;
80+ if self . ignored_errors . len ( ) >= 10 {
81+ println ! (
82+ "Treating process \" {}\" [pid: {}] as terminated after 10 unknown errors:" ,
83+ self . command_name, self . pid
84+ ) ;
85+ println ! ( "{:#?}" , self . ignored_errors) ;
86+ Ok ( false )
87+ } else {
88+ // Pretend that sampling worked and that the thread is still alive.
89+ Ok ( true )
90+ }
91+ }
7692 Err ( err) => Err ( err) ,
7793 }
7894 }
7995
80- fn sample_impl ( & mut self , now : Instant ) -> kernel_error :: Result < ( ) > {
96+ fn sample_impl ( & mut self , now : Instant ) -> Result < ( ) , SamplingError > {
8197 // First, check for any newly-loaded libraries.
8298 let changes = self
8399 . lib_info_manager
@@ -99,10 +115,7 @@ impl TaskProfiler {
99115 }
100116
101117 // Enumerate threads.
102- let thread_acts = get_thread_list ( self . task ) . map_err ( |err| match err {
103- KernelError :: InvalidArgument => KernelError :: Terminated ,
104- err => err,
105- } ) ?;
118+ let thread_acts = get_thread_list ( self . task ) ?;
106119 let previously_live_threads: HashSet < _ > =
107120 self . live_threads . iter ( ) . map ( |( t, _) | * t) . collect ( ) ;
108121 let mut now_live_threads = HashSet :: new ( ) ;
@@ -111,9 +124,12 @@ impl TaskProfiler {
111124 let thread = match entry {
112125 Entry :: Occupied ( ref mut entry) => entry. get_mut ( ) ,
113126 Entry :: Vacant ( entry) => {
114- match ThreadProfiler :: new ( self . task , self . pid , thread_act, now, false ) ? {
115- Some ( thread) => entry. insert ( thread) ,
116- None => continue ,
127+ if let Some ( thread) =
128+ ThreadProfiler :: new ( self . task , self . pid , thread_act, now, false )
129+ {
130+ entry. insert ( thread)
131+ } else {
132+ continue ;
117133 }
118134 }
119135 } ;
@@ -209,10 +225,19 @@ impl TaskProfiler {
209225 }
210226}
211227
212- fn get_thread_list ( task : mach_port_t ) -> kernel_error :: Result < Vec < thread_act_t > > {
228+ fn get_thread_list ( task : mach_port_t ) -> Result < Vec < thread_act_t > , SamplingError > {
213229 let mut thread_list: thread_act_port_array_t = std:: ptr:: null_mut ( ) ;
214230 let mut thread_count: mach_msg_type_number_t = Default :: default ( ) ;
215- unsafe { task_threads ( task, & mut thread_list, & mut thread_count) } . into_result ( ) ?;
231+ unsafe { task_threads ( task, & mut thread_list, & mut thread_count) }
232+ . into_result ( )
233+ . map_err ( |err| match err {
234+ KernelError :: InvalidArgument
235+ | KernelError :: MachSendInvalidDest
236+ | KernelError :: Terminated => {
237+ SamplingError :: ProcessTerminated ( "task_threads in get_thread_list" , err)
238+ }
239+ err => SamplingError :: Ignorable ( "task_threads in get_thread_list" , err) ,
240+ } ) ?;
216241
217242 let thread_acts =
218243 unsafe { std:: slice:: from_raw_parts ( thread_list, thread_count as usize ) } . to_owned ( ) ;
@@ -224,7 +249,8 @@ fn get_thread_list(task: mach_port_t) -> kernel_error::Result<Vec<thread_act_t>>
224249 ( thread_count as usize * mem:: size_of :: < thread_act_t > ( ) ) as mach_vm_size_t ,
225250 )
226251 }
227- . into_result ( ) ?;
252+ . into_result ( )
253+ . map_err ( |err| SamplingError :: Fatal ( "mach_vm_deallocate in get_thread_list" , err) ) ?;
228254
229255 Ok ( thread_acts)
230256}
0 commit comments