Advertisement
Guest User

lstasks

a guest
Dec 10th, 2013
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 19.65 KB | None | 0 0
  1. // lstasks.c
  2.    
  3. #include <getopt.h>
  4. #include <sys/sysctl.h>
  5. #include <mach/mach.h>
  6. #include <Carbon/Carbon.h>
  7.    
  8. #define PROGNAME  "lstasks"
  9.    
  10. // pretty-printing macros
  11. #define INDENT_L1 "  "
  12. #define INDENT_L2 "    "
  13. #define INDENT_L3 "      "
  14. #define INDENT_L4 "        "
  15. #define SUMMARY_HEADER \
  16.     "task#   BSD pid program         PSN (high)   PSN (low)    #threads\n"
  17.    
  18. static const char *task_roles[] = {
  19.     "RENICED",
  20.     "UNSPECIFIED",
  21.     "FOREGROUND_APPLICATION",
  22.     "BACKGROUND_APPLICATION",
  23.     "CONTROL_APPLICATION",
  24.     "GRAPHICS_SERVER",
  25. };
  26. #define TASK_ROLES_MAX (sizeof(task_roles)/sizeof(char *))
  27.    
  28. static const char *thread_policies[] = {
  29.     "UNKNOWN?",
  30.     "STANDARD|EXTENDED",
  31.     "TIME_CONSTRAINT",
  32.     "PRECEDENCE",
  33. };
  34. #define THREAD_POLICIES_MAX (sizeof(thread_policies)/sizeof(char *))
  35.    
  36. static const char *thread_states[] = {
  37.     "NONE",
  38.     "RUNNING",
  39.     "STOPPED",
  40.     "WAITING",
  41.     "UNINTERRUPTIBLE",
  42.     "HALTED",
  43. };
  44. #define THREAD_STATES_MAX (sizeof(thread_states)/sizeof(char *))
  45.    
  46. #define EXIT_ON_MACH_ERROR(msg, retval) \
  47.     if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); exit((retval)); }
  48.    
  49. // get BSD process name from process ID
  50. static char *
  51. getprocname(pid_t pid)
  52. {
  53.     size_t len = sizeof(struct kinfo_proc);
  54.     static int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
  55.     static struct kinfo_proc kp;
  56.    
  57.     name[3] = pid;
  58.     kp.kp_proc.p_comm[0] = '\0';
  59.    
  60.     if (sysctl((int *)name, sizeof(name)/sizeof(*name), &kp, &len, NULL, 0))
  61.         return "?";
  62.    
  63.     if (kp.kp_proc.p_comm[0] == '\0')
  64.         return "exited?";
  65.    
  66.     return kp.kp_proc.p_comm;
  67. }
  68.    
  69. void
  70. usage()
  71. {
  72.     printf("usage: %s [-s|-v] [-p <pid>]\n", PROGNAME);
  73.     exit(1);
  74. }
  75.    
  76. // used as the printf() while printing only the summary
  77. int
  78. noprintf(const char *format, ...)
  79. {
  80.     return 0; // nothing
  81. }
  82.    
  83. int
  84. main(int argc, char **argv)
  85. {
  86.     int i, j, summary = 0, verbose = 0;
  87.     int (* Printf)(const char *format, ...);
  88.    
  89.     pid_t pid;
  90.    
  91.     // for Carbon processes
  92.     OSStatus            status;
  93.     ProcessSerialNumber psn;
  94.     CFStringRef         nameRef;
  95.     char                name[MAXPATHLEN];
  96.    
  97.     kern_return_t kr;
  98.     mach_port_t   myhost;                // host port
  99.     mach_port_t   mytask;                // our task
  100.     mach_port_t   onetask = 0;           // we want only one specific task
  101.     mach_port_t   p_default_set;         // processor set name port
  102.     mach_port_t   p_default_set_control; // processor set control port
  103.    
  104.     //// for task-related querying
  105.    
  106.     // pointer to ool buffer for processor_set_tasks(), and the size of
  107.     // the data actually returned in the ool buffer
  108.     task_array_t           task_list;
  109.     mach_msg_type_number_t task_count;
  110.    
  111.     // maximum-sized buffer for task_info(), and the size of the data
  112.     // actually filled in by task_info()
  113.     task_info_data_t       tinfo;
  114.     mach_msg_type_number_t task_info_count;
  115.    
  116.     // flavor-specific pointers to cast the generic tinfo buffer
  117.     task_basic_info_t        basic_info;
  118.     task_events_info_t       events_info;
  119.     task_thread_times_info_t thread_times_info;
  120.     task_absolutetime_info_t absolutetime_info;
  121.    
  122.     // used for calling task_get_policy()
  123.     task_category_policy_data_t category_policy;
  124.     boolean_t get_default;
  125.    
  126.     // opaque token that identifies the task as a BSM audit subject
  127.     audit_token_t    audit_token;
  128.     security_token_t security_token; // kernel's security token is { 0, 1 }
  129.    
  130.     //// for thread-related querying
  131.    
  132.     // pointer to ool buffer for task_threads(), and the size of the data
  133.     // actually returned in the ool buffer
  134.     thread_array_t         thread_list;
  135.     mach_msg_type_number_t thread_count;
  136.    
  137.     // maximum-sized buffer for thread_info(), and the size of the data
  138.     // actually filled in by thread_info()
  139.     thread_info_data_t     thinfo;
  140.     mach_msg_type_number_t thread_info_count;
  141.    
  142.     // flavor-specific pointers to cast the generic thinfo buffer
  143.     thread_basic_info_t basic_info_th;
  144.    
  145.     // used for calling thread_get_policy()
  146.     thread_extended_policy_data_t        extended_policy;
  147.     thread_time_constraint_policy_data_t time_constraint_policy;
  148.     thread_precedence_policy_data_t      precedence_policy;
  149.    
  150.     // to count individual types of process subsystem entities
  151.     uint32_t stat_task = 0;   // Mach tasks
  152.     uint32_t stat_proc = 0;   // BSD processes
  153.     uint32_t stat_cpm = 0;    // Carbon Process Manager processes
  154.     uint32_t stat_thread = 0; // Mach threads
  155.    
  156.     // assume we won't be silent: use the verbose version of printf() by default
  157.     Printf = printf;
  158.    
  159.     myhost = mach_host_self();
  160.     mytask = mach_task_self();
  161.    
  162.     while ((i = getopt(argc, argv, "p:sv")) != -1) {
  163.         switch (i) {
  164.             case 'p':
  165.                 pid = strtoul(optarg, NULL, 10);
  166.                 kr = task_for_pid(mytask, pid, &onetask);
  167.                 EXIT_ON_MACH_ERROR("task_for_pid", 1);
  168.                 break;
  169.             case 's':
  170.                 summary = 1;
  171.                 Printf = noprintf;
  172.                 break;
  173.             case 'v':
  174.                 verbose = 1;
  175.                 break;
  176.             default:
  177.                 usage();
  178.         }
  179.     }
  180.    
  181.     // can't have both
  182.     if (summary && verbose)
  183.         usage();
  184.    
  185.     argv += optind;
  186.     argc -= optind;
  187.    
  188.     kr = processor_set_default(myhost, &p_default_set);
  189.     EXIT_ON_MACH_ERROR("processor_default", 1);
  190.    
  191.     // get the privileged port so that we can get all tasks
  192.     kr = host_processor_set_priv(myhost, p_default_set, &p_default_set_control);
  193.     EXIT_ON_MACH_ERROR("host_processor_set_priv", 1);
  194.    
  195.     // we could check for multiple processor sets, but we know there aren't...
  196.     kr = processor_set_tasks(p_default_set_control, &task_list, &task_count);
  197.     EXIT_ON_MACH_ERROR("processor_set_tasks", 1);
  198.    
  199.     if (!verbose)
  200.         Printf(SUMMARY_HEADER);
  201.    
  202.     // check out each task
  203.     for (i = 0; i < task_count; i++) {
  204.    
  205.         // ignore our own task
  206.         if (task_list[i] == mytask)
  207.             continue;
  208.    
  209.         if (onetask && (task_list[i] != onetask))
  210.             continue;
  211.    
  212.         pid = 0;
  213.         status = procNotFound;
  214.    
  215.         // note that we didn't count this task
  216.         stat_task++;
  217.    
  218.         if (verbose)
  219.             Printf("Task #%d\n", i);
  220.         else
  221.             Printf("%5d", i);
  222.    
  223.         // check for BSD process (process 0 not counted as a BSD process)
  224.         kr = pid_for_task(task_list[i], &pid);
  225.         if ((kr == KERN_SUCCESS) && (pid > 0)) {
  226.             stat_proc++;
  227.    
  228.             if (verbose)
  229.                 Printf(INDENT_L1 "BSD process id (pid)   = %u (%s)\n", pid,
  230.                        getprocname(pid));
  231.             else
  232.                 Printf("    %6u %-16s", pid, getprocname(pid));
  233.          } else // no BSD process
  234.             if (verbose)
  235.                 Printf(INDENT_L1 "BSD process id (pid)   = "
  236.                        "/* not a BSD process */\n");
  237.             else
  238.                 Printf("    %6s %-16s", "-", "-");
  239.    
  240.         // check whether there is a process serial number
  241.         if (pid > 0)
  242.             status = GetProcessForPID(pid, &psn);
  243.         if (status == noErr) {
  244.             stat_cpm++;
  245.             if (verbose) {
  246.                 status = CopyProcessName(&psn, &nameRef);
  247.                 CFStringGetCString(nameRef, name, MAXPATHLEN,
  248.                                    kCFStringEncodingASCII);
  249.                 Printf(INDENT_L1 "Carbon process name    = %s\n", name);
  250.                 CFRelease(nameRef);
  251.             } else
  252.                 Printf(" %-12d%-12d", psn.highLongOfPSN, psn.lowLongOfPSN);
  253.         } else // no PSN
  254.             if (verbose)
  255.                 Printf(INDENT_L1 "Carbon process name    = "
  256.                        "/* not a Carbon process */\n");
  257.             else
  258.                 Printf(" %-12s%-12s", "-", "-");
  259.    
  260.         if (!verbose)
  261.             goto do_threads;
  262.    
  263.         // basic task information
  264.         task_info_count = TASK_INFO_MAX;
  265.         kr = task_info(task_list[i], TASK_BASIC_INFO, (task_info_t)tinfo,
  266.                        &task_info_count);
  267.         if (kr != KERN_SUCCESS) {
  268.             mach_error("task_info:", kr);
  269.             fprintf(stderr, "*** TASK_BASIC_INFO failed (task=%x)\n",
  270.                     task_list[i]);
  271.             // skip this task
  272.             continue;
  273.         }
  274.         basic_info = (task_basic_info_t)tinfo;
  275.         Printf(INDENT_L2 "virtual size         = %u KB\n",
  276.                basic_info->virtual_size >> 10);
  277.         Printf(INDENT_L2 "resident size        = %u KB\n",
  278.                basic_info->resident_size >> 10);
  279.         if ((basic_info->policy < 0) &&
  280.             (basic_info->policy > THREAD_POLICIES_MAX))
  281.             basic_info->policy = 0;
  282.         Printf(INDENT_L2 "default policy       = %u (%s)\n",
  283.                basic_info->policy, thread_policies[basic_info->policy]);
  284.    
  285.         Printf(INDENT_L1 "Thread run times\n");
  286.    
  287.         Printf(INDENT_L2 "user (terminated)    = %u s %u us\n",
  288.                basic_info->user_time.seconds,
  289.                basic_info->user_time.microseconds);
  290.         Printf(INDENT_L2 "system (terminated)  = %u s %u us\n",
  291.                basic_info->system_time.seconds,
  292.                basic_info->system_time.microseconds);
  293.    
  294.         // times for live threads (unreliable -- we are not suspending)
  295.         task_info_count = TASK_INFO_MAX;
  296.         kr = task_info(task_list[i], TASK_THREAD_TIMES_INFO,
  297.                        (task_info_t)tinfo, &task_info_count);
  298.         if (kr == KERN_SUCCESS) {
  299.             thread_times_info = (task_thread_times_info_t)tinfo;
  300.             Printf(INDENT_L2 "user (live)          = %u s %u us\n",
  301.                    thread_times_info->user_time.seconds,
  302.                    thread_times_info->user_time.microseconds);
  303.             Printf(INDENT_L2 "system (live)        = %u s %u us\n",
  304.                    thread_times_info->system_time.seconds,
  305.                    thread_times_info->system_time.microseconds);
  306.         }
  307.    
  308.         // absolute times for live threads, and overall absolute time
  309.         task_info_count = TASK_INFO_MAX;
  310.         kr = task_info(task_list[i], TASK_ABSOLUTETIME_INFO,
  311.                        (task_info_t)tinfo, &task_info_count);
  312.         if (kr == KERN_SUCCESS) {
  313.             Printf(INDENT_L1 "Thread times (absolute)\n");
  314.             absolutetime_info = (task_absolutetime_info_t)tinfo;
  315.             Printf(INDENT_L2 "user (total)         = %lld\n",
  316.                    absolutetime_info->total_user);
  317.             Printf(INDENT_L2 "system (total)       = %lld\n",
  318.                    absolutetime_info->total_system);
  319.             Printf(INDENT_L2 "user (live)          = %lld\n",
  320.                    absolutetime_info->threads_user);
  321.             Printf(INDENT_L2 "system (live)        = %lld\n",
  322.                    absolutetime_info->threads_system);
  323.         }
  324.    
  325.         // events
  326.         task_info_count = TASK_INFO_MAX;
  327.         kr = task_info(task_list[i], TASK_EVENTS_INFO, (task_info_t)tinfo,
  328.                        &task_info_count);
  329.         if (kr == KERN_SUCCESS) {
  330.             events_info = (task_events_info_t)tinfo;
  331.             Printf(INDENT_L2 "page faults          = %u\n",
  332.                     events_info->faults);
  333.             Printf(INDENT_L2 "actual pageins       = %u\n",
  334.                    events_info->pageins);
  335.             Printf(INDENT_L2 "copy-on-write faults = %u\n",
  336.                    events_info->cow_faults);
  337.             Printf(INDENT_L2 "messages sent        = %u\n",
  338.                    events_info->messages_sent);
  339.             Printf(INDENT_L2 "messages received    = %u\n",
  340.                    events_info->messages_received);
  341.             Printf(INDENT_L2 "Mach system calls    = %u\n",
  342.                    events_info->syscalls_mach);
  343.             Printf(INDENT_L2 "Unix system calls    = %u\n",
  344.                    events_info->syscalls_unix);
  345.             Printf(INDENT_L2 "context switches     = %u\n",
  346.                    events_info->csw);
  347.         }
  348.    
  349.         // task policy information
  350.         task_info_count = TASK_CATEGORY_POLICY_COUNT;
  351.         get_default = FALSE;
  352.         kr = task_policy_get(task_list[i], TASK_CATEGORY_POLICY,
  353.                              (task_policy_t)&category_policy,
  354.                              &task_info_count, &get_default);
  355.         if (kr == KERN_SUCCESS) {
  356.             if (get_default == FALSE) {
  357.                 if ((category_policy.role >= -1) &&
  358.                     (category_policy.role < (TASK_ROLES_MAX - 1)))
  359.                     Printf(INDENT_L2 "role                 = %s\n",
  360.                            task_roles[category_policy.role + 1]);
  361.             } else // no current settings -- other parameters take precedence
  362.                 Printf(INDENT_L2 "role                 = NONE\n");
  363.         }
  364.    
  365.         // audit token
  366.         task_info_count = TASK_AUDIT_TOKEN_COUNT;
  367.         kr = task_info(task_list[i], TASK_AUDIT_TOKEN,
  368.                        (task_info_t)&audit_token, &task_info_count);
  369.         if (kr == KERN_SUCCESS) {
  370.             int n;
  371.             Printf(INDENT_L2 "audit token          = ");
  372.             for (n = 0; n < sizeof(audit_token)/sizeof(uint32_t); n++)
  373.                 Printf("%x ", audit_token.val[n]);
  374.             Printf("\n");
  375.         }
  376.    
  377.         // security token
  378.         task_info_count = TASK_SECURITY_TOKEN_COUNT;
  379.         kr = task_info(task_list[i], TASK_SECURITY_TOKEN,
  380.                        (task_info_t)&security_token, &task_info_count);
  381.         if (kr == KERN_SUCCESS) {
  382.             int n;
  383.             Printf(INDENT_L2 "security token       = ");
  384.             for (n = 0; n < sizeof(security_token)/sizeof(uint32_t); n++)
  385.                 Printf("%x ", security_token.val[n]);
  386.             Printf("\n");
  387.         }
  388.    
  389. do_threads:
  390.    
  391.         // get threads in the task
  392.         kr = task_threads(task_list[i], &thread_list, &thread_count);
  393.         if (kr != KERN_SUCCESS) {
  394.             mach_error("task_threads:", kr);
  395.             fprintf(stderr, "task_threads() failed (task=%x)\n", task_list[i]);
  396.             continue;
  397.         }
  398.    
  399.         if (thread_count > 0)
  400.             stat_thread += thread_count;
  401.    
  402.         if (!verbose) {
  403.             Printf(" %8d\n", thread_count);
  404.             continue;
  405.         }
  406.    
  407.         Printf(INDENT_L1 "Threads in this task   = %u\n", thread_count);
  408.    
  409.         // check out threads
  410.         for (j = 0; j < thread_count; j++) {
  411.    
  412.             thread_info_count = THREAD_INFO_MAX;
  413.             kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
  414.                              (thread_info_t)thinfo, &thread_info_count);
  415.             if (kr != KERN_SUCCESS) {
  416.                 mach_error("task_info:", kr);
  417.                 fprintf(stderr,
  418.                         "*** thread_info() failed (task=%x thread=%x)\n",
  419.                         task_list[i], thread_list[j]);
  420.                 continue;
  421.             }
  422.    
  423.             basic_info_th = (thread_basic_info_t)thinfo;
  424.             Printf(INDENT_L2 "thread %u/%u (%p) in task %u (%p)\n",
  425.                    j, thread_count - 1, thread_list[j], i, task_list[i]);
  426.    
  427.             Printf(INDENT_L3 "user run time                = %u s %u us\n",
  428.                    basic_info_th->user_time.seconds,
  429.                    basic_info_th->user_time.microseconds);
  430.             Printf(INDENT_L3 "system run time              = %u s %u us\n",
  431.                    basic_info_th->system_time.seconds,
  432.                    basic_info_th->system_time.microseconds);
  433.             Printf(INDENT_L3 "scaled cpu usage percentage  = %u\n",
  434.                    basic_info_th->cpu_usage);
  435.    
  436.             switch (basic_info_th->policy) {
  437.    
  438.             case THREAD_EXTENDED_POLICY:
  439.                 get_default = FALSE;
  440.                 thread_info_count = THREAD_EXTENDED_POLICY_COUNT;
  441.                 kr = thread_policy_get(thread_list[j], THREAD_EXTENDED_POLICY,
  442.                                        (thread_policy_t)&extended_policy,
  443.                                        &thread_info_count, &get_default);
  444.                 if (kr != KERN_SUCCESS)
  445.                     break;
  446.                 Printf(INDENT_L3 "scheduling policy            = %s\n",
  447.                        (extended_policy.timeshare == TRUE) ? \
  448.                            "STANDARD" : "EXTENDED");
  449.                 break;
  450.    
  451.             case THREAD_TIME_CONSTRAINT_POLICY:
  452.                 get_default = FALSE;
  453.                 thread_info_count = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
  454.                 kr = thread_policy_get(thread_list[j],
  455.                                        THREAD_TIME_CONSTRAINT_POLICY,
  456.                                        (thread_policy_t)&time_constraint_policy,
  457.                                        &thread_info_count, &get_default);
  458.                 if (kr != KERN_SUCCESS)
  459.                     break;
  460.                 Printf(INDENT_L3 "scheduling policy            = " \
  461.                        "TIME_CONSTRAINT\n");
  462.                 Printf(INDENT_L4   "period                     = %-4u\n",
  463.                        time_constraint_policy.period);
  464.                 Printf(INDENT_L4   "computation                = %-4u\n",
  465.                        time_constraint_policy.computation);
  466.                 Printf(INDENT_L4   "constraint                 = %-4u\n",
  467.                        time_constraint_policy.constraint);
  468.                 Printf(INDENT_L4   "preemptible                = %s\n",
  469.                        (time_constraint_policy.preemptible == TRUE) ? \
  470.                            "TRUE" : "FALSE");
  471.                 break;
  472.    
  473.             case THREAD_PRECEDENCE_POLICY:
  474.                 get_default = FALSE;
  475.                 thread_info_count = THREAD_PRECEDENCE_POLICY;
  476.                 kr = thread_policy_get(thread_list[j], THREAD_PRECEDENCE_POLICY,
  477.                                        (thread_policy_t)&precedence_policy,
  478.                                        &thread_info_count, &get_default);
  479.                 if (kr != KERN_SUCCESS)
  480.                     break;
  481.                 Printf(INDENT_L3 "scheduling policy            = PRECEDENCE\n");
  482.                 Printf(INDENT_L4 "importance                 = %-4u\n",
  483.                        precedence_policy.importance);
  484.                 break;
  485.    
  486.             default:
  487.                 Printf(INDENT_L3 "scheduling policy            = UNKNOWN?\n");
  488.                 break;
  489.             }
  490.    
  491.             Printf(INDENT_L3
  492.                    "run state                    = %-4u (%s)\n",
  493.                    basic_info_th->run_state,
  494.                    (basic_info_th->run_state >= THREAD_STATES_MAX) ? \
  495.                        "?" : thread_states[basic_info_th->run_state]);
  496.    
  497.             Printf(INDENT_L3
  498.                    "flags                        = %-4x%s",
  499.                    basic_info_th->flags,
  500.                    (basic_info_th->flags & TH_FLAGS_IDLE) ? \
  501.                        " (IDLE)\n" : "\n");
  502.    
  503.             Printf(INDENT_L3 "suspend count                = %u\n",
  504.                    basic_info_th->suspend_count);
  505.             Printf(INDENT_L3 "sleeping for time            = %u s\n",
  506.                    basic_info_th->sleep_time);
  507.    
  508.         } // for each thread
  509.    
  510.         vm_deallocate(mytask, (vm_address_t)thread_list,
  511.                       thread_count * sizeof(thread_act_t));
  512.    
  513.     } // for each task
  514.    
  515.     Printf("\n");
  516.    
  517.     fprintf(stdout, "%4d Mach tasks\n%4d Mach threads\n"
  518.             "%4d BSD processes\n%4d CPM processes\n",
  519.             stat_task, stat_thread, stat_proc, stat_cpm);
  520.    
  521.     vm_deallocate(mytask, (vm_address_t)task_list, task_count * sizeof(task_t));
  522.    
  523.     exit(0);
  524. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement