@@ -2,42 +2,54 @@ extern crate libc;
2
2
3
3
use std:: num:: NonZeroUsize ;
4
4
5
- use self :: libc:: { kern_return_t, mach_msg_type_number_t, mach_port_t, thread_t} ;
6
-
7
- // This constant is from
8
- // /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/
9
- // usr/include/mach/machine/thread_state.h.
10
- //
11
- // It has not been updated since Apple devices started to support 64-bit ARM (iOS), so it
12
- // should be very stable.
13
- const THREAD_STATE_MAX : i32 = 1296 ;
14
- #[ allow( non_camel_case_types) ]
15
- // https://github.com/apple/darwin-xnu/blob/a1babec6b135d1f35b2590a1990af3c5c5393479/osfmk/mach/mach_types.defs#L155
16
- type task_inspect_t = mach_port_t ;
5
+ use self :: libc:: {
6
+ kern_return_t, mach_port_t, natural_t, task_threads, thread_act_array_t, vm_size_t,
7
+ } ;
8
+
17
9
#[ allow( non_camel_case_types) ]
18
- // https://github. com/apple/darwin-xnu/blob/a1babec6b135d1f35b2590a1990af3c5c5393479/osfmk/mach/mach_types.defs#L238
19
- type thread_array_t = [ thread_t ; THREAD_STATE_MAX as usize ] ;
10
+ // https://developer.apple. com/documentation/kernel/mach_port_name_t
11
+ type mach_port_name_t = natural_t ;
20
12
21
13
extern "C" {
22
- // https://developer.apple.com/documentation/kernel/1537751-task_threads/
23
- fn task_threads (
24
- target_task : task_inspect_t ,
25
- act_list : * mut thread_array_t ,
26
- act_listCnt : * mut mach_msg_type_number_t ,
14
+ // https://developer.apple.com/documentation/kernel/1402285-mach_vm_deallocate
15
+ fn mach_vm_deallocate (
16
+ target_task : mach_port_t ,
17
+ address : * mut u32 ,
18
+ size : vm_size_t ,
27
19
) -> kern_return_t ;
20
+
21
+ // https://developer.apple.com/documentation/kernel/1578777-mach_port_deallocate
22
+ fn mach_port_deallocate ( task : mach_port_t , name : mach_port_name_t ) -> kern_return_t ;
28
23
}
29
24
30
25
pub ( crate ) fn num_threads ( ) -> Option < NonZeroUsize > {
31
- // http ://web.mit.edu/darwin/src/modules/xnu/osfmk/man/ task_threads.html
32
- let mut thread_state = [ 0u32 ; THREAD_STATE_MAX as usize ] ;
26
+ // https ://developer.apple.com/documentation/kernel/1537751- task_threads
27
+ let mut thread_list : thread_act_array_t = std :: ptr :: null_mut ( ) ;
33
28
let mut thread_count = 0 ;
34
29
35
- // Safety: `mach_task_self` always returns a valid value, `thread_state` is large enough, and
36
- // both it and `thread_count` are writable.
37
- let result =
38
- unsafe { task_threads ( libc:: mach_task_self ( ) , & mut thread_state, & mut thread_count) } ;
30
+ // Safety:
31
+ // - `mach_task_self` always returns a valid value,
32
+ // - `thread_list` is a pointer that will point to kernel allocated memory that needs to be
33
+ // deallocated if the call succeeds
34
+ let task = unsafe { libc:: mach_task_self ( ) } ;
35
+ let result = unsafe { task_threads ( task, & mut thread_list, & mut thread_count) } ;
39
36
40
37
if result == libc:: KERN_SUCCESS {
38
+ // Deallocate the mach port rights for the threads
39
+ for thread in 0 ..thread_count {
40
+ unsafe {
41
+ mach_port_deallocate ( task, * ( thread_list. offset ( thread as isize ) ) as u32 ) ;
42
+ }
43
+ }
44
+ // Deallocate the thread list
45
+ unsafe {
46
+ mach_vm_deallocate (
47
+ task,
48
+ thread_list,
49
+ std:: mem:: size_of :: < mach_port_t > ( ) * thread_count as usize ,
50
+ ) ;
51
+ }
52
+
41
53
NonZeroUsize :: new ( thread_count as usize )
42
54
} else {
43
55
None
0 commit comments