Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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.h"
      6 
      7 #include <errno.h>
      8 #include <sys/resource.h>
      9 
     10 #include "base/file_util.h"
     11 #include "base/logging.h"
     12 #include "base/stringprintf.h"
     13 
     14 #if defined(OS_CHROMEOS)
     15 static bool use_cgroups = false;
     16 static bool cgroups_inited = false;
     17 static const char kForegroundTasks[] =
     18     "/tmp/cgroup/cpu/chrome_renderers/foreground/tasks";
     19 static const char kBackgroundTasks[] =
     20     "/tmp/cgroup/cpu/chrome_renderers/background/tasks";
     21 static FilePath foreground_tasks;
     22 static FilePath background_tasks;
     23 #endif
     24 
     25 namespace base {
     26 
     27 #if defined(OS_CHROMEOS)
     28 // We are more aggressive in our lowering of background process priority
     29 // for chromeos as we have much more control over other processes running
     30 // on the machine.
     31 const int kPriorityAdjustment = 19;
     32 #else
     33 const int kPriorityAdjustment = 5;
     34 #endif
     35 
     36 bool Process::IsProcessBackgrounded() const {
     37   DCHECK(process_);
     38   return saved_priority_ == kUnsetProcessPriority;
     39 }
     40 
     41 bool Process::SetProcessBackgrounded(bool background) {
     42   DCHECK(process_);
     43 
     44 #if defined(OS_CHROMEOS)
     45   // Check for cgroups files. ChromeOS supports these by default. It creates
     46   // a cgroup mount in /tmp/cgroup and then configures two cpu task groups,
     47   // one contains at most a single foreground renderer and the other contains
     48   // all background renderers. This allows us to limit the impact of background
     49   // renderers on foreground ones to a greater level than simple renicing.
     50   if (!cgroups_inited) {
     51     cgroups_inited = true;
     52     foreground_tasks = FilePath(kForegroundTasks);
     53     background_tasks = FilePath(kBackgroundTasks);
     54     file_util::FileSystemType foreground_type;
     55     file_util::FileSystemType background_type;
     56     use_cgroups =
     57         file_util::GetFileSystemType(foreground_tasks, &foreground_type) &&
     58         file_util::GetFileSystemType(background_tasks, &background_type) &&
     59         foreground_type == file_util::FILE_SYSTEM_CGROUP &&
     60         background_type == file_util::FILE_SYSTEM_CGROUP;
     61   }
     62 
     63   if (use_cgroups) {
     64     if (background) {
     65       std::string pid = StringPrintf("%d", process_);
     66       if (file_util::WriteFile(background_tasks, pid.c_str(), pid.size()) > 0) {
     67         // With cgroups there's no real notion of priority as an int, but this
     68         // will ensure we only move renderers back to the foreground group
     69         // if we've ever put them in the background one.
     70         saved_priority_ = 0;
     71         return true;
     72       } else {
     73         return false;
     74       }
     75     } else {
     76       if (saved_priority_ == kUnsetProcessPriority) {
     77         // Can't restore if we were never backgrounded.
     78         return false;
     79       }
     80       std::string pid = StringPrintf("%d", process_);
     81       if (file_util::WriteFile(foreground_tasks, pid.c_str(), pid.size()) > 0) {
     82         saved_priority_ = kUnsetProcessPriority;
     83         return true;
     84       } else {
     85         return false;
     86       }
     87     }
     88   }
     89 #endif // OS_CHROMEOS
     90 
     91   if (background) {
     92     // We won't be able to raise the priority if we don't have the right rlimit.
     93     // The limit may be adjusted in /etc/security/limits.conf for PAM systems.
     94     struct rlimit rlim;
     95     if (getrlimit(RLIMIT_NICE, &rlim) != 0) {
     96       // Call to getrlimit failed, don't background.
     97       return false;
     98     }
     99     errno = 0;
    100     int current_priority = GetPriority();
    101     if (errno) {
    102       // Couldn't get priority.
    103       return false;
    104     }
    105     // {set,get}priority values are in the range -20 to 19, where -1 is higher
    106     // priority than 0. But rlimit's are in the range from 0 to 39 where
    107     // 1 is higher than 0.
    108     if ((20 - current_priority) > static_cast<int>(rlim.rlim_cur)) {
    109       // User is not allowed to raise the priority back to where it is now.
    110       return false;
    111     }
    112     int result =
    113         setpriority(
    114             PRIO_PROCESS, process_, current_priority + kPriorityAdjustment);
    115     if (result == -1) {
    116       LOG(ERROR) << "Failed to lower priority, errno: " << errno;
    117       return false;
    118     }
    119     saved_priority_ = current_priority;
    120     return true;
    121   } else {
    122     if (saved_priority_ == kUnsetProcessPriority) {
    123       // Can't restore if we were never backgrounded.
    124       return false;
    125     }
    126     int result = setpriority(PRIO_PROCESS, process_, saved_priority_);
    127     // If we can't restore something has gone terribly wrong.
    128     DPCHECK(result == 0);
    129     saved_priority_ = kUnsetProcessPriority;
    130     return true;
    131   }
    132 }
    133 
    134 }  // namespace base
    135