github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/concurrency.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  
    17  #include <atomic>
    18  
    19  #include "gtest/gtest.h"
    20  #include "absl/strings/string_view.h"
    21  #include "absl/time/clock.h"
    22  #include "absl/time/time.h"
    23  #include "benchmark/benchmark.h"
    24  #include "test/util/platform_util.h"
    25  #include "test/util/test_util.h"
    26  #include "test/util/thread_util.h"
    27  
    28  namespace gvisor {
    29  namespace testing {
    30  namespace {
    31  
    32  // Test that a thread that never yields to the OS does not prevent other threads
    33  // from running.
    34  TEST(ConcurrencyTest, SingleProcessMultithreaded) {
    35    std::atomic<int> a(0);
    36  
    37    ScopedThread t([&a]() {
    38      while (!a.load()) {
    39      }
    40    });
    41  
    42    absl::SleepFor(absl::Seconds(1));
    43  
    44    // We are still able to execute code in this thread. The other hasn't
    45    // permanently hung execution in both threads.
    46    a.store(1);
    47  }
    48  
    49  // Test that multiple threads in this process continue to execute in parallel,
    50  // even if an unrelated second process is spawned. Regression test for
    51  // b/32119508.
    52  TEST(ConcurrencyTest, MultiProcessMultithreaded) {
    53    // In PID 1, start TIDs 1 and 2, and put both to sleep.
    54    //
    55    // Start PID 3, which spins for 5 seconds, then exits.
    56    //
    57    // TIDs 1 and 2 wake and attempt to Activate, which cannot occur until PID 3
    58    // exits.
    59    //
    60    // Both TIDs 1 and 2 should be woken. If they are not both woken, the test
    61    // hangs.
    62    //
    63    // This is all fundamentally racy. If we are failing to wake all threads, the
    64    // expectation is that this test becomes flaky, rather than consistently
    65    // failing.
    66    //
    67    // If additional background threads fail to block, we may never schedule the
    68    // child, at which point this test effectively becomes
    69    // MultiProcessConcurrency. That's not expected to occur.
    70  
    71    std::atomic<int> a(0);
    72    ScopedThread t([&a]() {
    73      // Block so that PID 3 can execute and we can wait on its exit.
    74      absl::SleepFor(absl::Seconds(1));
    75      while (!a.load()) {
    76      }
    77    });
    78  
    79    pid_t child_pid = fork();
    80    if (child_pid == 0) {
    81      // Busy wait without making any blocking syscalls.
    82      auto end = absl::Now() + absl::Seconds(5);
    83      while (absl::Now() < end) {
    84      }
    85      _exit(0);
    86    }
    87    ASSERT_THAT(child_pid, SyscallSucceeds());
    88  
    89    absl::SleepFor(absl::Seconds(1));
    90  
    91    // If only TID 1 is woken, thread.Join will hang.
    92    // If only TID 2 is woken, both will hang.
    93    a.store(1);
    94    t.Join();
    95  
    96    int status = 0;
    97    EXPECT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), SyscallSucceeds());
    98    EXPECT_TRUE(WIFEXITED(status));
    99    EXPECT_EQ(WEXITSTATUS(status), 0);
   100  }
   101  
   102  // Test that multiple processes can execute concurrently, even if one process
   103  // never yields.
   104  TEST(ConcurrencyTest, MultiProcessConcurrency) {
   105    SKIP_IF(PlatformSupportMultiProcess() == PlatformSupport::NotSupported);
   106  
   107    pid_t child_pid = fork();
   108    if (child_pid == 0) {
   109      while (true) {
   110        int x = 0;
   111        benchmark::DoNotOptimize(x);  // Don't optimize this loop away.
   112      }
   113    }
   114    ASSERT_THAT(child_pid, SyscallSucceeds());
   115  
   116    absl::SleepFor(absl::Seconds(5));
   117  
   118    // We are still able to execute code in this process. The other hasn't
   119    // permanently hung execution in both processes.
   120    ASSERT_THAT(kill(child_pid, SIGKILL), SyscallSucceeds());
   121    int status = 0;
   122  
   123    ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), SyscallSucceeds());
   124    ASSERT_TRUE(WIFSIGNALED(status));
   125    ASSERT_EQ(WTERMSIG(status), SIGKILL);
   126  }
   127  
   128  }  // namespace
   129  }  // namespace testing
   130  }  // namespace gvisor