SolarisProcessTable.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. htop - SolarisProcessTable.c
  3. (C) 2014 Hisham H. Muhammad
  4. (C) 2017,2018 Guy M. Broome
  5. Released under the GNU GPLv2+, see the COPYING file
  6. in the source distribution for its full text.
  7. */
  8. #include "config.h" // IWYU pragma: keep
  9. #include "solaris/SolarisProcessTable.h"
  10. #include <unistd.h>
  11. #include <stdlib.h>
  12. #include <sys/types.h>
  13. #include <sys/user.h>
  14. #include <limits.h>
  15. #include <string.h>
  16. #include <procfs.h>
  17. #include <errno.h>
  18. #include <pwd.h>
  19. #include <math.h>
  20. #include <time.h>
  21. #include "CRT.h"
  22. #include "solaris/Platform.h"
  23. #include "solaris/SolarisMachine.h"
  24. #include "solaris/SolarisProcess.h"
  25. #define GZONE "global "
  26. #define UZONE "unknown "
  27. static char* SolarisProcessTable_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) {
  28. char* zname;
  29. if ( sproc->zoneid == 0 ) {
  30. zname = xStrdup(GZONE);
  31. } else if ( kd == NULL ) {
  32. zname = xStrdup(UZONE);
  33. } else {
  34. kstat_t* ks = kstat_lookup_wrapper( kd, "zones", sproc->zoneid, NULL );
  35. zname = xStrdup(ks == NULL ? UZONE : ks->ks_name);
  36. }
  37. return zname;
  38. }
  39. ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
  40. SolarisProcessTable* this = xCalloc(1, sizeof(SolarisProcessTable));
  41. Object_setClass(this, Class(ProcessTable));
  42. ProcessTable* super = &this->super;
  43. ProcessTable_init(super, Class(SolarisProcess), host, pidMatchList);
  44. return super;
  45. }
  46. void ProcessTable_delete(Object* cast) {
  47. SolarisProcessTable* this = (SolarisProcessTable*) cast;
  48. ProcessTable_done(&this->super);
  49. free(this);
  50. }
  51. static void SolarisProcessTable_updateExe(pid_t pid, Process* proc) {
  52. char path[32];
  53. xSnprintf(path, sizeof(path), "/proc/%d/path/a.out", pid);
  54. char target[PATH_MAX];
  55. ssize_t ret = readlink(path, target, sizeof(target) - 1);
  56. if (ret <= 0)
  57. return;
  58. target[ret] = '\0';
  59. Process_updateExe(proc, target);
  60. }
  61. static void SolarisProcessTable_updateCwd(pid_t pid, Process* proc) {
  62. char path[32];
  63. xSnprintf(path, sizeof(path), "/proc/%d/cwd", pid);
  64. char target[PATH_MAX];
  65. ssize_t ret = readlink(path, target, sizeof(target) - 1);
  66. if (ret <= 0)
  67. return;
  68. target[ret] = '\0';
  69. free_and_xStrdup(&proc->procCwd, target);
  70. }
  71. /* Taken from: https://docs.oracle.com/cd/E19253-01/817-6223/6mlkidlom/index.html#tbl-sched-state */
  72. static inline ProcessState SolarisProcessTable_getProcessState(char state) {
  73. switch (state) {
  74. case 'S': return SLEEPING;
  75. case 'R': return RUNNABLE;
  76. case 'O': return RUNNING;
  77. case 'Z': return ZOMBIE;
  78. case 'T': return STOPPED;
  79. case 'I': return IDLE;
  80. default: return UNKNOWN;
  81. }
  82. }
  83. /* NOTE: the following is a callback function of type proc_walk_f
  84. * and MUST conform to the appropriate definition in order
  85. * to work. See libproc(3LIB) on a Solaris or Illumos
  86. * system for more info.
  87. */
  88. static int SolarisProcessTable_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* listptr) {
  89. bool preExisting;
  90. pid_t getpid;
  91. // Setup process list
  92. ProcessTable* pt = (ProcessTable*) listptr;
  93. const Machine* host = pt->super.host;
  94. const SolarisMachine* shost = (const SolarisMachine*) host;
  95. id_t lwpid_real = _lwpsinfo->pr_lwpid;
  96. if (lwpid_real > 1023) {
  97. return 0;
  98. }
  99. pid_t lwpid = (_psinfo->pr_pid * 1024) + lwpid_real;
  100. bool onMasterLWP = (_lwpsinfo->pr_lwpid == _psinfo->pr_lwp.pr_lwpid);
  101. if (onMasterLWP) {
  102. getpid = _psinfo->pr_pid * 1024;
  103. } else {
  104. getpid = lwpid;
  105. }
  106. Process* proc = ProcessTable_getProcess(pt, getpid, &preExisting, SolarisProcess_new);
  107. SolarisProcess* sproc = (SolarisProcess*) proc;
  108. const Settings* settings = host->settings;
  109. // Common code pass 1
  110. proc->super.show = false;
  111. sproc->taskid = _psinfo->pr_taskid;
  112. sproc->projid = _psinfo->pr_projid;
  113. sproc->poolid = _psinfo->pr_poolid;
  114. sproc->contid = _psinfo->pr_contract;
  115. proc->priority = _lwpsinfo->pr_pri;
  116. proc->nice = _lwpsinfo->pr_nice - NZERO;
  117. proc->processor = _lwpsinfo->pr_onpro;
  118. proc->state = SolarisProcessTable_getProcessState(_lwpsinfo->pr_sname);
  119. // NOTE: This 'percentage' is a 16-bit BINARY FRACTIONS where 1.0 = 0x8000
  120. // Source: https://docs.oracle.com/cd/E19253-01/816-5174/proc-4/index.html
  121. // (accessed on 18 November 2017)
  122. proc->percent_mem = ((uint16_t)_psinfo->pr_pctmem / (double)32768) * (double)100.0;
  123. proc->pgrp = _psinfo->pr_pgid;
  124. proc->nlwp = _psinfo->pr_nlwp;
  125. proc->session = _psinfo->pr_sid;
  126. proc->tty_nr = _psinfo->pr_ttydev;
  127. const char* name = (_psinfo->pr_ttydev != PRNODEV) ? ttyname(_psinfo->pr_ttydev) : NULL;
  128. if (!name) {
  129. free(proc->tty_name);
  130. proc->tty_name = NULL;
  131. } else {
  132. free_and_xStrdup(&proc->tty_name, name);
  133. }
  134. proc->m_resident = _psinfo->pr_rssize; // KB
  135. proc->m_virt = _psinfo->pr_size; // KB
  136. if (proc->st_uid != _psinfo->pr_euid) {
  137. proc->st_uid = _psinfo->pr_euid;
  138. proc->user = UsersTable_getRef(host->usersTable, proc->st_uid);
  139. }
  140. if (!preExisting) {
  141. sproc->realpid = _psinfo->pr_pid;
  142. sproc->lwpid = lwpid_real;
  143. sproc->zoneid = _psinfo->pr_zoneid;
  144. sproc->zname = SolarisProcessTable_readZoneName(shost->kd, sproc);
  145. SolarisProcessTable_updateExe(_psinfo->pr_pid, proc);
  146. Process_updateComm(proc, _psinfo->pr_fname);
  147. Process_updateCmdline(proc, _psinfo->pr_psargs, 0, 0);
  148. if (settings->ss->flags & PROCESS_FLAG_CWD) {
  149. SolarisProcessTable_updateCwd(_psinfo->pr_pid, proc);
  150. }
  151. }
  152. // End common code pass 1
  153. if (onMasterLWP) { // Are we on the representative LWP?
  154. Process_setParent(proc, (_psinfo->pr_ppid * 1024));
  155. Process_setThreadGroup(proc, (_psinfo->pr_ppid * 1024));
  156. sproc->realppid = _psinfo->pr_ppid;
  157. sproc->realtgid = _psinfo->pr_ppid;
  158. // See note above (in common section) about this BINARY FRACTION
  159. proc->percent_cpu = ((uint16_t)_psinfo->pr_pctcpu / (double)32768) * (double)100.0;
  160. Process_updateCPUFieldWidths(proc->percent_cpu);
  161. proc->time = _psinfo->pr_time.tv_sec * 100 + _psinfo->pr_time.tv_nsec / 10000000;
  162. if (!preExisting) { // Tasks done only for NEW processes
  163. proc->isUserlandThread = false;
  164. proc->starttime_ctime = _psinfo->pr_start.tv_sec;
  165. }
  166. // Update proc and thread counts based on settings
  167. if (proc->isKernelThread && !settings->hideKernelThreads) {
  168. pt->kernelThreads += proc->nlwp;
  169. pt->totalTasks += proc->nlwp + 1;
  170. if (proc->state == RUNNING) {
  171. pt->runningTasks++;
  172. }
  173. } else if (!proc->isKernelThread) {
  174. if (proc->state == RUNNING) {
  175. pt->runningTasks++;
  176. }
  177. if (settings->hideUserlandThreads) {
  178. pt->totalTasks++;
  179. } else {
  180. pt->userlandThreads += proc->nlwp;
  181. pt->totalTasks += proc->nlwp + 1;
  182. }
  183. }
  184. proc->super.show = !(settings->hideKernelThreads && proc->isKernelThread);
  185. } else { // We are not in the master LWP, so jump to the LWP handling code
  186. proc->percent_cpu = ((uint16_t)_lwpsinfo->pr_pctcpu / (double)32768) * (double)100.0;
  187. Process_updateCPUFieldWidths(proc->percent_cpu);
  188. proc->time = _lwpsinfo->pr_time.tv_sec * 100 + _lwpsinfo->pr_time.tv_nsec / 10000000;
  189. if (!preExisting) { // Tasks done only for NEW LWPs
  190. proc->isUserlandThread = true;
  191. Process_setParent(proc, _psinfo->pr_pid * 1024);
  192. Process_setThreadGroup(proc, _psinfo->pr_pid * 1024);
  193. sproc->realppid = _psinfo->pr_pid;
  194. sproc->realtgid = _psinfo->pr_pid;
  195. proc->starttime_ctime = _lwpsinfo->pr_start.tv_sec;
  196. }
  197. // Top-level process only gets this for the representative LWP
  198. if (proc->isKernelThread && !settings->hideKernelThreads) {
  199. proc->super.show = true;
  200. }
  201. if (!proc->isKernelThread && !settings->hideUserlandThreads) {
  202. proc->super.show = true;
  203. }
  204. } // Top-level LWP or subordinate LWP
  205. // Common code pass 2
  206. if (!preExisting) {
  207. if ((sproc->realppid <= 0) && !(sproc->realpid <= 1)) {
  208. proc->isKernelThread = true;
  209. } else {
  210. proc->isKernelThread = false;
  211. }
  212. Process_fillStarttimeBuffer(proc);
  213. ProcessTable_add(pt, proc);
  214. }
  215. proc->super.updated = true;
  216. // End common code pass 2
  217. return 0;
  218. }
  219. void ProcessTable_goThroughEntries(ProcessTable* super) {
  220. super->kernelThreads = 1;
  221. proc_walk(&SolarisProcessTable_walkproc, super, PR_WALK_LWP);
  222. }