Disallow breakaway from job for unit tests

BUG=328592, 371406
R=sky@chromium.org

Review URL: https://codereview.chromium.org/441333002

Cr-Commit-Position: refs/heads/master@{#288305}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288305 0039d316-1c4b-4281-b951-d872f2087c98
parent 10bec4f5
...@@ -48,7 +48,7 @@ namespace base { ...@@ -48,7 +48,7 @@ namespace base {
// Returns exit code of the process. // Returns exit code of the process.
int LaunchChildTestProcessWithOptions(const CommandLine& command_line, int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
const LaunchOptions& options, const LaunchOptions& options,
bool use_job_objects, int flags,
base::TimeDelta timeout, base::TimeDelta timeout,
bool* was_timeout); bool* was_timeout);
...@@ -223,7 +223,7 @@ void RunCallback( ...@@ -223,7 +223,7 @@ void RunCallback(
void DoLaunchChildTestProcess( void DoLaunchChildTestProcess(
const CommandLine& command_line, const CommandLine& command_line,
base::TimeDelta timeout, base::TimeDelta timeout,
bool use_job_objects, int flags,
bool redirect_stdio, bool redirect_stdio,
scoped_refptr<MessageLoopProxy> message_loop_proxy, scoped_refptr<MessageLoopProxy> message_loop_proxy,
const TestLauncher::LaunchChildGTestProcessCallback& callback) { const TestLauncher::LaunchChildGTestProcessCallback& callback) {
...@@ -275,7 +275,7 @@ void DoLaunchChildTestProcess( ...@@ -275,7 +275,7 @@ void DoLaunchChildTestProcess(
bool was_timeout = false; bool was_timeout = false;
int exit_code = LaunchChildTestProcessWithOptions( int exit_code = LaunchChildTestProcessWithOptions(
command_line, options, use_job_objects, timeout, &was_timeout); command_line, options, flags, timeout, &was_timeout);
if (redirect_stdio) { if (redirect_stdio) {
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -409,7 +409,7 @@ void TestLauncher::LaunchChildGTestProcess( ...@@ -409,7 +409,7 @@ void TestLauncher::LaunchChildGTestProcess(
const CommandLine& command_line, const CommandLine& command_line,
const std::string& wrapper, const std::string& wrapper,
base::TimeDelta timeout, base::TimeDelta timeout,
bool use_job_objects, int flags,
const LaunchChildGTestProcessCallback& callback) { const LaunchChildGTestProcessCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
...@@ -427,7 +427,7 @@ void TestLauncher::LaunchChildGTestProcess( ...@@ -427,7 +427,7 @@ void TestLauncher::LaunchChildGTestProcess(
Bind(&DoLaunchChildTestProcess, Bind(&DoLaunchChildTestProcess,
new_command_line, new_command_line,
timeout, timeout,
use_job_objects, flags,
redirect_stdio, redirect_stdio,
MessageLoopProxy::current(), MessageLoopProxy::current(),
Bind(&TestLauncher::OnLaunchTestProcessFinished, Bind(&TestLauncher::OnLaunchTestProcessFinished,
...@@ -1009,7 +1009,7 @@ CommandLine PrepareCommandLineForGTest(const CommandLine& command_line, ...@@ -1009,7 +1009,7 @@ CommandLine PrepareCommandLineForGTest(const CommandLine& command_line,
// TODO(phajdan.jr): Move to anonymous namespace. // TODO(phajdan.jr): Move to anonymous namespace.
int LaunchChildTestProcessWithOptions(const CommandLine& command_line, int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
const LaunchOptions& options, const LaunchOptions& options,
bool use_job_objects, int flags,
base::TimeDelta timeout, base::TimeDelta timeout,
bool* was_timeout) { bool* was_timeout) {
#if defined(OS_POSIX) #if defined(OS_POSIX)
...@@ -1023,19 +1023,22 @@ int LaunchChildTestProcessWithOptions(const CommandLine& command_line, ...@@ -1023,19 +1023,22 @@ int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
DCHECK(!new_options.job_handle); DCHECK(!new_options.job_handle);
win::ScopedHandle job_handle; win::ScopedHandle job_handle;
if (use_job_objects) { if (flags & TestLauncher::USE_JOB_OBJECTS) {
job_handle.Set(CreateJobObject(NULL, NULL)); job_handle.Set(CreateJobObject(NULL, NULL));
if (!job_handle.IsValid()) { if (!job_handle.IsValid()) {
LOG(ERROR) << "Could not create JobObject."; LOG(ERROR) << "Could not create JobObject.";
return -1; return -1;
} }
DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
// Allow break-away from job since sandbox and few other places rely on it // Allow break-away from job since sandbox and few other places rely on it
// on Windows versions prior to Windows 8 (which supports nested jobs). // on Windows versions prior to Windows 8 (which supports nested jobs).
// TODO(phajdan.jr): Do not allow break-away on Windows 8. // TODO(phajdan.jr): Do not allow break-away on Windows 8.
if (!SetJobObjectLimitFlags(job_handle.Get(), if (flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB)
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) {
LOG(ERROR) << "Could not SetJobObjectLimitFlags."; LOG(ERROR) << "Could not SetJobObjectLimitFlags.";
return -1; return -1;
} }
......
...@@ -69,6 +69,18 @@ class TestLauncherDelegate { ...@@ -69,6 +69,18 @@ class TestLauncherDelegate {
// Launches tests using a TestLauncherDelegate. // Launches tests using a TestLauncherDelegate.
class TestLauncher { class TestLauncher {
public: public:
// Flags controlling behavior of LaunchChildGTestProcess.
enum LaunchChildGTestProcessFlags {
// Allows usage of job objects on Windows. Helps properly clean up child
// processes.
USE_JOB_OBJECTS = (1 << 0),
// Allows breakaway from job on Windows. May result in some child processes
// not being properly terminated after launcher dies if these processes
// fail to cooperate.
ALLOW_BREAKAWAY_FROM_JOB = (1 << 1),
};
// Constructor. |parallel_jobs| is the limit of simultaneous parallel test // Constructor. |parallel_jobs| is the limit of simultaneous parallel test
// jobs. // jobs.
TestLauncher(TestLauncherDelegate* launcher_delegate, size_t parallel_jobs); TestLauncher(TestLauncherDelegate* launcher_delegate, size_t parallel_jobs);
...@@ -87,13 +99,12 @@ class TestLauncher { ...@@ -87,13 +99,12 @@ class TestLauncher {
// Launches a child process (assumed to be gtest-based binary) using // Launches a child process (assumed to be gtest-based binary) using
// |command_line|. If |wrapper| is not empty, it is prepended to the final // |command_line|. If |wrapper| is not empty, it is prepended to the final
// command line. If the child process is still running after |timeout|, it // command line. If the child process is still running after |timeout|, it
// is terminated. |use_job_objects| determines whether job objects are used // is terminated. After the child process finishes |callback| is called
// on Windows (if unsure pass true). After the child process finishes // on the same thread this method was called.
// |callback| is called on the same thread this method was called.
void LaunchChildGTestProcess(const CommandLine& command_line, void LaunchChildGTestProcess(const CommandLine& command_line,
const std::string& wrapper, const std::string& wrapper,
base::TimeDelta timeout, base::TimeDelta timeout,
bool use_job_objects, int flags,
const LaunchChildGTestProcessCallback& callback); const LaunchChildGTestProcessCallback& callback);
// Called when a test has finished running. // Called when a test has finished running.
......
...@@ -187,7 +187,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { ...@@ -187,7 +187,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate {
cmd_line, cmd_line,
std::string(), std::string(),
TestTimeouts::test_launcher_timeout(), TestTimeouts::test_launcher_timeout(),
use_job_objects_, use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0,
Bind(&UnitTestLauncherDelegate::SerialGTestCallback, Bind(&UnitTestLauncherDelegate::SerialGTestCallback,
Unretained(this), Unretained(this),
callback_state, callback_state,
...@@ -229,7 +229,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { ...@@ -229,7 +229,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate {
cmd_line, cmd_line,
std::string(), std::string(),
timeout, timeout,
use_job_objects_, use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0,
Bind(&UnitTestLauncherDelegate::GTestCallback, Bind(&UnitTestLauncherDelegate::GTestCallback,
Unretained(this), Unretained(this),
callback_state)); callback_state));
......
...@@ -345,7 +345,8 @@ void WrapperTestLauncherDelegate::DoRunTest(base::TestLauncher* test_launcher, ...@@ -345,7 +345,8 @@ void WrapperTestLauncherDelegate::DoRunTest(base::TestLauncher* test_launcher,
new_cmd_line, new_cmd_line,
browser_wrapper ? browser_wrapper : std::string(), browser_wrapper ? browser_wrapper : std::string(),
TestTimeouts::action_max_timeout(), TestTimeouts::action_max_timeout(),
true, base::TestLauncher::USE_JOB_OBJECTS |
base::TestLauncher::ALLOW_BREAKAWAY_FROM_JOB,
base::Bind(&WrapperTestLauncherDelegate::GTestCallback, base::Bind(&WrapperTestLauncherDelegate::GTestCallback,
base::Unretained(this), base::Unretained(this),
test_launcher, test_launcher,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment