From 105b1431c37c159892cc0983dd0bc2411c6f0c96 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 20 Jun 2011 21:43:18 +0000 Subject: QNX compatibility patch (by Haruka Iwao). git-svn-id: http://googletest.googlecode.com/svn/trunk@586 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/internal/gtest-port.h | 13 +++++--- src/gtest-death-test.cc | 60 ++++++++++++++++++++++++++++++++----- src/gtest-port.cc | 25 ++++++++++++++++ test/gtest-port_test.cc | 9 ++++-- 4 files changed, 93 insertions(+), 14 deletions(-) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 94efca3..891ac8a 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -92,6 +92,7 @@ // GTEST_OS_MAC - Mac OS X // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) @@ -245,6 +246,8 @@ # define GTEST_OS_NACL 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 #endif // __CYGWIN__ // Brings in definitions for functions used in the testing::internal::posix @@ -420,7 +423,8 @@ // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX) +# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ + || GTEST_OS_QNX) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -452,8 +456,9 @@ // defining __GNUC__ and friends, but cannot compile GCC's tuple // implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB // Feature Pack download, which we cannot assume the user has. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ - || _MSC_VER >= 1600 +// QNX's QCC compiler is a modified GCC but it doesn't support TR1 tuple. +# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ + && !GTEST_OS_QNX) || _MSC_VER >= 1600 # define GTEST_USE_OWN_TR1_TUPLE 0 # else # define GTEST_USE_OWN_TR1_TUPLE 1 @@ -544,7 +549,7 @@ #if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD) + GTEST_OS_OPENBSD || GTEST_OS_QNX) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT #endif diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 44ff6b2..fb4a9f9 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -52,6 +52,10 @@ # include # endif // GTEST_OS_WINDOWS +# if GTEST_OS_QNX +# include +# endif // GTEST_OS_QNX + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" @@ -894,6 +898,7 @@ extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC +# if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. @@ -926,6 +931,7 @@ static int ExecDeathTestChildMain(void* child_arg) { GetLastErrnoDescription().c_str())); return EXIT_FAILURE; } +# endif // !GTEST_OS_QNX // Two utility routines that together determine the direction the stack // grows. @@ -949,14 +955,51 @@ bool StackGrowsDown() { return result; } -// A threadsafe implementation of fork(2) for threadsafe-style death tests -// that uses clone(2). It dies with an error message if anything goes -// wrong. -static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { +// Spawns a child process with the same executable as the current process in +// a thread-safe manner and instructs it to run the death test. The +// implementation uses fork(2) + exec. On systems where clone(2) is +// available, it is used instead, being slightly more thread-safe. On QNX, +// fork supports only single-threaded environments, so this function uses +// spawn(2) there instead. The function dies with an error message if +// anything goes wrong. +static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; -# if GTEST_HAS_CLONE +# if GTEST_OS_QNX + // Obtains the current directory and sets it to be closed in the child + // process. + const int cwd_fd = open(".", O_RDONLY); + GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + int fd_flags; + // Set close_fd to be closed after spawn. + GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, + fd_flags | FD_CLOEXEC)); + struct inheritance inherit = {0}; + // spawn is a system call. + child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + // Restores the current working directory. + GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); + +# else // GTEST_OS_QNX + +# if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { @@ -973,14 +1016,15 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } -# else +# else const bool use_fork = true; -# endif // GTEST_HAS_CLONE +# endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } +# endif // GTEST_OS_QNX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; @@ -1028,7 +1072,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // is necessary. FlushInfoLog(); - const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b860d48..3206914 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -51,6 +51,11 @@ # include #endif // GTEST_OS_MAC +#if GTEST_OS_QNX +# include +# include +#endif // GTEST_OS_QNX + #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" @@ -98,6 +103,26 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_QNX + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const int fd = open("/proc/self/as", O_RDONLY); + if (fd < 0) { + return 0; + } + procfs_info process_info; + const int status = + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + close(fd); + if (status == EOK) { + return static_cast(process_info.num_threads); + } else { + return 0; + } +} + #else size_t GetThreadCount() { diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 1c6e2b0..c83e005 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -267,7 +267,7 @@ TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1)); } -#if GTEST_OS_MAC +#if GTEST_OS_MAC || GTEST_OS_QNX void* ThreadFunc(void* data) { pthread_mutex_t* mutex = static_cast(data); pthread_mutex_lock(mutex); @@ -297,6 +297,8 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) { void* dummy; ASSERT_EQ(0, pthread_join(thread_id, &dummy)); +# if GTEST_OS_MAC + // MacOS X may not immediately report the updated thread count after // joining a thread, causing flakiness in this test. To counter that, we // wait for up to .5 seconds for the OS to report the correct value. @@ -306,6 +308,9 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) { SleepMilliseconds(100); } + +# endif // GTEST_OS_MAC + EXPECT_EQ(1U, GetThreadCount()); pthread_mutex_destroy(&mutex); } @@ -313,7 +318,7 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) { TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { EXPECT_EQ(0U, GetThreadCount()); } -#endif // GTEST_OS_MAC +#endif // GTEST_OS_MAC || GTEST_OS_QNX TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; -- cgit v1.2.1