chrt.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * chrt - manipulate real-time attributes of a process
  4. * Copyright (c) 2006-2007 Bernhard Reutner-Fischer
  5. *
  6. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  7. */
  8. //config:config CHRT
  9. //config: bool "chrt (4.7 kb)"
  10. //config: default y
  11. //config: help
  12. //config: Manipulate real-time attributes of a process.
  13. //config: This requires sched_{g,s}etparam support in your libc.
  14. //applet:IF_CHRT(APPLET_NOEXEC(chrt, chrt, BB_DIR_USR_BIN, BB_SUID_DROP, chrt))
  15. //kbuild:lib-$(CONFIG_CHRT) += chrt.o
  16. //usage:#define chrt_trivial_usage
  17. //usage: "-m | -p [PRIO] PID | [-rfobi] PRIO PROG ARGS"
  18. //usage:#define chrt_full_usage "\n\n"
  19. //usage: "Change scheduling priority and class for a process\n"
  20. //usage: "\n -m Show min/max priorities"
  21. //usage: "\n -p Operate on PID"
  22. //usage: "\n -r Set SCHED_RR class"
  23. //usage: "\n -f Set SCHED_FIFO class"
  24. //usage: "\n -o Set SCHED_OTHER class"
  25. //usage: "\n -b Set SCHED_BATCH class"
  26. //usage: "\n -i Set SCHED_IDLE class"
  27. //usage:
  28. //usage:#define chrt_example_usage
  29. //usage: "$ chrt -r 4 sleep 900; x=$!\n"
  30. //usage: "$ chrt -f -p 3 $x\n"
  31. //usage: "You need CAP_SYS_NICE privileges to set scheduling attributes of a process"
  32. #include <sched.h>
  33. #include "libbb.h"
  34. #ifndef SCHED_IDLE
  35. # define SCHED_IDLE 5
  36. #endif
  37. //musl has no __MUSL__ or similar define to check for,
  38. //but its <sys/types.h> has these lines:
  39. // #define __NEED_fsblkcnt_t
  40. // #define __NEED_fsfilcnt_t
  41. #if defined(__linux__) && defined(__NEED_fsblkcnt_t) && defined(__NEED_fsfilcnt_t)
  42. # define LIBC_IS_MUSL 1
  43. # include <sys/syscall.h>
  44. #else
  45. # define LIBC_IS_MUSL 0
  46. #endif
  47. static const char *policy_name(int pol)
  48. {
  49. if (pol > 6)
  50. return utoa(pol);
  51. return nth_string(
  52. "OTHER" "\0" /* 0:SCHED_OTHER */
  53. "FIFO" "\0" /* 1:SCHED_FIFO */
  54. "RR" "\0" /* 2:SCHED_RR */
  55. "BATCH" "\0" /* 3:SCHED_BATCH */
  56. "ISO" "\0" /* 4:SCHED_ISO */
  57. "IDLE" "\0" /* 5:SCHED_IDLE */
  58. "DEADLINE", /* 6:SCHED_DEADLINE */
  59. pol
  60. );
  61. }
  62. static void show_min_max(int pol)
  63. {
  64. const char *fmt = "SCHED_%s min/max priority\t: %u/%u\n";
  65. int max, min;
  66. max = sched_get_priority_max(pol);
  67. min = sched_get_priority_min(pol);
  68. if ((max|min) < 0)
  69. fmt = "SCHED_%s not supported\n";
  70. printf(fmt, policy_name(pol), min, max);
  71. }
  72. #define OPT_m (1<<0)
  73. #define OPT_p (1<<1)
  74. #define OPT_r (1<<2)
  75. #define OPT_f (1<<3)
  76. #define OPT_o (1<<4)
  77. #define OPT_b (1<<5)
  78. #define OPT_i (1<<6)
  79. int chrt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  80. int chrt_main(int argc UNUSED_PARAM, char **argv)
  81. {
  82. pid_t pid = 0;
  83. unsigned opt;
  84. struct sched_param sp;
  85. char *pid_str;
  86. char *priority = NULL;
  87. const char *current_new;
  88. int policy = SCHED_RR;
  89. int ret;
  90. opt = getopt32(argv, "^"
  91. "+" "mprfobi"
  92. "\0"
  93. /* only one policy accepted: */
  94. "r--fobi:f--robi:o--rfbi:b--rfoi:i--rfob"
  95. );
  96. if (opt & OPT_m) { /* print min/max and exit */
  97. show_min_max(SCHED_OTHER);
  98. show_min_max(SCHED_FIFO);
  99. show_min_max(SCHED_RR);
  100. show_min_max(SCHED_BATCH);
  101. show_min_max(SCHED_IDLE);
  102. fflush_stdout_and_exit(EXIT_SUCCESS);
  103. }
  104. //if (opt & OPT_r)
  105. // policy = SCHED_RR; - default, already set
  106. if (opt & OPT_f)
  107. policy = SCHED_FIFO;
  108. if (opt & OPT_o)
  109. policy = SCHED_OTHER;
  110. if (opt & OPT_b)
  111. policy = SCHED_BATCH;
  112. if (opt & OPT_i)
  113. policy = SCHED_IDLE;
  114. argv += optind;
  115. if (!argv[0])
  116. bb_show_usage();
  117. if (opt & OPT_p) {
  118. pid_str = *argv++;
  119. if (*argv) { /* "-p PRIO PID [...]" */
  120. priority = pid_str;
  121. pid_str = *argv;
  122. }
  123. /* else "-p PID", and *argv == NULL */
  124. pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
  125. } else {
  126. priority = *argv++;
  127. if (!*argv)
  128. bb_show_usage();
  129. }
  130. current_new = "current\0new";
  131. if (opt & OPT_p) {
  132. int pol;
  133. print_rt_info:
  134. #if LIBC_IS_MUSL
  135. /* musl libc returns ENOSYS for its sched_getscheduler library
  136. * function, because the sched_getscheduler Linux kernel system call
  137. * does not conform to Posix; so we use the system call directly
  138. */
  139. pol = syscall(SYS_sched_getscheduler, pid);
  140. #else
  141. pol = sched_getscheduler(pid);
  142. #endif
  143. if (pol < 0)
  144. bb_perror_msg_and_die("can't %cet pid %u's policy", 'g', (int)pid);
  145. #ifdef SCHED_RESET_ON_FORK
  146. /* "Since Linux 2.6.32, the SCHED_RESET_ON_FORK flag
  147. * can be ORed in policy when calling sched_setscheduler().
  148. * As a result of including this flag, children created by
  149. * fork(2) do not inherit privileged scheduling policies"
  150. *
  151. * This bit is also returned by sched_getscheduler()!
  152. * (TODO: do we want to show it?)
  153. */
  154. pol &= ~SCHED_RESET_ON_FORK;
  155. #endif
  156. printf("pid %u's %s scheduling policy: SCHED_%s\n",
  157. pid, current_new, policy_name(pol)
  158. );
  159. #if LIBC_IS_MUSL
  160. ret = syscall(SYS_sched_getparam, pid, &sp);
  161. #else
  162. ret = sched_getparam(pid, &sp);
  163. #endif
  164. if (ret)
  165. bb_perror_msg_and_die("can't get pid %u's attributes", (int)pid);
  166. printf("pid %u's %s scheduling priority: %d\n",
  167. (int)pid, current_new, sp.sched_priority
  168. );
  169. if (!*argv) {
  170. /* Either it was just "-p PID",
  171. * or it was "-p PRIO PID" and we came here
  172. * for the second time (see goto below) */
  173. return EXIT_SUCCESS;
  174. }
  175. *argv = NULL;
  176. current_new += 8;
  177. }
  178. sp.sched_priority = xstrtou_range(priority, 0,
  179. sched_get_priority_min(policy), sched_get_priority_max(policy)
  180. );
  181. #if LIBC_IS_MUSL
  182. ret = syscall(SYS_sched_setscheduler, pid, policy, &sp);
  183. #else
  184. ret = sched_setscheduler(pid, policy, &sp);
  185. #endif
  186. if (ret)
  187. bb_perror_msg_and_die("can't %cet pid %u's policy", 's', (int)pid);
  188. if (!argv[0]) /* "-p PRIO PID [...]" */
  189. goto print_rt_info;
  190. BB_EXECVP_or_die(argv);
  191. }