@@ -404,12 +404,28 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessTable
404404 }
405405}
406406
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+
407423/*
408424 * Scan threads for process state information.
409425 * Based on: http://stackoverflow.com/questions/6788274/ios-mac-cpu-usage-for-thread
410426 * and https://github.com/max-horvath/htop-osx/blob/e86692e869e30b0bc7264b3675d2a4014866ef46/ProcessList.c
411427 */
412- void DarwinProcess_scanThreads (DarwinProcess * dp ) {
428+ void DarwinProcess_scanThreads (DarwinProcess * dp , DarwinProcessTable * dpt ) {
413429 Process * proc = (Process * ) dp ;
414430 kern_return_t ret ;
415431
@@ -421,55 +437,105 @@ void DarwinProcess_scanThreads(DarwinProcess* dp) {
421437 return ;
422438 }
423439
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 );
426444 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 ));
427448 dp -> taskAccess = false;
428449 return ;
429450 }
430451
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+ }
437462 }
438463
439464 thread_array_t thread_list ;
440465 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 );
442467 if (ret != KERN_SUCCESS ) {
468+ CRT_debug ("task_threads(%d) failed: %s" , pid , mach_error_string (ret ));
443469 dp -> taskAccess = false;
444- mach_port_deallocate (mach_task_self (), port );
470+ mach_port_deallocate (mach_task_self (), task );
445471 return ;
446472 }
447473
474+ const bool hideUserlandThreads = dpt -> super .super .host -> settings -> hideUserlandThreads ;
475+
448476 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 ;
459497 }
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 );
460532 }
533+
461534 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 );
463536
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 );
473539}
474540
475541
0 commit comments