diff options
| -rw-r--r-- | include/gtest/internal/gtest-port.h | 13 | ||||
| -rw-r--r-- | src/gtest-death-test.cc | 60 | ||||
| -rw-r--r-- | src/gtest-port.cc | 25 | ||||
| -rw-r--r-- | 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 94efca30..891ac8af 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 <vector>  // NOLINT  #endif diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 44ff6b2f..fb4a9f9d 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -52,6 +52,10 @@  #  include <sys/wait.h>  # endif  // GTEST_OS_WINDOWS +# if GTEST_OS_QNX +#  include <spawn.h> +# 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 b860d481..32069146 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -51,6 +51,11 @@  # include <mach/vm_map.h>  #endif  // GTEST_OS_MAC +#if GTEST_OS_QNX +# include <devctl.h> +# include <sys/procfs.h> +#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<size_t>(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 1c6e2b09..c83e005f 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<pthread_mutex_t*>(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;  | 
