LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - process_util_linux.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 131 2 1.5 %
Date: 2012-06-02 Functions: 12 2 16.7 %

       1                 : // Copyright (c) 2008 The Chromium Authors. All rights reserved.
       2                 : // Use of this source code is governed by a BSD-style license that can be
       3                 : // found in the LICENSE file.
       4                 : 
       5                 : #include "base/process_util.h"
       6                 : 
       7                 : #include <ctype.h>
       8                 : #include <dirent.h>
       9                 : #include <fcntl.h>
      10                 : #include <unistd.h>
      11                 : #include <string>
      12                 : #include <sys/types.h>
      13                 : #include <sys/wait.h>
      14                 : 
      15                 : #include "base/debug_util.h"
      16                 : #include "base/eintr_wrapper.h"
      17                 : #include "base/file_util.h"
      18                 : #include "base/logging.h"
      19                 : #include "base/string_tokenizer.h"
      20                 : #include "base/string_util.h"
      21                 : 
      22                 : #ifdef MOZ_MEMORY_ANDROID
      23                 : #include "jemalloc.h"
      24                 : #endif
      25                 : 
      26                 : namespace {
      27                 : 
      28                 : enum ParsingState {
      29                 :   KEY_NAME,
      30                 :   KEY_VALUE
      31                 : };
      32                 : 
      33            1464 : static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
      34                 : 
      35                 : }  // namespace
      36                 : 
      37                 : namespace base {
      38                 : 
      39               0 : bool LaunchApp(const std::vector<std::string>& argv,
      40                 :                const file_handle_mapping_vector& fds_to_remap,
      41                 :                bool wait, ProcessHandle* process_handle) {
      42               0 :   return LaunchApp(argv, fds_to_remap, environment_map(),
      43               0 :                    wait, process_handle);
      44                 : }
      45                 : 
      46               0 : bool LaunchApp(const std::vector<std::string>& argv,
      47                 :                const file_handle_mapping_vector& fds_to_remap,
      48                 :                const environment_map& env_vars_to_set,
      49                 :                bool wait, ProcessHandle* process_handle,
      50                 :                ProcessArchitecture arch) {
      51               0 :   scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
      52                 :   // Illegal to allocate memory after fork and before execvp
      53               0 :   InjectiveMultimap fd_shuffle1, fd_shuffle2;
      54               0 :   fd_shuffle1.reserve(fds_to_remap.size());
      55               0 :   fd_shuffle2.reserve(fds_to_remap.size());
      56                 : 
      57               0 :   pid_t pid = fork();
      58               0 :   if (pid < 0)
      59               0 :     return false;
      60                 : 
      61               0 :   if (pid == 0) {
      62               0 :     for (file_handle_mapping_vector::const_iterator
      63               0 :         it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
      64               0 :       fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
      65               0 :       fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
      66                 :     }
      67                 : 
      68               0 :     if (!ShuffleFileDescriptors(&fd_shuffle1))
      69               0 :       _exit(127);
      70                 : 
      71               0 :     CloseSuperfluousFds(fd_shuffle2);
      72                 : 
      73               0 :     for (environment_map::const_iterator it = env_vars_to_set.begin();
      74               0 :          it != env_vars_to_set.end(); ++it) {
      75               0 :       if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/))
      76               0 :         _exit(127);
      77                 :     }
      78                 : 
      79               0 :     for (size_t i = 0; i < argv.size(); i++)
      80               0 :       argv_cstr[i] = const_cast<char*>(argv[i].c_str());
      81               0 :     argv_cstr[argv.size()] = NULL;
      82               0 :     execvp(argv_cstr[0], argv_cstr.get());
      83                 :     // if we get here, we're in serious trouble and should complain loudly
      84               0 :     DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
      85               0 :     exit(127);
      86                 :   } else {
      87                 :     gProcessLog.print("==> process %d launched child process %d\n",
      88               0 :                       GetCurrentProcId(), pid);
      89               0 :     if (wait)
      90               0 :       HANDLE_EINTR(waitpid(pid, 0, 0));
      91                 : 
      92               0 :     if (process_handle)
      93               0 :       *process_handle = pid;
      94                 :   }
      95                 : 
      96               0 :   return true;
      97                 : }
      98                 : 
      99               0 : bool LaunchApp(const CommandLine& cl,
     100                 :                bool wait, bool start_hidden,
     101                 :                ProcessHandle* process_handle) {
     102               0 :   file_handle_mapping_vector no_files;
     103               0 :   return LaunchApp(cl.argv(), no_files, wait, process_handle);
     104                 : }
     105                 : 
     106               0 : NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
     107                 :                                            const ProcessFilter* filter)
     108               0 :     : executable_name_(executable_name), filter_(filter) {
     109               0 :   procfs_dir_ = opendir("/proc");
     110               0 : }
     111                 : 
     112               0 : NamedProcessIterator::~NamedProcessIterator() {
     113               0 :   if (procfs_dir_) {
     114               0 :     closedir(procfs_dir_);
     115               0 :     procfs_dir_ = NULL;
     116                 :   }
     117               0 : }
     118                 : 
     119               0 : const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
     120               0 :   bool result = false;
     121               0 :   do {
     122               0 :     result = CheckForNextProcess();
     123               0 :   } while (result && !IncludeEntry());
     124                 : 
     125               0 :   if (result)
     126               0 :     return &entry_;
     127                 : 
     128               0 :   return NULL;
     129                 : }
     130                 : 
     131               0 : bool NamedProcessIterator::CheckForNextProcess() {
     132                 :   // TODO(port): skip processes owned by different UID
     133                 : 
     134               0 :   dirent* slot = 0;
     135                 :   const char* openparen;
     136                 :   const char* closeparen;
     137                 : 
     138                 :   // Arbitrarily guess that there will never be more than 200 non-process
     139                 :   // files in /proc.  Hardy has 53.
     140               0 :   int skipped = 0;
     141               0 :   const int kSkipLimit = 200;
     142               0 :   while (skipped < kSkipLimit) {
     143               0 :     slot = readdir(procfs_dir_);
     144                 :     // all done looking through /proc?
     145               0 :     if (!slot)
     146               0 :       return false;
     147                 : 
     148                 :     // If not a process, keep looking for one.
     149               0 :     bool notprocess = false;
     150                 :     int i;
     151               0 :     for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) {
     152               0 :        if (!isdigit(slot->d_name[i])) {
     153               0 :          notprocess = true;
     154               0 :          break;
     155                 :        }
     156                 :     }
     157               0 :     if (i == NAME_MAX || notprocess) {
     158               0 :       skipped++;
     159               0 :       continue;
     160                 :     }
     161                 : 
     162                 :     // Read the process's status.
     163                 :     char buf[NAME_MAX + 12];
     164               0 :     sprintf(buf, "/proc/%s/stat", slot->d_name);
     165               0 :     FILE *fp = fopen(buf, "r");
     166               0 :     if (!fp)
     167               0 :       return false;
     168               0 :     const char* result = fgets(buf, sizeof(buf), fp);
     169               0 :     fclose(fp);
     170               0 :     if (!result)
     171               0 :       return false;
     172                 : 
     173                 :     // Parse the status.  It is formatted like this:
     174                 :     // %d (%s) %c %d ...
     175                 :     // pid (name) runstate ppid
     176                 :     // To avoid being fooled by names containing a closing paren, scan
     177                 :     // backwards.
     178               0 :     openparen = strchr(buf, '(');
     179               0 :     closeparen = strrchr(buf, ')');
     180               0 :     if (!openparen || !closeparen)
     181               0 :       return false;
     182               0 :     char runstate = closeparen[2];
     183                 : 
     184                 :     // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
     185                 :     // Allowed values: D R S T Z
     186               0 :     if (runstate != 'Z')
     187               0 :       break;
     188                 : 
     189                 :     // Nope, it's a zombie; somebody isn't cleaning up after their children.
     190                 :     // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
     191                 :     // There could be a lot of zombies, can't really decrement i here.
     192                 :   }
     193               0 :   if (skipped >= kSkipLimit) {
     194               0 :     NOTREACHED();
     195               0 :     return false;
     196                 :   }
     197                 : 
     198               0 :   entry_.pid = atoi(slot->d_name);
     199               0 :   entry_.ppid = atoi(closeparen + 3);
     200                 : 
     201                 :   // TODO(port): read pid's commandline's $0, like killall does.  Using the
     202                 :   // short name between openparen and closeparen won't work for long names!
     203               0 :   int len = closeparen - openparen - 1;
     204               0 :   if (len > NAME_MAX)
     205               0 :     len = NAME_MAX;
     206               0 :   memcpy(entry_.szExeFile, openparen + 1, len);
     207               0 :   entry_.szExeFile[len] = 0;
     208                 : 
     209               0 :   return true;
     210                 : }
     211                 : 
     212               0 : bool NamedProcessIterator::IncludeEntry() {
     213                 :   // TODO(port): make this also work for non-ASCII filenames
     214               0 :   if (WideToASCII(executable_name_) != entry_.szExeFile)
     215               0 :     return false;
     216               0 :   if (!filter_)
     217               0 :     return true;
     218               0 :   return filter_->Includes(entry_.pid, entry_.ppid);
     219                 : }
     220                 : 
     221                 : // To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
     222                 : // in your kernel configuration.
     223               0 : bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
     224               0 :   std::string proc_io_contents;
     225               0 :   if (!file_util::ReadFileToString(L"/proc/self/io", &proc_io_contents))
     226               0 :     return false;
     227                 : 
     228               0 :   (*io_counters).OtherOperationCount = 0;
     229               0 :   (*io_counters).OtherTransferCount = 0;
     230                 : 
     231               0 :   StringTokenizer tokenizer(proc_io_contents, ": \n");
     232               0 :   ParsingState state = KEY_NAME;
     233               0 :   std::string last_key_name;
     234               0 :   while (tokenizer.GetNext()) {
     235               0 :     switch (state) {
     236                 :       case KEY_NAME:
     237               0 :         last_key_name = tokenizer.token();
     238               0 :         state = KEY_VALUE;
     239               0 :         break;
     240                 :       case KEY_VALUE:
     241               0 :         DCHECK(!last_key_name.empty());
     242               0 :         if (last_key_name == "syscr") {
     243               0 :           (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token());
     244               0 :         } else if (last_key_name == "syscw") {
     245               0 :           (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token());
     246               0 :         } else if (last_key_name == "rchar") {
     247               0 :           (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token());
     248               0 :         } else if (last_key_name == "wchar") {
     249               0 :           (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token());
     250                 :         }
     251               0 :         state = KEY_NAME;
     252               0 :         break;
     253                 :     }
     254                 :   }
     255               0 :   return true;
     256                 : }
     257                 : 
     258            4392 : }  // namespace base

Generated by: LCOV version 1.7