Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Side by Side Diff: base/test/test_launcher.cc

Issue 23484026: GTTF: kill spawned test processes when the launcher is killed (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: LAZY_INSTANCE_INITIALIZER Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | base/test/unit_test_launcher.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/test/test_launcher.h" 5 #include "base/test/test_launcher.h"
6 6
7 #if defined(OS_POSIX)
8 #include <fcntl.h>
9 #endif
10
7 #include "base/at_exit.h" 11 #include "base/at_exit.h"
8 #include "base/bind.h" 12 #include "base/bind.h"
9 #include "base/command_line.h" 13 #include "base/command_line.h"
10 #include "base/environment.h" 14 #include "base/environment.h"
11 #include "base/file_util.h" 15 #include "base/file_util.h"
12 #include "base/files/file_path.h" 16 #include "base/files/file_path.h"
13 #include "base/format_macros.h" 17 #include "base/format_macros.h"
18 #include "base/lazy_instance.h"
14 #include "base/logging.h" 19 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h" 21 #include "base/message_loop/message_loop.h"
17 #include "base/process/kill.h" 22 #include "base/process/kill.h"
18 #include "base/process/launch.h" 23 #include "base/process/launch.h"
19 #include "base/strings/string_number_conversions.h" 24 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/stringprintf.h" 25 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h" 26 #include "base/strings/utf_string_conversions.h"
22 #include "base/test/test_timeouts.h" 27 #include "base/test/test_timeouts.h"
23 #include "base/threading/thread_checker.h" 28 #include "base/threading/thread_checker.h"
(...skipping 13 matching lines...) Expand all
37 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; 42 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
38 // The environment variable name for the test shard index. 43 // The environment variable name for the test shard index.
39 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; 44 const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
40 45
41 // The default output file for XML output. 46 // The default output file for XML output.
42 const FilePath::CharType kDefaultOutputFile[] = FILE_PATH_LITERAL( 47 const FilePath::CharType kDefaultOutputFile[] = FILE_PATH_LITERAL(
43 "test_detail.xml"); 48 "test_detail.xml");
44 49
45 namespace { 50 namespace {
46 51
52 // Set of live launch test processes with corresponding lock (it is allowed
53 // for callers to launch processes on different threads).
54 LazyInstance<std::set<ProcessHandle> > g_live_process_handles
55 = LAZY_INSTANCE_INITIALIZER;
56 LazyInstance<Lock> g_live_process_handles_lock = LAZY_INSTANCE_INITIALIZER;
57
58 #if defined(OS_POSIX)
59 // Self-pipe that makes it possible to do complex shutdown handling
60 // outside of the signal handler.
61 int g_shutdown_pipe[2] = { -1, -1 };
62
63 void ShutdownPipeSignalHandler(int signal) {
64 HANDLE_EINTR(write(g_shutdown_pipe[1], "q", 1));
65 }
66
67 // I/O watcher for the reading end of the self-pipe above.
68 // Terminates any launched child processes and exits the process.
69 class SignalFDWatcher : public MessageLoopForIO::Watcher {
70 public:
71 SignalFDWatcher() {
72 }
73
74 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
75 fprintf(stdout, "\nCaught signal. Killing spawned test processes...\n");
76 fflush(stdout);
77
78 // Keep the lock until exiting the process to prevent further processes
79 // from being spawned.
80 AutoLock lock(g_live_process_handles_lock.Get());
81
82 fprintf(stdout,
83 "Sending SIGTERM to %" PRIuS " child processes... ",
84 g_live_process_handles.Get().size());
85 fflush(stdout);
86
87 for (std::set<ProcessHandle>::iterator i =
88 g_live_process_handles.Get().begin();
89 i != g_live_process_handles.Get().end();
90 ++i) {
91 kill((-1) * (*i), SIGTERM); // Send the signal to entire process group.
92 }
93
94 fprintf(stdout,
95 "done.\nGiving processes a chance to terminate cleanly... ");
96 fflush(stdout);
97
98 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
99
100 fprintf(stdout, "done.\n");
101 fflush(stdout);
102
103 fprintf(stdout,
104 "Sending SIGKILL to %" PRIuS " child processes... ",
105 g_live_process_handles.Get().size());
106 fflush(stdout);
107
108 for (std::set<ProcessHandle>::iterator i =
109 g_live_process_handles.Get().begin();
110 i != g_live_process_handles.Get().end();
111 ++i) {
112 kill((-1) * (*i), SIGKILL); // Send the signal to entire process group.
113 }
114
115 fprintf(stdout, "done.\n");
116 fflush(stdout);
117
118 // The signal would normally kill the process, so exit now.
119 exit(1);
120 }
121
122 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
123 NOTREACHED();
124 }
125
126 private:
127 DISALLOW_COPY_AND_ASSIGN(SignalFDWatcher);
128 };
129 #endif // defined(OS_POSIX)
130
47 // Parses the environment variable var as an Int32. If it is unset, returns 131 // Parses the environment variable var as an Int32. If it is unset, returns
48 // default_val. If it is set, unsets it then converts it to Int32 before 132 // default_val. If it is set, unsets it then converts it to Int32 before
49 // returning it. If unsetting or converting to an Int32 fails, print an 133 // returning it. If unsetting or converting to an Int32 fails, print an
50 // error and exit with failure. 134 // error and exit with failure.
51 int32 Int32FromEnvOrDie(const char* const var, int32 default_val) { 135 int32 Int32FromEnvOrDie(const char* const var, int32 default_val) {
52 scoped_ptr<Environment> env(Environment::Create()); 136 scoped_ptr<Environment> env(Environment::Create());
53 std::string str_val; 137 std::string str_val;
54 int32 result; 138 int32 result;
55 if (!env->GetVar(var, &str_val)) 139 if (!env->GetVar(var, &str_val))
56 return default_val; 140 return default_val;
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, 618 int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
535 const LaunchOptions& options, 619 const LaunchOptions& options,
536 base::TimeDelta timeout, 620 base::TimeDelta timeout,
537 bool* was_timeout) { 621 bool* was_timeout) {
538 #if defined(OS_POSIX) 622 #if defined(OS_POSIX)
539 // Make sure an option we rely on is present - see LaunchChildGTestProcess. 623 // Make sure an option we rely on is present - see LaunchChildGTestProcess.
540 DCHECK(options.new_process_group); 624 DCHECK(options.new_process_group);
541 #endif 625 #endif
542 626
543 base::ProcessHandle process_handle; 627 base::ProcessHandle process_handle;
544 if (!base::LaunchProcess(command_line, options, &process_handle)) 628
545 return -1; 629 {
630 // Note how we grab the lock before the process possibly gets created.
631 // This ensures that when the lock is held, ALL the processes are registered
632 // in the set.
633 AutoLock lock(g_live_process_handles_lock.Get());
634
635 if (!base::LaunchProcess(command_line, options, &process_handle))
636 return -1;
637
638 g_live_process_handles.Get().insert(process_handle);
639 }
546 640
547 int exit_code = 0; 641 int exit_code = 0;
548 if (!base::WaitForExitCodeWithTimeout(process_handle, 642 if (!base::WaitForExitCodeWithTimeout(process_handle,
549 &exit_code, 643 &exit_code,
550 timeout)) { 644 timeout)) {
551 *was_timeout = true; 645 *was_timeout = true;
552 exit_code = -1; // Set a non-zero exit code to signal a failure. 646 exit_code = -1; // Set a non-zero exit code to signal a failure.
553 647
554 // Ensure that the process terminates. 648 // Ensure that the process terminates.
555 base::KillProcess(process_handle, -1, true); 649 base::KillProcess(process_handle, -1, true);
556 } 650 }
557 651
652 {
653 // Note how we grab the log before issuing a possibly broad process kill.
654 // Other code parts that grab the log kill processes, so avoid trying
655 // to do that twice and trigger all kinds of log messages.
656 AutoLock lock(g_live_process_handles_lock.Get());
657
558 #if defined(OS_POSIX) 658 #if defined(OS_POSIX)
559 if (exit_code != 0) { 659 if (exit_code != 0) {
560 // On POSIX, in case the test does not exit cleanly, either due to a crash 660 // On POSIX, in case the test does not exit cleanly, either due to a crash
561 // or due to it timing out, we need to clean up any child processes that 661 // or due to it timing out, we need to clean up any child processes that
562 // it might have created. On Windows, child processes are automatically 662 // it might have created. On Windows, child processes are automatically
563 // cleaned up using JobObjects. 663 // cleaned up using JobObjects.
564 base::KillProcessGroup(process_handle); 664 base::KillProcessGroup(process_handle);
665 }
666 #endif
667
668 g_live_process_handles.Get().erase(process_handle);
565 } 669 }
566 #endif
567 670
568 base::CloseProcessHandle(process_handle); 671 base::CloseProcessHandle(process_handle);
569 672
570 return exit_code; 673 return exit_code;
571 } 674 }
572 675
573 int LaunchTests(TestLauncherDelegate* launcher_delegate, 676 int LaunchTests(TestLauncherDelegate* launcher_delegate,
574 int argc, 677 int argc,
575 char** argv) { 678 char** argv) {
576 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 679 const CommandLine* command_line = CommandLine::ForCurrentProcess();
577 680
578 681
579 int32 total_shards; 682 int32 total_shards;
580 int32 shard_index; 683 int32 shard_index;
581 InitSharding(&total_shards, &shard_index); 684 InitSharding(&total_shards, &shard_index);
582 685
583 int cycles = 1; 686 int cycles = 1;
584 if (command_line->HasSwitch(kGTestRepeatFlag)) 687 if (command_line->HasSwitch(kGTestRepeatFlag))
585 StringToInt(command_line->GetSwitchValueASCII(kGTestRepeatFlag), &cycles); 688 StringToInt(command_line->GetSwitchValueASCII(kGTestRepeatFlag), &cycles);
586 689
587 int exit_code = 0; 690 int exit_code = 0;
588 691
692 #if defined(OS_POSIX)
693 CHECK_EQ(0, pipe(g_shutdown_pipe));
694
695 struct sigaction action;
696 memset(&action, 0, sizeof(action));
697 sigemptyset(&action.sa_mask);
698 action.sa_handler = &ShutdownPipeSignalHandler;
699
700 CHECK_EQ(0, sigaction(SIGINT, &action, NULL));
701 CHECK_EQ(0, sigaction(SIGQUIT, &action, NULL));
702 CHECK_EQ(0, sigaction(SIGTERM, &action, NULL));
703
704 MessageLoopForIO::FileDescriptorWatcher controller;
705 SignalFDWatcher watcher;
706
707 CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
708 g_shutdown_pipe[0],
709 true,
710 MessageLoopForIO::WATCH_READ,
711 &controller,
712 &watcher));
713 #endif // defined(OS_POSIX)
714
589 MessageLoop::current()->PostTask( 715 MessageLoop::current()->PostTask(
590 FROM_HERE, 716 FROM_HERE,
591 Bind(&RunTestIteration, 717 Bind(&RunTestIteration,
592 launcher_delegate, 718 launcher_delegate,
593 total_shards, 719 total_shards,
594 shard_index, 720 shard_index,
595 cycles, 721 cycles,
596 &exit_code, 722 &exit_code,
597 true)); 723 true));
598 724
599 MessageLoop::current()->Run(); 725 MessageLoop::current()->Run();
600 726
601 return exit_code; 727 return exit_code;
602 } 728 }
603 729
604 } // namespace base 730 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | base/test/unit_test_launcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698