github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/priority.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <sys/resource.h>
    16  #include <sys/time.h>
    17  #include <sys/types.h>
    18  #include <unistd.h>
    19  
    20  #include <string>
    21  #include <vector>
    22  
    23  #include "gtest/gtest.h"
    24  #include "absl/strings/numbers.h"
    25  #include "absl/strings/str_split.h"
    26  #include "test/util/capability_util.h"
    27  #include "test/util/fs_util.h"
    28  #include "test/util/test_util.h"
    29  #include "test/util/thread_util.h"
    30  
    31  namespace gvisor {
    32  namespace testing {
    33  
    34  namespace {
    35  
    36  // These tests are for both the getpriority(2) and setpriority(2) syscalls
    37  // These tests are very rudimentary because getpriority and setpriority
    38  // have not yet been fully implemented.
    39  
    40  // Getpriority does something
    41  TEST(GetpriorityTest, Implemented) {
    42    // "getpriority() can legitimately return the value -1, it is necessary to
    43    // clear the external variable errno prior to the call"
    44    errno = 0;
    45    EXPECT_THAT(getpriority(PRIO_PROCESS, /*who=*/0), SyscallSucceeds());
    46  }
    47  
    48  // Invalid which
    49  TEST(GetpriorityTest, InvalidWhich) {
    50    errno = 0;
    51    EXPECT_THAT(getpriority(/*which=*/3, /*who=*/0),
    52                SyscallFailsWithErrno(EINVAL));
    53  }
    54  
    55  // Process is found when which=PRIO_PROCESS
    56  TEST(GetpriorityTest, ValidWho) {
    57    errno = 0;
    58    EXPECT_THAT(getpriority(PRIO_PROCESS, getpid()), SyscallSucceeds());
    59  }
    60  
    61  // Process is not found when which=PRIO_PROCESS
    62  TEST(GetpriorityTest, InvalidWho) {
    63    errno = 0;
    64    // Flaky, but it's tough to avoid a race condition when finding an unused pid
    65    EXPECT_THAT(getpriority(PRIO_PROCESS, /*who=*/INT_MAX - 1),
    66                SyscallFailsWithErrno(ESRCH));
    67  }
    68  
    69  // Setpriority does something
    70  TEST(SetpriorityTest, Implemented) {
    71    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
    72  
    73    // No need to clear errno for setpriority():
    74    // "The setpriority() call returns 0 if there is no error, or -1 if there is"
    75    EXPECT_THAT(setpriority(PRIO_PROCESS, /*who=*/0,
    76                            /*nice=*/16),  // NOLINT(bugprone-argument-comment)
    77                SyscallSucceeds());
    78  }
    79  
    80  // Invalid which
    81  TEST(Setpriority, InvalidWhich) {
    82    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
    83  
    84    EXPECT_THAT(setpriority(/*which=*/3, /*who=*/0,
    85                            /*nice=*/16),  // NOLINT(bugprone-argument-comment)
    86                SyscallFailsWithErrno(EINVAL));
    87  }
    88  
    89  // Process is found when which=PRIO_PROCESS
    90  TEST(SetpriorityTest, ValidWho) {
    91    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
    92  
    93    EXPECT_THAT(setpriority(PRIO_PROCESS, getpid(),
    94                            /*nice=*/16),  // NOLINT(bugprone-argument-comment)
    95                SyscallSucceeds());
    96  }
    97  
    98  // niceval is within the range [-20, 19]
    99  TEST(SetpriorityTest, InsideRange) {
   100    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
   101  
   102    // Set 0 < niceval < 19
   103    int nice = 12;
   104    EXPECT_THAT(setpriority(PRIO_PROCESS, getpid(), nice), SyscallSucceeds());
   105  
   106    errno = 0;
   107    EXPECT_THAT(getpriority(PRIO_PROCESS, getpid()),
   108                SyscallSucceedsWithValue(nice));
   109  
   110    // Set -20 < niceval < 0
   111    nice = -12;
   112    EXPECT_THAT(setpriority(PRIO_PROCESS, getpid(), nice), SyscallSucceeds());
   113  
   114    errno = 0;
   115    EXPECT_THAT(getpriority(PRIO_PROCESS, getpid()),
   116                SyscallSucceedsWithValue(nice));
   117  }
   118  
   119  // Verify that priority/niceness are exposed via /proc/PID/stat.
   120  TEST(SetpriorityTest, NicenessExposedViaProcfs) {
   121    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
   122  
   123    constexpr int kNiceVal = 12;
   124    ASSERT_THAT(setpriority(PRIO_PROCESS, getpid(), kNiceVal), SyscallSucceeds());
   125  
   126    errno = 0;
   127    ASSERT_THAT(getpriority(PRIO_PROCESS, getpid()),
   128                SyscallSucceedsWithValue(kNiceVal));
   129  
   130    // Now verify we can read that same value via /proc/self/stat.
   131    std::string proc_stat;
   132    ASSERT_NO_ERRNO(GetContents("/proc/self/stat", &proc_stat));
   133    std::vector<std::string> pieces = absl::StrSplit(proc_stat, ' ');
   134    ASSERT_GT(pieces.size(), 20);
   135  
   136    int niceness_procfs = 0;
   137    ASSERT_TRUE(absl::SimpleAtoi(pieces[18], &niceness_procfs));
   138    EXPECT_EQ(niceness_procfs, kNiceVal);
   139  }
   140  
   141  // In the kernel's implementation, values outside the range of [-20, 19] are
   142  // truncated to these minimum and maximum values. See
   143  // https://elixir.bootlin.com/linux/v4.4/source/kernel/sys.c#L190
   144  TEST(SetpriorityTest, OutsideRange) {
   145    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
   146  
   147    // Set niceval > 19
   148    EXPECT_THAT(setpriority(PRIO_PROCESS, getpid(),
   149                            /*nice=*/100),  // NOLINT(bugprone-argument-comment)
   150                SyscallSucceeds());
   151  
   152    errno = 0;
   153    // Test niceval truncated to 19
   154    EXPECT_THAT(getpriority(PRIO_PROCESS, getpid()),
   155                SyscallSucceedsWithValue(
   156                    /*maxnice=*/19));  // NOLINT(bugprone-argument-comment)
   157  
   158    // Set niceval < -20
   159    EXPECT_THAT(setpriority(PRIO_PROCESS, getpid(),
   160                            /*nice=*/-100),  // NOLINT(bugprone-argument-comment)
   161                SyscallSucceeds());
   162  
   163    errno = 0;
   164    // Test niceval truncated to -20
   165    EXPECT_THAT(getpriority(PRIO_PROCESS, getpid()),
   166                SyscallSucceedsWithValue(
   167                    /*minnice=*/-20));  // NOLINT(bugprone-argument-comment)
   168  }
   169  
   170  // Process is not found when which=PRIO_PROCESS
   171  TEST(SetpriorityTest, InvalidWho) {
   172    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
   173  
   174    // Flaky, but it's tough to avoid a race condition when finding an unused pid
   175    EXPECT_THAT(setpriority(PRIO_PROCESS,
   176                            /*who=*/INT_MAX - 1,
   177                            /*nice=*/16),  // NOLINT(bugprone-argument-comment)
   178                SyscallFailsWithErrno(ESRCH));
   179  }
   180  
   181  // Nice succeeds, correctly modifies (or in this case does not
   182  // modify priority of process
   183  TEST(SetpriorityTest, NiceSucceeds) {
   184    errno = 0;
   185    const int priority_before = getpriority(PRIO_PROCESS, /*who=*/0);
   186    ASSERT_THAT(nice(/*inc=*/0), SyscallSucceeds());
   187  
   188    // nice(0) should not change priority
   189    EXPECT_EQ(priority_before, getpriority(PRIO_PROCESS, /*who=*/0));
   190  }
   191  
   192  // Threads resulting from clone() maintain parent's priority
   193  // Changes to child priority do not affect parent's priority
   194  TEST(GetpriorityTest, CloneMaintainsPriority) {
   195    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_NICE)));
   196  
   197    constexpr int kParentPriority = 16;
   198    constexpr int kChildPriority = 14;
   199    ASSERT_THAT(setpriority(PRIO_PROCESS, getpid(), kParentPriority),
   200                SyscallSucceeds());
   201  
   202    ScopedThread th([]() {
   203      // Check that priority equals that of parent thread
   204      pid_t my_tid;
   205      EXPECT_THAT(my_tid = syscall(__NR_gettid), SyscallSucceeds());
   206      EXPECT_THAT(getpriority(PRIO_PROCESS, my_tid),
   207                  SyscallSucceedsWithValue(kParentPriority));
   208  
   209      // Change the child thread's priority
   210      EXPECT_THAT(setpriority(PRIO_PROCESS, my_tid, kChildPriority),
   211                  SyscallSucceeds());
   212    });
   213    th.Join();
   214  
   215    // Check that parent's priority reemained the same even though
   216    // the child's priority was altered
   217    EXPECT_EQ(kParentPriority, getpriority(PRIO_PROCESS, syscall(__NR_gettid)));
   218  }
   219  
   220  }  // namespace
   221  
   222  }  // namespace testing
   223  }  // namespace gvisor