coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] nice: add -a arg to set absolute niceness


From: Kevin Mark
Subject: [PATCH] nice: add -a arg to set absolute niceness
Date: Fri, 21 Aug 2020 05:36:29 -0700

Adds an -a --absolute argument to nice which sets niceness to the
given value as opposed to -n --adjustment which sets niceness
relative to the current niceness.

$ nice -n $((12 - $(nice))) nice
12

can be replaced with

$ nice -a 12 nice
12

clarifying the intent of the command as well as operating in
environments which may not be able to easily retrieve the current
niceness.

Avoided significant refactoring by converting the given absolute
value into a relative one which can be used by the relative
value-based code.

Pulled the GET_NICENESS and range enforcement operations into their
own functions, get_cached_niceness and clamp_int_str respectively.
get_cached_niceness avoids repeated syscalls by statically storing
the first result.

* doc/coreutils.texi (nice): document new argument, add example
* src/nice.c (clamp_int_str, get_cached_niceness, main): add new
  argument, minor refactors to deduplicate code
* tests/misc/nice-fail.sh: add new known failure tests
* tests/misc/nice.sh: add new feature tests
---
 doc/coreutils.texi      | 24 ++++++++++++++-
 src/nice.c              | 66 +++++++++++++++++++++++++++++++----------
 tests/misc/nice-fail.sh |  2 ++
 tests/misc/nice.sh      |  8 +++++
 4 files changed, 83 insertions(+), 17 deletions(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index a55514d59..e3a205b0e 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -17795,7 +17795,7 @@ built-in utilities}).
 Note to change the @dfn{niceness} of an existing process,
 one needs to use the @command{renice} command.
 
-The program accepts the following option.  Also see @ref{Common options}.
+The program accepts the following options.  Also see @ref{Common options}.
 Options must precede operands.
 
 @table @samp
@@ -17812,6 +17812,15 @@ For compatibility @command{nice} also supports an 
obsolete
 option syntax @option{-@var{adjustment}}.  New scripts should use
 @option{-n @var{adjustment}} instead.
 
+@item -a @var{absolute}
+@itemx --absolute=@var{absolute}
+@opindex -a
+@opindex --absolute
+Sets the command's niceness to @var{absolute}. If @var{absolute} is
+less than the current niceness and you lack appropriate privileges,
+@command{nice} issues a warning but otherwise acts as if you specified
+the current niceness.
+
 @end table
 
 @command{nice} is installed only on systems that have the POSIX
@@ -17859,6 +17868,19 @@ $ nice nice -n 3 nice
 13
 @end example
 
+The @var{absolute} argument sets a command's niceness regardless of the
+current niceness.
+
+Here we demonstrate that the final niceness value is 5 even when we
+previously set the niceness to 1 and 2:
+
+@example
+$ nice -a 1 nice -a 5 nice
+5
+$ nice -a 2 nice -a 5 nice
+5
+@end example
+
 Specifying a niceness larger than the supported range
 is the same as specifying the maximum supported value:
 
diff --git a/src/nice.c b/src/nice.c
index 0933e85a0..53f9d4045 100644
--- a/src/nice.c
+++ b/src/nice.c
@@ -57,6 +57,7 @@
 
 static struct option const longopts[] =
 {
+  {"absolute", required_argument, NULL, 'a'},
   {"adjustment", required_argument, NULL, 'n'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
@@ -81,6 +82,7 @@ With no COMMAND, print the current niceness.  Niceness values 
range from\n\
       emit_mandatory_arg_note ();
 
       fputs (_("\
+  -a, --absolute=N     set the niceness to N\n\
   -n, --adjustment=N   add integer N to the niceness (default 10)\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
@@ -97,10 +99,39 @@ perm_related_errno (int err)
   return err == EACCES || err == EPERM;
 }
 
+static int
+clamp_int_str (char const *str, char const *name, int min, int max)
+{
+  long int tmp;
+  if (LONGINT_OVERFLOW < xstrtol (str, NULL, 10, &tmp, ""))
+  {
+    die (EXIT_CANCELED, 0, _("invalid %s %s"), name, quote (str));
+  }
+  return MAX (min, MIN (tmp, max));
+}
+
+static int
+get_cached_niceness (void)
+{
+  static bool cached = false;
+  static int niceness;
+  if (cached)
+  {
+    return niceness;
+  }
+  niceness = GET_NICENESS ();
+  if (niceness == -1 && errno != 0)
+  {
+    die (EXIT_CANCELED, errno, _("cannot get niceness"));
+  }
+  cached = true;
+  return niceness;
+}
+
 int
 main (int argc, char **argv)
 {
-  int current_niceness;
+  bool absolute = false;
   int adjustment = 10;
   char const *adjustment_given = NULL;
   bool ok;
@@ -136,11 +167,16 @@ main (int argc, char **argv)
           /* Initialize getopt_long's internal state.  */
           optind = 0;
 
-          c = getopt_long (fake_argc, fake_argv, "+n:", longopts, NULL);
+          c = getopt_long (fake_argc, fake_argv, "+a:n:", longopts, NULL);
           i += optind - 1;
 
           switch (c)
             {
+            case 'a':
+            absolute = true;
+            adjustment_given = optarg;
+            break;
+
             case 'n':
               adjustment_given = optarg;
               break;
@@ -167,12 +203,16 @@ main (int argc, char **argv)
       /* If the requested adjustment is outside the valid range,
          silently bring it to just within range; this mimics what
          "setpriority" and "nice" do.  */
-      enum { MIN_ADJUSTMENT = 1 - 2 * NZERO, MAX_ADJUSTMENT = 2 * NZERO - 1 };
-      long int tmp;
-      if (LONGINT_OVERFLOW < xstrtol (adjustment_given, NULL, 10, &tmp, ""))
-        die (EXIT_CANCELED, 0, _("invalid adjustment %s"),
-             quote (adjustment_given));
-      adjustment = MAX (MIN_ADJUSTMENT, MIN (tmp, MAX_ADJUSTMENT));
+      if (absolute)
+      {
+        adjustment = clamp_int_str (adjustment_given, "niceness", -NZERO,
+                                    NZERO - 1) - get_cached_niceness ();
+      }
+      else
+      {
+        adjustment = clamp_int_str (adjustment_given, "adjustment",
+                                    1 - 2 * NZERO, 2 * NZERO - 1);
+      }
     }
 
   if (i == argc)
@@ -184,10 +224,7 @@ main (int argc, char **argv)
         }
       /* No command given; print the niceness.  */
       errno = 0;
-      current_niceness = GET_NICENESS ();
-      if (current_niceness == -1 && errno != 0)
-        die (EXIT_CANCELED, errno, _("cannot get niceness"));
-      printf ("%d\n", current_niceness);
+      printf ("%d\n", get_cached_niceness ());
       return EXIT_SUCCESS;
     }
 
@@ -195,10 +232,7 @@ main (int argc, char **argv)
 #if HAVE_NICE
   ok = (nice (adjustment) != -1 || errno == 0);
 #else
-  current_niceness = GET_NICENESS ();
-  if (current_niceness == -1 && errno != 0)
-    die (EXIT_CANCELED, errno, _("cannot get niceness"));
-  ok = (setpriority (PRIO_PROCESS, 0, current_niceness + adjustment) == 0);
+  ok = setpriority (PRIO_PROCESS, 0, get_cached_niceness () + adjustment) == 0;
 #endif
   if (!ok)
     {
diff --git a/tests/misc/nice-fail.sh b/tests/misc/nice-fail.sh
index 493336b54..a70ecaa02 100755
--- a/tests/misc/nice-fail.sh
+++ b/tests/misc/nice-fail.sh
@@ -23,8 +23,10 @@ print_ver_ nice
 
 # These tests verify exact status of internal failure.
 returns_ 125 nice -n 1 || fail=1 # missing command
+returns_ 125 nice -a 1 || fail=1 # missing command
 returns_ 125 nice --- || fail=1 # unknown option
 returns_ 125 nice -n 1a || fail=1 # invalid adjustment
+returns_ 125 nice -a 1a || fail=1 # invalid absolute
 returns_ 2 nice sh -c 'exit 2' || fail=1 # exit status propagation
 returns_ 126 nice . || fail=1 # invalid command
 returns_ 127 nice no_such || fail=1 # no such command
diff --git a/tests/misc/nice.sh b/tests/misc/nice.sh
index 4d31977fe..a2aab2e4d 100755
--- a/tests/misc/nice.sh
+++ b/tests/misc/nice.sh
@@ -40,6 +40,10 @@ tests='
 17 --1:-n:2:-13 13
 18 -n:-1:-12 12
 19 --1:-12 12
+20 --adjustment:1 1
+21 -a:1 1
+22 --absolute:1 1
+23 -a:1:-n:5 5
 NA LAST NA
 '
 set $tests
@@ -90,4 +94,8 @@ else
   test x$(nice --1 nice) = x-1 || fail=1
 fi
 
+# Test absolute niceness - current niceness should not impact result
+# Using "-a" here causes a false positive in prohibit_test_minus_ao
+test x$(nice -n 5 nice --absolute 8 nice 2> /dev/null) = x8 || fail=1
+
 Exit $fail
-- 
2.25.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]