@@ -404,12 +404,28 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessTable
404
404
}
405
405
}
406
406
407
+ static ProcessState stateToChar (int run_state ) {
408
+ switch (run_state ) {
409
+ case TH_STATE_RUNNING :
410
+ return RUNNING ;
411
+ case TH_STATE_STOPPED :
412
+ return STOPPED ;
413
+ case TH_STATE_WAITING :
414
+ return WAITING ;
415
+ case TH_STATE_UNINTERRUPTIBLE :
416
+ return UNINTERRUPTIBLE_WAIT ;
417
+ case TH_STATE_HALTED :
418
+ return BLOCKED ;
419
+ }
420
+ return UNKNOWN ;
421
+ }
422
+
407
423
/*
408
424
* Scan threads for process state information.
409
425
* Based on: http://stackoverflow.com/questions/6788274/ios-mac-cpu-usage-for-thread
410
426
* and https://github.com/max-horvath/htop-osx/blob/e86692e869e30b0bc7264b3675d2a4014866ef46/ProcessList.c
411
427
*/
412
- void DarwinProcess_scanThreads (DarwinProcess * dp ) {
428
+ void DarwinProcess_scanThreads (DarwinProcess * dp , DarwinProcessTable * dpt ) {
413
429
Process * proc = (Process * ) dp ;
414
430
kern_return_t ret ;
415
431
@@ -421,55 +437,105 @@ void DarwinProcess_scanThreads(DarwinProcess* dp) {
421
437
return ;
422
438
}
423
439
424
- task_t port ;
425
- ret = task_for_pid (mach_task_self (), Process_getPid (proc ), & port );
440
+ pid_t pid = Process_getPid (proc );
441
+
442
+ task_t task ;
443
+ ret = task_for_pid (mach_task_self (), pid , & task );
426
444
if (ret != KERN_SUCCESS ) {
445
+ // TODO: workaround for modern MacOS limits on task_for_pid()
446
+ if (ret != KERN_FAILURE )
447
+ CRT_debug ("task_for_pid(%d) failed: %s" , pid , mach_error_string (ret ));
427
448
dp -> taskAccess = false;
428
449
return ;
429
450
}
430
451
431
- task_info_data_t tinfo ;
432
- mach_msg_type_number_t task_info_count = TASK_INFO_MAX ;
433
- ret = task_info (port , TASK_BASIC_INFO , (task_info_t ) tinfo , & task_info_count );
434
- if (ret != KERN_SUCCESS ) {
435
- dp -> taskAccess = false;
436
- return ;
452
+ {
453
+ task_info_data_t tinfo ;
454
+ mach_msg_type_number_t task_info_count = TASK_INFO_MAX ;
455
+ ret = task_info (task , TASK_BASIC_INFO , (task_info_t ) & tinfo , & task_info_count );
456
+ if (ret != KERN_SUCCESS ) {
457
+ CRT_debug ("task_info(%d) failed: %s" , pid , mach_error_string (ret ));
458
+ dp -> taskAccess = false;
459
+ mach_port_deallocate (mach_task_self (), task );
460
+ return ;
461
+ }
437
462
}
438
463
439
464
thread_array_t thread_list ;
440
465
mach_msg_type_number_t thread_count ;
441
- ret = task_threads (port , & thread_list , & thread_count );
466
+ ret = task_threads (task , & thread_list , & thread_count );
442
467
if (ret != KERN_SUCCESS ) {
468
+ CRT_debug ("task_threads(%d) failed: %s" , pid , mach_error_string (ret ));
443
469
dp -> taskAccess = false;
444
- mach_port_deallocate (mach_task_self (), port );
470
+ mach_port_deallocate (mach_task_self (), task );
445
471
return ;
446
472
}
447
473
474
+ const bool hideUserlandThreads = dpt -> super .super .host -> settings -> hideUserlandThreads ;
475
+
448
476
integer_t run_state = 999 ;
449
- for (unsigned int i = 0 ; i < thread_count ; i ++ ) {
450
- thread_info_data_t thinfo ;
451
- mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT ;
452
- ret = thread_info (thread_list [i ], THREAD_BASIC_INFO , (thread_info_t )thinfo , & thread_info_count );
453
- if (ret == KERN_SUCCESS ) {
454
- thread_basic_info_t basic_info_th = (thread_basic_info_t ) thinfo ;
455
- if (basic_info_th -> run_state < run_state ) {
456
- run_state = basic_info_th -> run_state ;
457
- }
458
- mach_port_deallocate (mach_task_self (), thread_list [i ]);
477
+ for (mach_msg_type_number_t i = 0 ; i < thread_count ; i ++ ) {
478
+
479
+ thread_identifier_info_data_t identifer_info ;
480
+ mach_msg_type_number_t identifer_info_count = THREAD_IDENTIFIER_INFO_COUNT ;
481
+ ret = thread_info (thread_list [i ], THREAD_IDENTIFIER_INFO , (thread_info_t ) & identifer_info , & identifer_info_count );
482
+ if (ret != KERN_SUCCESS ) {
483
+ CRT_debug ("thread_info(%d:%d) for identifier failed: %s" , pid , i , mach_error_string (ret ));
484
+ continue ;
485
+ }
486
+
487
+ uint64_t tid = identifer_info .thread_id ;
488
+
489
+ bool preExisting ;
490
+ Process * tprocess = ProcessTable_getProcess (& dpt -> super , tid , & preExisting , DarwinProcess_new );
491
+ tprocess -> super .updated = true;
492
+ dpt -> super .totalTasks ++ ;
493
+
494
+ if (hideUserlandThreads ) {
495
+ tprocess -> super .show = false;
496
+ continue ;
459
497
}
498
+
499
+ assert (Process_getPid (tprocess ) == tid );
500
+ Process_setParent (tprocess , pid );
501
+ Process_setThreadGroup (tprocess , pid );
502
+ tprocess -> super .show = true;
503
+ tprocess -> isUserlandThread = true;
504
+ tprocess -> st_uid = proc -> st_uid ;
505
+ tprocess -> user = proc -> user ;
506
+
507
+ thread_extended_info_data_t extended_info ;
508
+ mach_msg_type_number_t extended_info_count = THREAD_EXTENDED_INFO_COUNT ;
509
+ ret = thread_info (thread_list [i ], THREAD_EXTENDED_INFO , (thread_info_t ) & extended_info , & extended_info_count );
510
+ if (ret != KERN_SUCCESS ) {
511
+ CRT_debug ("thread_info(%d:%d) for extended failed: %s" , pid , i , mach_error_string (ret ));
512
+ continue ;
513
+ }
514
+
515
+ DarwinProcess * tdproc = (DarwinProcess * )tprocess ;
516
+ tdproc -> super .state = stateToChar (extended_info .pth_run_state );
517
+ tdproc -> super .percent_cpu = extended_info .pth_cpu_usage / 10.0 ;
518
+ tdproc -> stime = extended_info .pth_system_time ;
519
+ tdproc -> utime = extended_info .pth_user_time ;
520
+ tdproc -> super .time = (extended_info .pth_system_time + extended_info .pth_user_time ) / 10000000 ;
521
+ tdproc -> super .priority = extended_info .pth_curpri ;
522
+
523
+ if (extended_info .pth_run_state < run_state )
524
+ run_state = extended_info .pth_run_state ;
525
+
526
+ // TODO: depend on setting
527
+ const char * name = extended_info .pth_name [0 ] != '\0' ? extended_info .pth_name : proc -> procComm ;
528
+ Process_updateCmdline (tprocess , name , 0 , strlen (name ));
529
+
530
+ if (!preExisting )
531
+ ProcessTable_add (& dpt -> super , tprocess );
460
532
}
533
+
461
534
vm_deallocate (mach_task_self (), (vm_address_t ) thread_list , sizeof (thread_port_array_t ) * thread_count );
462
- mach_port_deallocate (mach_task_self (), port );
535
+ mach_port_deallocate (mach_task_self (), task );
463
536
464
- /* Taken from: https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/osfmk/mach/thread_info.h#L129 */
465
- switch (run_state ) {
466
- case TH_STATE_RUNNING : proc -> state = RUNNING ; break ;
467
- case TH_STATE_STOPPED : proc -> state = STOPPED ; break ;
468
- case TH_STATE_WAITING : proc -> state = WAITING ; break ;
469
- case TH_STATE_UNINTERRUPTIBLE : proc -> state = UNINTERRUPTIBLE_WAIT ; break ;
470
- case TH_STATE_HALTED : proc -> state = BLOCKED ; break ;
471
- default : proc -> state = UNKNOWN ;
472
- }
537
+ if (run_state != 999 )
538
+ proc -> state = stateToChar (run_state );
473
539
}
474
540
475
541
0 commit comments