// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sandbox/linux/services/thread_helpers.h" #include <errno.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/posix/eintr_wrapper.h" #include "base/process/process_metrics.h" #include "base/threading/platform_thread.h" #include "base/threading/thread.h" #include "build/build_config.h" #include "sandbox/linux/tests/unit_tests.h" #include "testing/gtest/include/gtest/gtest.h" using base::PlatformThread; namespace sandbox { namespace { int GetRaceTestIterations() { if (IsRunningOnValgrind()) { return 2; } else { return 1000; } } class ScopedProcSelfTask { public: ScopedProcSelfTask() : fd_(-1) { fd_ = open("/proc/self/task/", O_RDONLY | O_DIRECTORY); CHECK_LE(0, fd_); } ~ScopedProcSelfTask() { PCHECK(0 == IGNORE_EINTR(close(fd_))); } int fd() { return fd_; } private: int fd_; DISALLOW_COPY_AND_ASSIGN(ScopedProcSelfTask); }; #if defined(THREAD_SANITIZER) // These tests fail under ThreadSanitizer, see http://crbug.com/342305 #define MAYBE_IsSingleThreadedBasic DISABLED_IsSingleThreadedBasic #define MAYBE_IsSingleThreadedIterated DISABLED_IsSingleThreadedIterated #define MAYBE_IsSingleThreadedStartAndStop DISABLED_IsSingleThreadedStartAndStop #else #define MAYBE_IsSingleThreadedBasic IsSingleThreadedBasic #define MAYBE_IsSingleThreadedIterated IsSingleThreadedIterated #define MAYBE_IsSingleThreadedStartAndStop IsSingleThreadedStartAndStop #endif TEST(ThreadHelpers, MAYBE_IsSingleThreadedBasic) { ScopedProcSelfTask task; ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(task.fd())); ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(-1)); base::Thread thread("sandbox_tests"); ASSERT_TRUE(thread.Start()); ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(task.fd())); ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(-1)); // Explicitly stop the thread here to not pollute the next test. ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(task.fd(), &thread)); } TEST(ThreadHelpers, MAYBE_IsSingleThreadedIterated) { ScopedProcSelfTask task; ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(task.fd())); // Iterate to check for race conditions. for (int i = 0; i < GetRaceTestIterations(); ++i) { base::Thread thread("sandbox_tests"); ASSERT_TRUE(thread.Start()); ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(task.fd())); // Explicitly stop the thread here to not pollute the next test. ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(task.fd(), &thread)); } } TEST(ThreadHelpers, MAYBE_IsSingleThreadedStartAndStop) { ScopedProcSelfTask task; ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(task.fd())); base::Thread thread("sandbox_tests"); // This is testing for a race condition, so iterate. // Manually, this has been tested with more that 1M iterations. for (int i = 0; i < GetRaceTestIterations(); ++i) { ASSERT_TRUE(thread.Start()); ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(task.fd())); ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(task.fd(), &thread)); ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(task.fd())); ASSERT_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle())); } } } // namespace } // namespace sandbox