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