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

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: trybots 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;
sky 2013/09/10 16:17:27 These aren't globals. My take of the style guide i
Paweł Hajdan Jr. 2013/09/10 17:17:08 I'm fine to make changes but would like to underst
sky 2013/09/10 19:14:46 My reasoning is that it's not a global. g_browser_
Paweł Hajdan Jr. 2013/09/10 19:56:45 Current version of the code is consistent with usa
55 LazyInstance<Lock> g_live_process_handles_lock;
56
57 #if defined(OS_POSIX)
58 // Self-pipe that makes it possible to do complex shutdown handling
59 // outside of the signal handler.
60 int g_shutdown_pipe[2] = { -1, -1 };
61
62 void ShutdownPipeSignalHandler(int signal) {
63 HANDLE_EINTR(write(g_shutdown_pipe[1], "q", 1));
64 }
65
66 // I/O watcher for the reading end of the self-pipe above.
67 // Terminates any launched child processes and exits the process.
68 class SignalFDWatcher : public MessageLoopForIO::Watcher {
69 public:
70 SignalFDWatcher() {
71 }
72
73 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
74 fprintf(stdout, "\nCaught signal. Killing spawned test processes...\n");
75 fflush(stdout);
76
77 // Keep the lock until exiting the process to prevent further processes
78 // from being spawned.
79 AutoLock lock(g_live_process_handles_lock.Get());
80
81 fprintf(stdout,
82 "Sending SIGTERM to %" PRIuS " child processes... ",
83 g_live_process_handles.Get().size());
84 fflush(stdout);
85
86 for (std::set<ProcessHandle>::iterator i =
87 g_live_process_handles.Get().begin();
88 i != g_live_process_handles.Get().end();
89 ++i) {
90 kill((-1) * (*i), SIGTERM); // Send the signal to entire process group.
91 }
92
93 fprintf(stdout,
94 "done.\nGiving processes a chance to terminate cleanly... ");
95 fflush(stdout);
96
97 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
98
99 fprintf(stdout, "done.\n");
100 fflush(stdout);
101
102 fprintf(stdout,
103 "Sending SIGKILL to %" PRIuS " child processes... ",
104 g_live_process_handles.Get().size());
105 fflush(stdout);
106
107 for (std::set<ProcessHandle>::iterator i =
108 g_live_process_handles.Get().begin();
109 i != g_live_process_handles.Get().end();
110 ++i) {
111 kill((-1) * (*i), SIGKILL); // Send the signal to entire process group.
112 }
113
114 fprintf(stdout, "done.\n");
115 fflush(stdout);
116
117 // The signal would normally kill the process, so exit now.
118 exit(1);
119 }
120
121 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
122 NOTREACHED();
123 }
124
125 private:
126 DISALLOW_COPY_AND_ASSIGN(SignalFDWatcher);
127 };
128 #endif // defined(OS_POSIX)
129
47 // Parses the environment variable var as an Int32. If it is unset, returns 130 // 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 131 // 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 132 // returning it. If unsetting or converting to an Int32 fails, print an
50 // error and exit with failure. 133 // error and exit with failure.
51 int32 Int32FromEnvOrDie(const char* const var, int32 default_val) { 134 int32 Int32FromEnvOrDie(const char* const var, int32 default_val) {
52 scoped_ptr<Environment> env(Environment::Create()); 135 scoped_ptr<Environment> env(Environment::Create());
53 std::string str_val; 136 std::string str_val;
54 int32 result; 137 int32 result;
55 if (!env->GetVar(var, &str_val)) 138 if (!env->GetVar(var, &str_val))
56 return default_val; 139 return default_val;
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, 617 int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
535 const LaunchOptions& options, 618 const LaunchOptions& options,
536 base::TimeDelta timeout, 619 base::TimeDelta timeout,
537 bool* was_timeout) { 620 bool* was_timeout) {
538 #if defined(OS_POSIX) 621 #if defined(OS_POSIX)
539 // Make sure an option we rely on is present - see LaunchChildGTestProcess. 622 // Make sure an option we rely on is present - see LaunchChildGTestProcess.
540 DCHECK(options.new_process_group); 623 DCHECK(options.new_process_group);
541 #endif 624 #endif
542 625
543 base::ProcessHandle process_handle; 626 base::ProcessHandle process_handle;
544 if (!base::LaunchProcess(command_line, options, &process_handle)) 627
545 return -1; 628 {
629 // Note how we grab the lock before the process possibly gets created.
630 // This ensures that when the lock is held, ALL the processes are registered
631 // in the set.
632 AutoLock lock(g_live_process_handles_lock.Get());
633
634 if (!base::LaunchProcess(command_line, options, &process_handle))
635 return -1;
636
637 g_live_process_handles.Get().insert(process_handle);
638 }
546 639
547 int exit_code = 0; 640 int exit_code = 0;
548 if (!base::WaitForExitCodeWithTimeout(process_handle, 641 if (!base::WaitForExitCodeWithTimeout(process_handle,
549 &exit_code, 642 &exit_code,
550 timeout)) { 643 timeout)) {
551 *was_timeout = true; 644 *was_timeout = true;
552 exit_code = -1; // Set a non-zero exit code to signal a failure. 645 exit_code = -1; // Set a non-zero exit code to signal a failure.
553 646
554 // Ensure that the process terminates. 647 // Ensure that the process terminates.
555 base::KillProcess(process_handle, -1, true); 648 base::KillProcess(process_handle, -1, true);
556 } 649 }
557 650
651 {
652 // Note how we grab the log before issuing a possibly broad process kill.
653 // Other code parts that grab the log kill processes, so avoid trying
654 // to do that twice and trigger all kinds of log messages.
655 AutoLock lock(g_live_process_handles_lock.Get());
656
558 #if defined(OS_POSIX) 657 #if defined(OS_POSIX)
559 if (exit_code != 0) { 658 if (exit_code != 0) {
sky 2013/09/10 16:17:27 How come you have this inside the lock? Doesn't se
Paweł Hajdan Jr. 2013/09/10 17:17:08 This is tricky, and suggestions how to improve the
sky 2013/09/10 19:14:46 Under what circumstances might you try to kill the
Paweł Hajdan Jr. 2013/09/10 19:56:45 Worker thread executing this code at the same time
560 // On POSIX, in case the test does not exit cleanly, either due to a crash 659 // 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 660 // 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 661 // it might have created. On Windows, child processes are automatically
563 // cleaned up using JobObjects. 662 // cleaned up using JobObjects.
564 base::KillProcessGroup(process_handle); 663 base::KillProcessGroup(process_handle);
664 }
665 #endif
666
667 g_live_process_handles.Get().erase(process_handle);
565 } 668 }
566 #endif
567 669
568 base::CloseProcessHandle(process_handle); 670 base::CloseProcessHandle(process_handle);
569 671
570 return exit_code; 672 return exit_code;
571 } 673 }
572 674
573 int LaunchTests(TestLauncherDelegate* launcher_delegate, 675 int LaunchTests(TestLauncherDelegate* launcher_delegate,
574 int argc, 676 int argc,
575 char** argv) { 677 char** argv) {
576 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 678 const CommandLine* command_line = CommandLine::ForCurrentProcess();
577 679
578 680
579 int32 total_shards; 681 int32 total_shards;
580 int32 shard_index; 682 int32 shard_index;
581 InitSharding(&total_shards, &shard_index); 683 InitSharding(&total_shards, &shard_index);
582 684
583 int cycles = 1; 685 int cycles = 1;
584 if (command_line->HasSwitch(kGTestRepeatFlag)) 686 if (command_line->HasSwitch(kGTestRepeatFlag))
585 StringToInt(command_line->GetSwitchValueASCII(kGTestRepeatFlag), &cycles); 687 StringToInt(command_line->GetSwitchValueASCII(kGTestRepeatFlag), &cycles);
586 688
587 int exit_code = 0; 689 int exit_code = 0;
588 690
691 #if defined(OS_POSIX)
692 CHECK_EQ(0, pipe(g_shutdown_pipe));
693
694 struct sigaction action;
695 memset(&action, 0, sizeof(action));
696 sigemptyset(&action.sa_mask);
697 action.sa_handler = &ShutdownPipeSignalHandler;
698
699 CHECK_EQ(0, sigaction(SIGINT, &action, NULL));
700 CHECK_EQ(0, sigaction(SIGQUIT, &action, NULL));
701 CHECK_EQ(0, sigaction(SIGTERM, &action, NULL));
702
703 MessageLoopForIO::FileDescriptorWatcher controller;
704 SignalFDWatcher watcher;
705
706 CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
707 g_shutdown_pipe[0],
708 true,
709 MessageLoopForIO::WATCH_READ,
710 &controller,
711 &watcher));
712 #endif // defined(OS_POSIX)
713
589 MessageLoop::current()->PostTask( 714 MessageLoop::current()->PostTask(
590 FROM_HERE, 715 FROM_HERE,
591 Bind(&RunTestIteration, 716 Bind(&RunTestIteration,
592 launcher_delegate, 717 launcher_delegate,
593 total_shards, 718 total_shards,
594 shard_index, 719 shard_index,
595 cycles, 720 cycles,
596 &exit_code, 721 &exit_code,
597 true)); 722 true));
598 723
599 MessageLoop::current()->Run(); 724 MessageLoop::current()->Run();
600 725
601 return exit_code; 726 return exit_code;
602 } 727 }
603 728
604 } // namespace base 729 } // 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