summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvladlosev <vladlosev@861a406c-534a-0410-8894-cb66d6ee9925>2011-06-20 21:43:18 +0000
committervladlosev <vladlosev@861a406c-534a-0410-8894-cb66d6ee9925>2011-06-20 21:43:18 +0000
commit105b1431c37c159892cc0983dd0bc2411c6f0c96 (patch)
tree3751feb2e92b653ef02a00d1fa2c6b5d907d0723
parent4f9248a4270559cf286cb12937ba78b58bde053f (diff)
downloadgoogletest-105b1431c37c159892cc0983dd0bc2411c6f0c96.tar.gz
QNX compatibility patch (by Haruka Iwao).
git-svn-id: http://googletest.googlecode.com/svn/trunk@586 861a406c-534a-0410-8894-cb66d6ee9925
-rw-r--r--include/gtest/internal/gtest-port.h13
-rw-r--r--src/gtest-death-test.cc60
-rw-r--r--src/gtest-port.cc25
-rw-r--r--test/gtest-port_test.cc9
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 <vector> // 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 <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 b860d48..3206914 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 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<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;