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

Side by Side Diff: base/process_util_posix.cc

Issue 3045018: Revert 53903 - Revert 52613 - Revert 52608 - Add and alternative GetAppOutput... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 5 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 | « base/process_util.h ('k') | base/process_util_unittest.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 (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 <dirent.h> 5 #include <dirent.h>
6 #include <errno.h> 6 #include <errno.h>
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <poll.h>
9 #include <signal.h> 8 #include <signal.h>
10 #include <stdlib.h> 9 #include <stdlib.h>
11 #include <sys/resource.h> 10 #include <sys/resource.h>
12 #include <sys/time.h> 11 #include <sys/time.h>
13 #include <sys/types.h> 12 #include <sys/types.h>
14 #include <sys/wait.h> 13 #include <sys/wait.h>
15 #include <unistd.h> 14 #include <unistd.h>
16 15
17 #include <limits> 16 #include <limits>
18 #include <set> 17 #include <set>
(...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 } 730 }
732 731
733 int64 TimeValToMicroseconds(const struct timeval& tv) { 732 int64 TimeValToMicroseconds(const struct timeval& tv) {
734 static const int kMicrosecondsPerSecond = 1000000; 733 static const int kMicrosecondsPerSecond = 1000000;
735 int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow. 734 int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow.
736 ret *= kMicrosecondsPerSecond; 735 ret *= kMicrosecondsPerSecond;
737 ret += tv.tv_usec; 736 ret += tv.tv_usec;
738 return ret; 737 return ret;
739 } 738 }
740 739
741 // Executes the application specified by |cl| and waits for it to exit, but 740 // Executes the application specified by |cl| and wait for it to exit. Stores
742 // at most |timeout_milliseconds| (use kNoTimeout for no timeout). Stores 741 // the output (stdout) in |output|. If |do_search_path| is set, it searches the
743 // the output (stdout) in |output|, and whether or not the timeout
744 // triggered in |timed_out|. If |do_search_path| is set, it searches the
745 // path for the application; in that case, |envp| must be null, and it will use 742 // path for the application; in that case, |envp| must be null, and it will use
746 // the current environment. If |do_search_path| is false, |cl| should fully 743 // the current environment. If |do_search_path| is false, |cl| should fully
747 // specify the path of the application, and |envp| will be used as the 744 // specify the path of the application, and |envp| will be used as the
748 // environment. Redirects stderr to /dev/null. Returns true on success 745 // environment. Redirects stderr to /dev/null. Returns true on success
749 // (application launched and exited cleanly, with exit code indicating success). 746 // (application launched and exited cleanly, with exit code indicating success).
750 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], 747 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[],
751 std::string* output, size_t max_output, 748 std::string* output, size_t max_output,
752 bool do_search_path, bool* timed_out, 749 bool do_search_path) {
753 int timeout_milliseconds) {
754 int pipe_fd[2]; 750 int pipe_fd[2];
755 pid_t pid; 751 pid_t pid;
756 InjectiveMultimap fd_shuffle1, fd_shuffle2; 752 InjectiveMultimap fd_shuffle1, fd_shuffle2;
757 const std::vector<std::string>& argv = cl.argv(); 753 const std::vector<std::string>& argv = cl.argv();
758 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); 754 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
759 755
760 fd_shuffle1.reserve(3); 756 fd_shuffle1.reserve(3);
761 fd_shuffle2.reserve(3); 757 fd_shuffle2.reserve(3);
762 758
763 // Either |do_search_path| should be false or |envp| should be null, but not 759 // Either |do_search_path| should be false or |envp| should be null, but not
(...skipping 21 matching lines...) Expand all
785 // call any previously-registered (in the parent) exit handlers, which 781 // call any previously-registered (in the parent) exit handlers, which
786 // might do things like block waiting for threads that don't even exist 782 // might do things like block waiting for threads that don't even exist
787 // in the child. 783 // in the child.
788 int dev_null = open("/dev/null", O_WRONLY); 784 int dev_null = open("/dev/null", O_WRONLY);
789 if (dev_null < 0) 785 if (dev_null < 0)
790 _exit(127); 786 _exit(127);
791 787
792 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); 788 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
793 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); 789 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
794 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); 790 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
795 // Adding another element here? Remember to increase the argument to 791 // Adding another element here? Remeber to increase the argument to
796 // reserve(), above. 792 // reserve(), above.
797 793
798 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), 794 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
799 std::back_inserter(fd_shuffle2)); 795 std::back_inserter(fd_shuffle2));
800 796
801 if (!ShuffleFileDescriptors(&fd_shuffle1)) 797 if (!ShuffleFileDescriptors(&fd_shuffle1))
802 _exit(127); 798 _exit(127);
803 799
804 CloseSuperfluousFds(fd_shuffle2); 800 CloseSuperfluousFds(fd_shuffle2);
805 801
(...skipping 12 matching lines...) Expand all
818 // be able to detect end of child's output (in theory we could still 814 // be able to detect end of child's output (in theory we could still
819 // write to the pipe). 815 // write to the pipe).
820 close(pipe_fd[1]); 816 close(pipe_fd[1]);
821 817
822 output->clear(); 818 output->clear();
823 char buffer[256]; 819 char buffer[256];
824 size_t output_buf_left = max_output; 820 size_t output_buf_left = max_output;
825 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| 821 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0|
826 // case in the logic below. 822 // case in the logic below.
827 823
828 *timed_out = false;
829 const Time timeout_time = Time::Now() +
830 TimeDelta::FromMilliseconds(timeout_milliseconds);
831 int remaining_ms = timeout_milliseconds;
832 while (output_buf_left > 0) { 824 while (output_buf_left > 0) {
833 struct pollfd poll_struct = { pipe_fd[0], POLLIN, 0 };
834 const int poll_ret_code = poll(&poll_struct, 1, remaining_ms);
835
836 // poll() should only fail due to interrupt.
837 DCHECK(poll_ret_code != -1 || errno == EINTR);
838 if (poll_ret_code == 0) {
839 *timed_out = true;
840 break;
841 }
842
843 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, 825 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer,
844 std::min(output_buf_left, sizeof(buffer)))); 826 std::min(output_buf_left, sizeof(buffer))));
845 if (bytes_read <= 0) 827 if (bytes_read <= 0)
846 break; 828 break;
847 output->append(buffer, bytes_read); 829 output->append(buffer, bytes_read);
848 output_buf_left -= static_cast<size_t>(bytes_read); 830 output_buf_left -= static_cast<size_t>(bytes_read);
849
850 // Update remaining_ms if we're not using an infinite timeout.
851 if (timeout_milliseconds >= 0) {
852 remaining_ms = (timeout_time - Time::Now()).InMilliseconds();
853 if (remaining_ms < 0) {
854 *timed_out = true;
855 break;
856 }
857 }
858 } 831 }
859 close(pipe_fd[0]); 832 close(pipe_fd[0]);
860 833
861 bool success = false; 834 // Always wait for exit code (even if we know we'll declare success).
862 int exit_code = PROCESS_END_PROCESS_WAS_HUNG; 835 int exit_code = EXIT_FAILURE;
863 if (*timed_out) { 836 bool success = WaitForExitCode(pid, &exit_code);
864 KillProcess(pid, exit_code, true);
865 // This waits up to 60 seconds for process to actually be dead
866 // which means this may overrun the timeout.
867 LOG(ERROR) << "Process "<< pid << " killed by timeout (waited "
868 << timeout_milliseconds << " ms).";
869 } else {
870 success = WaitForExitCode(pid, &exit_code);
871 }
872 837
873 // If we stopped because we read as much as we wanted, we always declare 838 // If we stopped because we read as much as we wanted, we always declare
874 // success (because the child may exit due to |SIGPIPE|). 839 // success (because the child may exit due to |SIGPIPE|).
875 if (output_buf_left || bytes_read <= 0) { 840 if (output_buf_left || bytes_read <= 0) {
876 if (!success || exit_code != EXIT_SUCCESS) 841 if (!success || exit_code != EXIT_SUCCESS)
877 return false; 842 return false;
878 } 843 }
879 844
880 return true; 845 return true;
881 } 846 }
882 } 847 }
883 } 848 }
884 849
885 bool GetAppOutput(const CommandLine& cl, std::string* output) { 850 bool GetAppOutput(const CommandLine& cl, std::string* output) {
886 // Run |execve()| with the current environment and store "unlimited" data. 851 // Run |execve()| with the current environment and store "unlimited" data.
887 bool timed_out;
888 return GetAppOutputInternal(cl, NULL, output, 852 return GetAppOutputInternal(cl, NULL, output,
889 std::numeric_limits<std::size_t>::max(), true, 853 std::numeric_limits<std::size_t>::max(), true);
890 &timed_out, base::kNoTimeout);
891 } 854 }
892 855
893 bool GetAppOutputWithTimeout(const CommandLine& cl, std::string* output, 856 // TODO(viettrungluu): Conceivably, we should have a timeout as well, so we
894 bool* timed_out, int timeout_milliseconds) { 857 // don't hang if what we're calling hangs.
895 return GetAppOutputInternal(cl, NULL, output,
896 std::numeric_limits<std::size_t>::max(), true,
897 timed_out, timeout_milliseconds);
898 }
899
900 bool GetAppOutputRestricted(const CommandLine& cl, 858 bool GetAppOutputRestricted(const CommandLine& cl,
901 std::string* output, size_t max_output) { 859 std::string* output, size_t max_output) {
902 // Run |execve()| with the empty environment. 860 // Run |execve()| with the empty environment.
903 char* const empty_environ = NULL; 861 char* const empty_environ = NULL;
904 bool timed_out; 862 return GetAppOutputInternal(cl, &empty_environ, output, max_output, false);
905 return GetAppOutputInternal(cl, &empty_environ, output, max_output, false,
906 &timed_out, base::kNoTimeout);
907 } 863 }
908 864
909 bool WaitForProcessesToExit(const std::wstring& executable_name, 865 bool WaitForProcessesToExit(const std::wstring& executable_name,
910 int64 wait_milliseconds, 866 int64 wait_milliseconds,
911 const ProcessFilter* filter) { 867 const ProcessFilter* filter) {
912 bool result = false; 868 bool result = false;
913 869
914 // TODO(port): This is inefficient, but works if there are multiple procs. 870 // TODO(port): This is inefficient, but works if there are multiple procs.
915 // TODO(port): use waitpid to avoid leaving zombies around 871 // TODO(port): use waitpid to avoid leaving zombies around
916 872
(...skipping 17 matching lines...) Expand all
934 const ProcessFilter* filter) { 890 const ProcessFilter* filter) {
935 bool exited_cleanly = 891 bool exited_cleanly =
936 WaitForProcessesToExit(executable_name, wait_milliseconds, 892 WaitForProcessesToExit(executable_name, wait_milliseconds,
937 filter); 893 filter);
938 if (!exited_cleanly) 894 if (!exited_cleanly)
939 KillProcesses(executable_name, exit_code, filter); 895 KillProcesses(executable_name, exit_code, filter);
940 return exited_cleanly; 896 return exited_cleanly;
941 } 897 }
942 898
943 } // namespace base 899 } // namespace base
OLDNEW
« no previous file with comments | « base/process_util.h ('k') | base/process_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698