Home | History | Annotate | Download | only in common
      1 //
      2 // Copyright (C) 2016 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "update_engine/common/cpu_limiter.h"
     18 
     19 #include <string>
     20 
     21 #include <base/bind.h>
     22 #include <base/logging.h>
     23 #include <base/strings/string_number_conversions.h>
     24 #include <base/time/time.h>
     25 
     26 #include "update_engine/common/utils.h"
     27 
     28 namespace {
     29 
     30 // Cgroup container is created in update-engine's upstart script located at
     31 // /etc/init/update-engine.conf.
     32 const char kCGroupSharesPath[] = "/sys/fs/cgroup/cpu/update-engine/cpu.shares";
     33 
     34 }  // namespace
     35 
     36 namespace chromeos_update_engine {
     37 
     38 CPULimiter::~CPULimiter() {
     39   // Set everything back to normal on destruction.
     40   CPULimiter::SetCpuShares(CpuShares::kNormal);
     41 }
     42 
     43 void CPULimiter::StartLimiter() {
     44   if (manage_shares_id_ != brillo::MessageLoop::kTaskIdNull) {
     45     LOG(ERROR) << "Cpu shares timeout source hasn't been destroyed.";
     46     StopLimiter();
     47   }
     48   manage_shares_id_ = brillo::MessageLoop::current()->PostDelayedTask(
     49       FROM_HERE,
     50       base::Bind(&CPULimiter::StopLimiterCallback, base::Unretained(this)),
     51       base::TimeDelta::FromHours(2));
     52   SetCpuShares(CpuShares::kLow);
     53 }
     54 
     55 void CPULimiter::StopLimiter() {
     56   if (manage_shares_id_ != brillo::MessageLoop::kTaskIdNull) {
     57     // If the shares were never set and there isn't a message loop instance,
     58     // we avoid calling CancelTask(), which otherwise would have been a no-op.
     59     brillo::MessageLoop::current()->CancelTask(manage_shares_id_);
     60     manage_shares_id_ = brillo::MessageLoop::kTaskIdNull;
     61   }
     62   SetCpuShares(CpuShares::kNormal);
     63 }
     64 
     65 bool CPULimiter::SetCpuShares(CpuShares shares) {
     66   // Short-circuit to avoid re-setting the shares.
     67   if (shares_ == shares)
     68     return true;
     69 
     70   std::string string_shares = base::IntToString(static_cast<int>(shares));
     71   LOG(INFO) << "Setting cgroup cpu shares to  " << string_shares;
     72   if (!utils::WriteFile(
     73           kCGroupSharesPath, string_shares.c_str(), string_shares.size())) {
     74     LOG(ERROR) << "Failed to change cgroup cpu shares to " << string_shares
     75                << " using " << kCGroupSharesPath;
     76     return false;
     77   }
     78   shares_ = shares;
     79   LOG(INFO) << "CPU shares = " << static_cast<int>(shares_);
     80   return true;
     81 }
     82 
     83 void CPULimiter::StopLimiterCallback() {
     84   SetCpuShares(CpuShares::kNormal);
     85   manage_shares_id_ = brillo::MessageLoop::kTaskIdNull;
     86 }
     87 
     88 }  // namespace chromeos_update_engine
     89