gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/getrusage.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 <signal.h>
    16  #include <sys/mman.h>
    17  #include <sys/resource.h>
    18  #include <sys/types.h>
    19  #include <sys/wait.h>
    20  
    21  #include "gtest/gtest.h"
    22  #include "absl/time/clock.h"
    23  #include "absl/time/time.h"
    24  #include "test/util/logging.h"
    25  #include "test/util/memory_util.h"
    26  #include "test/util/multiprocess_util.h"
    27  #include "test/util/signal_util.h"
    28  #include "test/util/test_util.h"
    29  
    30  namespace gvisor {
    31  namespace testing {
    32  
    33  namespace {
    34  
    35  TEST(GetrusageTest, BasicFork) {
    36    pid_t pid = fork();
    37    if (pid == 0) {
    38      struct rusage rusage_self;
    39      TEST_PCHECK(getrusage(RUSAGE_SELF, &rusage_self) == 0);
    40      struct rusage rusage_children;
    41      TEST_PCHECK(getrusage(RUSAGE_CHILDREN, &rusage_children) == 0);
    42      // The child has consumed some memory.
    43      TEST_CHECK(rusage_self.ru_maxrss != 0);
    44      // The child has no children of its own.
    45      TEST_CHECK(rusage_children.ru_maxrss == 0);
    46      _exit(0);
    47    }
    48    ASSERT_THAT(pid, SyscallSucceeds());
    49    int status;
    50    ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0), SyscallSucceeds());
    51    struct rusage rusage_self;
    52    ASSERT_THAT(getrusage(RUSAGE_SELF, &rusage_self), SyscallSucceeds());
    53    struct rusage rusage_children;
    54    ASSERT_THAT(getrusage(RUSAGE_CHILDREN, &rusage_children), SyscallSucceeds());
    55    // The parent has consumed some memory.
    56    EXPECT_GT(rusage_self.ru_maxrss, 0);
    57    // The child has consumed some memory, and because it has exited we can get
    58    // its max RSS.
    59    EXPECT_GT(rusage_children.ru_maxrss, 0);
    60  }
    61  
    62  // Verifies that a process can get the max resident set size of its grandchild,
    63  // i.e. that maxrss propagates correctly from children to waiting parents.
    64  TEST(GetrusageTest, Grandchild) {
    65    constexpr int kGrandchildSizeKb = 1024;
    66    pid_t pid = fork();
    67    if (pid == 0) {
    68      pid = fork();
    69      if (pid == 0) {
    70        int flags = MAP_ANONYMOUS | MAP_POPULATE | MAP_PRIVATE;
    71        void* addr =
    72            mmap(nullptr, kGrandchildSizeKb * 1024, PROT_WRITE, flags, -1, 0);
    73        TEST_PCHECK(addr != MAP_FAILED);
    74      } else {
    75        int status;
    76        TEST_PCHECK(RetryEINTR(waitpid)(pid, &status, 0) == pid);
    77      }
    78      _exit(0);
    79    }
    80    ASSERT_THAT(pid, SyscallSucceeds());
    81    int status;
    82    ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0), SyscallSucceeds());
    83    struct rusage rusage_self;
    84    ASSERT_THAT(getrusage(RUSAGE_SELF, &rusage_self), SyscallSucceeds());
    85    struct rusage rusage_children;
    86    ASSERT_THAT(getrusage(RUSAGE_CHILDREN, &rusage_children), SyscallSucceeds());
    87    // The parent has consumed some memory.
    88    EXPECT_GT(rusage_self.ru_maxrss, 0);
    89    // The child should consume next to no memory, but the grandchild will
    90    // consume at least 1MB. Verify that usage bubbles up to the grandparent.
    91    EXPECT_GT(rusage_children.ru_maxrss, kGrandchildSizeKb);
    92  }
    93  
    94  // Verifies that processes ignoring SIGCHLD do not have updated child maxrss
    95  // updated.
    96  TEST(GetrusageTest, IgnoreSIGCHLD) {
    97    const auto rest = [] {
    98      struct sigaction sa;
    99      sa.sa_handler = SIG_IGN;
   100      sa.sa_flags = 0;
   101      auto cleanup = TEST_CHECK_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGCHLD, sa));
   102      pid_t pid = fork();
   103      if (pid == 0) {
   104        struct rusage rusage_self;
   105        TEST_PCHECK(getrusage(RUSAGE_SELF, &rusage_self) == 0);
   106        // The child has consumed some memory.
   107        TEST_CHECK(rusage_self.ru_maxrss != 0);
   108        _exit(0);
   109      }
   110      TEST_CHECK_SUCCESS(pid);
   111      int status;
   112      TEST_CHECK_ERRNO(RetryEINTR(waitpid)(pid, &status, 0), ECHILD);
   113      struct rusage rusage_self;
   114      TEST_CHECK_SUCCESS(getrusage(RUSAGE_SELF, &rusage_self));
   115      struct rusage rusage_children;
   116      TEST_CHECK_SUCCESS(getrusage(RUSAGE_CHILDREN, &rusage_children));
   117      // The parent has consumed some memory.
   118      TEST_CHECK(rusage_self.ru_maxrss > 0);
   119      // The child's maxrss should not have propagated up.
   120      TEST_CHECK(rusage_children.ru_maxrss == 0);
   121    };
   122    // Execute inside a forked process so that rusage_children is clean.
   123    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   124  }
   125  
   126  // Verifies that zombie processes do not update their parent's maxrss. Only
   127  // reaped processes should do this.
   128  TEST(GetrusageTest, IgnoreZombie) {
   129    const auto rest = [] {
   130      pid_t pid = fork();
   131      if (pid == 0) {
   132        struct rusage rusage_self;
   133        TEST_PCHECK(getrusage(RUSAGE_SELF, &rusage_self) == 0);
   134        struct rusage rusage_children;
   135        TEST_PCHECK(getrusage(RUSAGE_CHILDREN, &rusage_children) == 0);
   136        // The child has consumed some memory.
   137        TEST_CHECK(rusage_self.ru_maxrss != 0);
   138        // The child has no children of its own.
   139        TEST_CHECK(rusage_children.ru_maxrss == 0);
   140        _exit(0);
   141      }
   142      TEST_CHECK_SUCCESS(pid);
   143      // Give the child time to exit. Because we don't call wait, the child should
   144      // remain a zombie.
   145      absl::SleepFor(absl::Seconds(5));
   146      struct rusage rusage_self;
   147      TEST_CHECK_SUCCESS(getrusage(RUSAGE_SELF, &rusage_self));
   148      struct rusage rusage_children;
   149      TEST_CHECK_SUCCESS(getrusage(RUSAGE_CHILDREN, &rusage_children));
   150      // The parent has consumed some memory.
   151      TEST_CHECK(rusage_self.ru_maxrss > 0);
   152      // The child has consumed some memory, but hasn't been reaped.
   153      TEST_CHECK(rusage_children.ru_maxrss == 0);
   154    };
   155    // Execute inside a forked process so that rusage_children is clean.
   156    EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
   157  }
   158  
   159  TEST(GetrusageTest, Wait4) {
   160    pid_t pid = fork();
   161    if (pid == 0) {
   162      struct rusage rusage_self;
   163      TEST_PCHECK(getrusage(RUSAGE_SELF, &rusage_self) == 0);
   164      struct rusage rusage_children;
   165      TEST_PCHECK(getrusage(RUSAGE_CHILDREN, &rusage_children) == 0);
   166      // The child has consumed some memory.
   167      TEST_CHECK(rusage_self.ru_maxrss != 0);
   168      // The child has no children of its own.
   169      TEST_CHECK(rusage_children.ru_maxrss == 0);
   170      _exit(0);
   171    }
   172    ASSERT_THAT(pid, SyscallSucceeds());
   173    struct rusage rusage_children;
   174    int status;
   175    ASSERT_THAT(RetryEINTR(wait4)(pid, &status, 0, &rusage_children),
   176                SyscallSucceeds());
   177    // The child has consumed some memory, and because it has exited we can get
   178    // its max RSS.
   179    EXPECT_GT(rusage_children.ru_maxrss, 0);
   180  }
   181  
   182  }  // namespace
   183  
   184  }  // namespace testing
   185  }  // namespace gvisor