Scheduling.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. htop - Scheduling.c
  3. (C) 2023 htop dev team
  4. Released under the GNU GPLv2+, see the COPYING file
  5. in the source distribution for its full text.
  6. */
  7. #include "config.h" // IWYU pragma: keep
  8. #include "Scheduling.h"
  9. #ifdef SCHEDULER_SUPPORT
  10. #include <assert.h>
  11. #include <stddef.h>
  12. #include "FunctionBar.h"
  13. #include "ListItem.h"
  14. #include "Macros.h"
  15. #include "Object.h"
  16. #include "Panel.h"
  17. #include "XUtils.h"
  18. static const SchedulingPolicy policies[] = {
  19. [SCHED_OTHER] = { "Other", SCHED_OTHER, false },
  20. #ifdef SCHED_BATCH
  21. [SCHED_BATCH] = { "Batch", SCHED_BATCH, false },
  22. #endif
  23. #ifdef SCHED_IDLE
  24. [SCHED_IDLE] = { "Idle", SCHED_IDLE, false },
  25. #endif
  26. [SCHED_FIFO] = { "FiFo", SCHED_FIFO, true },
  27. [SCHED_RR] = { "RoundRobin", SCHED_RR, true },
  28. };
  29. #ifdef SCHED_RESET_ON_FORK
  30. static bool reset_on_fork = false;
  31. #endif
  32. Panel* Scheduling_newPolicyPanel(int preSelectedPolicy) {
  33. Panel* this = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Select ", "Cancel "));
  34. Panel_setHeader(this, "New policy:");
  35. #ifdef SCHED_RESET_ON_FORK
  36. Panel_add(this, (Object*) ListItem_new(reset_on_fork ? "Reset on fork: on" : "Reset on fork: off", -1));
  37. #endif
  38. for (unsigned i = 0; i < ARRAYSIZE(policies); i++) {
  39. if (!policies[i].name)
  40. continue;
  41. Panel_add(this, (Object*) ListItem_new(policies[i].name, policies[i].id));
  42. if (policies[i].id == preSelectedPolicy)
  43. Panel_setSelected(this, i);
  44. }
  45. return this;
  46. }
  47. void Scheduling_togglePolicyPanelResetOnFork(Panel* schedPanel) {
  48. #ifdef SCHED_RESET_ON_FORK
  49. reset_on_fork = !reset_on_fork;
  50. ListItem* item = (ListItem*) Panel_get(schedPanel, 0);
  51. free_and_xStrdup(&item->value, reset_on_fork ? "Reset on fork: on" : "Reset on fork: off");
  52. #else
  53. (void)schedPanel;
  54. #endif
  55. }
  56. Panel* Scheduling_newPriorityPanel(int policy, int preSelectedPriority) {
  57. if (policy < 0 || (unsigned)policy >= ARRAYSIZE(policies) || policies[policy].name == NULL)
  58. return NULL;
  59. if (!policies[policy].prioritySupport)
  60. return NULL;
  61. int min = sched_get_priority_min(policy);
  62. if (min < 0)
  63. return NULL;
  64. int max = sched_get_priority_max(policy);
  65. if (max < 0 )
  66. return NULL;
  67. Panel* this = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Select ", "Cancel "));
  68. Panel_setHeader(this, "Priority:");
  69. for (int i = min; i <= max; i++) {
  70. char buf[16];
  71. xSnprintf(buf, sizeof(buf), "%d", i);
  72. Panel_add(this, (Object*) ListItem_new(buf, i));
  73. if (i == preSelectedPriority)
  74. Panel_setSelected(this, i);
  75. }
  76. return this;
  77. }
  78. static bool Scheduling_setPolicy(Process* p, Arg arg) {
  79. const SchedulingArg* sarg = arg.v;
  80. int policy = sarg->policy;
  81. assert(policy >= 0);
  82. assert((unsigned)policy < ARRAYSIZE(policies));
  83. assert(policies[policy].name);
  84. const struct sched_param param = { .sched_priority = policies[policy].prioritySupport ? sarg->priority : 0 };
  85. #ifdef SCHED_RESET_ON_FORK
  86. if (reset_on_fork)
  87. policy &= SCHED_RESET_ON_FORK;
  88. #endif
  89. int r = sched_setscheduler(Process_getPid(p), policy, &param);
  90. /* POSIX says on success the previous scheduling policy should be returned,
  91. * but Linux always returns 0. */
  92. return r != -1;
  93. }
  94. bool Scheduling_rowSetPolicy(Row* row, Arg arg) {
  95. Process* p = (Process*) row;
  96. assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class));
  97. return Scheduling_setPolicy(p, arg);
  98. }
  99. const char* Scheduling_formatPolicy(int policy) {
  100. #ifdef SCHED_RESET_ON_FORK
  101. policy = policy & ~SCHED_RESET_ON_FORK;
  102. #endif
  103. switch (policy) {
  104. case SCHED_OTHER:
  105. return "OTHER";
  106. case SCHED_FIFO:
  107. return "FIFO";
  108. case SCHED_RR:
  109. return "RR";
  110. #ifdef SCHED_BATCH
  111. case SCHED_BATCH:
  112. return "BATCH";
  113. #endif
  114. #ifdef SCHED_IDLE
  115. case SCHED_IDLE:
  116. return "IDLE";
  117. #endif
  118. #ifdef SCHED_DEADLINE
  119. case SCHED_DEADLINE:
  120. return "EDF";
  121. #endif
  122. default:
  123. return "???";
  124. }
  125. }
  126. /*
  127. * Gather scheduling policy (thread-specific data)
  128. */
  129. void Scheduling_readProcessPolicy(Process* proc) {
  130. proc->scheduling_policy = sched_getscheduler(Process_getPid(proc));
  131. }
  132. #endif /* SCHEDULER_SUPPORT */