ProcessTableModel.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #include "ProcessTableModel.h"
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <pwd.h>
  5. ProcessTableModel::ProcessTableModel()
  6. {
  7. setpwent();
  8. while (auto* passwd = getpwent())
  9. m_usernames.set(passwd->pw_uid, passwd->pw_name);
  10. endpwent();
  11. m_generic_process_icon = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/gear16.rgb", { 16, 16 });
  12. m_high_priority_icon = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/highpriority16.rgb", { 16, 16 });
  13. m_low_priority_icon = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/lowpriority16.rgb", { 16, 16 });
  14. m_normal_priority_icon = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/normalpriority16.rgb", { 16, 16 });
  15. }
  16. ProcessTableModel::~ProcessTableModel()
  17. {
  18. }
  19. int ProcessTableModel::row_count() const
  20. {
  21. return m_processes.size();
  22. }
  23. int ProcessTableModel::column_count() const
  24. {
  25. return Column::__Count;
  26. }
  27. String ProcessTableModel::column_name(int column) const
  28. {
  29. switch (column) {
  30. case Column::Icon: return "";
  31. case Column::PID: return "PID";
  32. case Column::State: return "State";
  33. case Column::User: return "User";
  34. case Column::Priority: return "Pr";
  35. case Column::Linear: return "Linear";
  36. case Column::Physical: return "Physical";
  37. case Column::CPU: return "CPU";
  38. case Column::Name: return "Name";
  39. default: ASSERT_NOT_REACHED();
  40. }
  41. }
  42. GTableModel::ColumnMetadata ProcessTableModel::column_metadata(int column) const
  43. {
  44. switch (column) {
  45. case Column::Icon: return { 16, TextAlignment::CenterLeft };
  46. case Column::PID: return { 25, TextAlignment::CenterRight };
  47. case Column::State: return { 75, TextAlignment::CenterLeft };
  48. case Column::Priority: return { 16, TextAlignment::CenterLeft };
  49. case Column::User: return { 50, TextAlignment::CenterLeft };
  50. case Column::Linear: return { 65, TextAlignment::CenterRight };
  51. case Column::Physical: return { 65, TextAlignment::CenterRight };
  52. case Column::CPU: return { 25, TextAlignment::CenterRight };
  53. case Column::Name: return { 140, TextAlignment::CenterLeft };
  54. default: ASSERT_NOT_REACHED();
  55. }
  56. }
  57. static String pretty_byte_size(size_t size)
  58. {
  59. return String::format("%uK", size / 1024);
  60. }
  61. GVariant ProcessTableModel::data(const GModelIndex& index, Role role) const
  62. {
  63. ASSERT(is_valid(index));
  64. auto it = m_processes.find(m_pids[index.row()]);
  65. auto& process = *(*it).value;
  66. if (role == Role::Sort) {
  67. switch (index.column()) {
  68. case Column::Icon: return 0;
  69. case Column::PID: return process.current_state.pid;
  70. case Column::State: return process.current_state.state;
  71. case Column::User: return process.current_state.user;
  72. case Column::Priority:
  73. if (process.current_state.priority == "Low")
  74. return 0;
  75. if (process.current_state.priority == "Normal")
  76. return 1;
  77. if (process.current_state.priority == "High")
  78. return 2;
  79. ASSERT_NOT_REACHED();
  80. return 3;
  81. case Column::Linear: return (int)process.current_state.linear;
  82. case Column::Physical: return (int)process.current_state.physical;
  83. case Column::CPU: return process.current_state.cpu_percent;
  84. case Column::Name: return process.current_state.name;
  85. }
  86. ASSERT_NOT_REACHED();
  87. return { };
  88. }
  89. switch (index.column()) {
  90. case Column::Icon: return *m_generic_process_icon;
  91. case Column::PID: return process.current_state.pid;
  92. case Column::State: return process.current_state.state;
  93. case Column::User: return process.current_state.user;
  94. case Column::Priority:
  95. if (process.current_state.priority == "High")
  96. return *m_high_priority_icon;
  97. if (process.current_state.priority == "Low")
  98. return *m_low_priority_icon;
  99. if (process.current_state.priority == "Normal")
  100. return *m_normal_priority_icon;
  101. return process.current_state.priority;
  102. case Column::Linear: return pretty_byte_size(process.current_state.linear);
  103. case Column::Physical: return pretty_byte_size(process.current_state.physical);
  104. case Column::CPU: return process.current_state.cpu_percent;
  105. case Column::Name: return process.current_state.name;
  106. }
  107. ASSERT_NOT_REACHED();
  108. }
  109. void ProcessTableModel::update()
  110. {
  111. FILE* fp = fopen("/proc/all", "r");
  112. if (!fp) {
  113. perror("failed to open /proc/all");
  114. exit(1);
  115. }
  116. unsigned last_sum_nsched = 0;
  117. for (auto& it : m_processes)
  118. last_sum_nsched += it.value->current_state.nsched;
  119. HashTable<pid_t> live_pids;
  120. unsigned sum_nsched = 0;
  121. for (;;) {
  122. char buf[BUFSIZ];
  123. char* ptr = fgets(buf, sizeof(buf), fp);
  124. if (!ptr)
  125. break;
  126. auto parts = String(buf, Chomp).split(',');
  127. if (parts.size() < 17)
  128. break;
  129. bool ok;
  130. pid_t pid = parts[0].to_uint(ok);
  131. ASSERT(ok);
  132. unsigned nsched = parts[1].to_uint(ok);
  133. ASSERT(ok);
  134. ProcessState state;
  135. state.pid = pid;
  136. state.nsched = nsched;
  137. unsigned uid = parts[5].to_uint(ok);
  138. ASSERT(ok);
  139. {
  140. auto it = m_usernames.find((uid_t)uid);
  141. if (it != m_usernames.end())
  142. state.user = String::format("%s", (*it).value.characters());
  143. else
  144. state.user = String::format("%u", uid);
  145. }
  146. state.priority = parts[16];
  147. state.state = parts[7];
  148. state.name = parts[11];
  149. state.linear = parts[12].to_uint(ok);
  150. ASSERT(ok);
  151. state.physical = parts[13].to_uint(ok);
  152. ASSERT(ok);
  153. sum_nsched += nsched;
  154. {
  155. auto it = m_processes.find(pid);
  156. if (it == m_processes.end())
  157. m_processes.set(pid, make<Process>());
  158. }
  159. auto it = m_processes.find(pid);
  160. ASSERT(it != m_processes.end());
  161. (*it).value->previous_state = (*it).value->current_state;
  162. (*it).value->current_state = state;
  163. live_pids.set(pid);
  164. }
  165. int rc = fclose(fp);
  166. ASSERT(rc == 0);
  167. m_pids.clear();
  168. Vector<pid_t> pids_to_remove;
  169. for (auto& it : m_processes) {
  170. if (!live_pids.contains(it.key)) {
  171. pids_to_remove.append(it.key);
  172. continue;
  173. }
  174. auto& process = *it.value;
  175. dword nsched_diff = process.current_state.nsched - process.previous_state.nsched;
  176. process.current_state.cpu_percent = ((float)nsched_diff * 100) / (float)(sum_nsched - last_sum_nsched);
  177. m_pids.append(it.key);
  178. }
  179. for (auto pid : pids_to_remove)
  180. m_processes.remove(pid);
  181. did_update();
  182. }