process_util_linux.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2009 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 <dlfcn.h>
10#include <errno.h>
11#include <fcntl.h>
12#include <sys/time.h>
13#include <sys/types.h>
14#include <sys/wait.h>
15#include <time.h>
16#include <unistd.h>
17
18#include "base/file_util.h"
19#include "base/logging.h"
20#include "base/string_number_conversions.h"
21#include "base/string_split.h"
22#include "base/string_tokenizer.h"
23#include "base/string_util.h"
24#include "base/sys_info.h"
25#include "base/thread_restrictions.h"
26
27namespace {
28
29enum ParsingState {
30  KEY_NAME,
31  KEY_VALUE
32};
33
34// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
35// spaces. Returns true if successful.
36bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
37  // Synchronously reading files in /proc is safe.
38  base::ThreadRestrictions::ScopedAllowIO allow_io;
39
40  FilePath stat_file("/proc");
41  stat_file = stat_file.Append(base::IntToString(pid));
42  stat_file = stat_file.Append("stat");
43  std::string mem_stats;
44  if (!file_util::ReadFileToString(stat_file, &mem_stats))
45    return false;
46  base::SplitString(mem_stats, ' ', proc_stats);
47  return true;
48}
49
50// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
51// line arguments. Returns true if successful.
52// Note: /proc/<pid>/cmdline contains command line arguments separated by single
53// null characters. We tokenize it into a vector of strings using '\0' as a
54// delimiter.
55bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
56  // Synchronously reading files in /proc is safe.
57  base::ThreadRestrictions::ScopedAllowIO allow_io;
58
59  FilePath cmd_line_file("/proc");
60  cmd_line_file = cmd_line_file.Append(base::IntToString(pid));
61  cmd_line_file = cmd_line_file.Append("cmdline");
62  std::string cmd_line;
63  if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
64    return false;
65  std::string delimiters;
66  delimiters.push_back('\0');
67  Tokenize(cmd_line, delimiters, proc_cmd_line_args);
68  return true;
69}
70
71}  // namespace
72
73namespace base {
74
75ProcessId GetParentProcessId(ProcessHandle process) {
76  // Synchronously reading files in /proc is safe.
77  base::ThreadRestrictions::ScopedAllowIO allow_io;
78
79  FilePath stat_file("/proc");
80  stat_file = stat_file.Append(base::IntToString(process));
81  stat_file = stat_file.Append("status");
82  std::string status;
83  if (!file_util::ReadFileToString(stat_file, &status))
84    return -1;
85
86  StringTokenizer tokenizer(status, ":\n");
87  ParsingState state = KEY_NAME;
88  std::string last_key_name;
89  while (tokenizer.GetNext()) {
90    switch (state) {
91      case KEY_NAME:
92        last_key_name = tokenizer.token();
93        state = KEY_VALUE;
94        break;
95      case KEY_VALUE:
96        DCHECK(!last_key_name.empty());
97        if (last_key_name == "PPid") {
98          int ppid;
99          base::StringToInt(tokenizer.token(), &ppid);
100          return ppid;
101        }
102        state = KEY_NAME;
103        break;
104    }
105  }
106  NOTREACHED();
107  return -1;
108}
109
110FilePath GetProcessExecutablePath(ProcessHandle process) {
111  FilePath stat_file("/proc");
112  stat_file = stat_file.Append(base::IntToString(process));
113  stat_file = stat_file.Append("exe");
114  char exename[2048];
115  ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename));
116  if (len < 1) {
117    // No such process.  Happens frequently in e.g. TerminateAllChromeProcesses
118    return FilePath();
119  }
120  return FilePath(std::string(exename, len));
121}
122
123ProcessIterator::ProcessIterator(const ProcessFilter* filter)
124    : filter_(filter) {
125  procfs_dir_ = opendir("/proc");
126}
127
128ProcessIterator::~ProcessIterator() {
129  if (procfs_dir_) {
130    closedir(procfs_dir_);
131    procfs_dir_ = NULL;
132  }
133}
134
135bool ProcessIterator::CheckForNextProcess() {
136  // TODO(port): skip processes owned by different UID
137
138  dirent* slot = 0;
139  const char* openparen;
140  const char* closeparen;
141  std::vector<std::string> cmd_line_args;
142
143  // Arbitrarily guess that there will never be more than 200 non-process
144  // files in /proc.  Hardy has 53.
145  int skipped = 0;
146  const int kSkipLimit = 200;
147  while (skipped < kSkipLimit) {
148    slot = readdir(procfs_dir_);
149    // all done looking through /proc?
150    if (!slot)
151      return false;
152
153    // If not a process, keep looking for one.
154    bool notprocess = false;
155    int i;
156    for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) {
157       if (!isdigit(slot->d_name[i])) {
158         notprocess = true;
159         break;
160       }
161    }
162    if (i == NAME_MAX || notprocess) {
163      skipped++;
164      continue;
165    }
166
167    // Read the process's command line.
168    std::string pid_string(slot->d_name);
169    int pid;
170    if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args))
171      return false;
172
173    // Read the process's status.
174    char buf[NAME_MAX + 12];
175    sprintf(buf, "/proc/%s/stat", slot->d_name);
176    FILE *fp = fopen(buf, "r");
177    if (!fp)
178      return false;
179    const char* result = fgets(buf, sizeof(buf), fp);
180    fclose(fp);
181    if (!result)
182      return false;
183
184    // Parse the status.  It is formatted like this:
185    // %d (%s) %c %d %d ...
186    // pid (name) runstate ppid gid
187    // To avoid being fooled by names containing a closing paren, scan
188    // backwards.
189    openparen = strchr(buf, '(');
190    closeparen = strrchr(buf, ')');
191    if (!openparen || !closeparen)
192      return false;
193    char runstate = closeparen[2];
194
195    // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
196    // Allowed values: D R S T Z
197    if (runstate != 'Z')
198      break;
199
200    // Nope, it's a zombie; somebody isn't cleaning up after their children.
201    // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
202    // There could be a lot of zombies, can't really decrement i here.
203  }
204  if (skipped >= kSkipLimit) {
205    NOTREACHED();
206    return false;
207  }
208
209  // This seems fragile.
210  entry_.pid_ = atoi(slot->d_name);
211  entry_.ppid_ = atoi(closeparen + 3);
212  entry_.gid_ = atoi(strchr(closeparen + 4, ' '));
213
214  entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
215
216  // TODO(port): read pid's commandline's $0, like killall does.  Using the
217  // short name between openparen and closeparen won't work for long names!
218  int len = closeparen - openparen - 1;
219  entry_.exe_file_.assign(openparen + 1, len);
220  return true;
221}
222
223bool NamedProcessIterator::IncludeEntry() {
224  // TODO(port): make this also work for non-ASCII filenames
225  if (WideToASCII(executable_name_) != entry().exe_file())
226    return false;
227  return ProcessIterator::IncludeEntry();
228}
229
230
231ProcessMetrics::ProcessMetrics(ProcessHandle process)
232    : process_(process),
233      last_time_(0),
234      last_system_time_(0),
235      last_cpu_(0) {
236  processor_count_ = base::SysInfo::NumberOfProcessors();
237}
238
239// static
240ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
241  return new ProcessMetrics(process);
242}
243
244// On linux, we return vsize.
245size_t ProcessMetrics::GetPagefileUsage() const {
246  std::vector<std::string> proc_stats;
247  if (!GetProcStats(process_, &proc_stats))
248    LOG(WARNING) << "Failed to get process stats.";
249  const size_t kVmSize = 22;
250  if (proc_stats.size() > kVmSize) {
251    int vm_size;
252    base::StringToInt(proc_stats[kVmSize], &vm_size);
253    return static_cast<size_t>(vm_size);
254  }
255  return 0;
256}
257
258// On linux, we return the high water mark of vsize.
259size_t ProcessMetrics::GetPeakPagefileUsage() const {
260  std::vector<std::string> proc_stats;
261  if (!GetProcStats(process_, &proc_stats))
262    LOG(WARNING) << "Failed to get process stats.";
263  const size_t kVmPeak = 21;
264  if (proc_stats.size() > kVmPeak) {
265    int vm_peak;
266    if (base::StringToInt(proc_stats[kVmPeak], &vm_peak))
267      return vm_peak;
268  }
269  return 0;
270}
271
272// On linux, we return RSS.
273size_t ProcessMetrics::GetWorkingSetSize() const {
274  std::vector<std::string> proc_stats;
275  if (!GetProcStats(process_, &proc_stats))
276    LOG(WARNING) << "Failed to get process stats.";
277  const size_t kVmRss = 23;
278  if (proc_stats.size() > kVmRss) {
279    int num_pages;
280    if (base::StringToInt(proc_stats[kVmRss], &num_pages))
281      return static_cast<size_t>(num_pages) * getpagesize();
282  }
283  return 0;
284}
285
286// On linux, we return the high water mark of RSS.
287size_t ProcessMetrics::GetPeakWorkingSetSize() const {
288  std::vector<std::string> proc_stats;
289  if (!GetProcStats(process_, &proc_stats))
290    LOG(WARNING) << "Failed to get process stats.";
291  const size_t kVmHwm = 23;
292  if (proc_stats.size() > kVmHwm) {
293    int num_pages;
294    base::StringToInt(proc_stats[kVmHwm], &num_pages);
295    return static_cast<size_t>(num_pages) * getpagesize();
296  }
297  return 0;
298}
299
300bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
301                                    size_t* shared_bytes) {
302  WorkingSetKBytes ws_usage;
303  if (!GetWorkingSetKBytes(&ws_usage))
304    return false;
305
306  if (private_bytes)
307    *private_bytes = ws_usage.priv << 10;
308
309  if (shared_bytes)
310    *shared_bytes = ws_usage.shared * 1024;
311
312  return true;
313}
314
315// Private and Shared working set sizes are obtained from /proc/<pid>/smaps.
316// When that's not available, use the values from /proc<pid>/statm as a
317// close approximation.
318// See http://www.pixelbeat.org/scripts/ps_mem.py
319bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
320  // Synchronously reading files in /proc is safe.
321  base::ThreadRestrictions::ScopedAllowIO allow_io;
322
323  FilePath stat_file =
324      FilePath("/proc").Append(base::IntToString(process_)).Append("smaps");
325  std::string smaps;
326  int private_kb = 0;
327  int pss_kb = 0;
328  bool have_pss = false;
329  if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) {
330    const std::string private_prefix = "Private_";
331    const std::string pss_prefix = "Pss";
332    StringTokenizer tokenizer(smaps, ":\n");
333    StringPiece last_key_name;
334    ParsingState state = KEY_NAME;
335    while (tokenizer.GetNext()) {
336      switch (state) {
337        case KEY_NAME:
338          last_key_name = tokenizer.token_piece();
339          state = KEY_VALUE;
340          break;
341        case KEY_VALUE:
342          if (last_key_name.empty()) {
343            NOTREACHED();
344            return false;
345          }
346          if (last_key_name.starts_with(private_prefix)) {
347            int cur;
348            base::StringToInt(tokenizer.token(), &cur);
349            private_kb += cur;
350          } else if (last_key_name.starts_with(pss_prefix)) {
351            have_pss = true;
352            int cur;
353            base::StringToInt(tokenizer.token(), &cur);
354            pss_kb += cur;
355          }
356          state = KEY_NAME;
357          break;
358      }
359    }
360  } else {
361    // Try statm if smaps is empty because of the SUID sandbox.
362    // First we need to get the page size though.
363    int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024;
364    if (page_size_kb <= 0)
365      return false;
366
367    stat_file =
368        FilePath("/proc").Append(base::IntToString(process_)).Append("statm");
369    std::string statm;
370    if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0)
371      return false;
372
373    std::vector<std::string> statm_vec;
374    base::SplitString(statm, ' ', &statm_vec);
375    if (statm_vec.size() != 7)
376      return false;  // Not the format we expect.
377
378    int statm1, statm2;
379    base::StringToInt(statm_vec[1], &statm1);
380    base::StringToInt(statm_vec[2], &statm2);
381    private_kb = (statm1 - statm2) * page_size_kb;
382  }
383  ws_usage->priv = private_kb;
384  // Sharable is not calculated, as it does not provide interesting data.
385  ws_usage->shareable = 0;
386
387  ws_usage->shared = 0;
388  if (have_pss)
389    ws_usage->shared = pss_kb;
390  return true;
391}
392
393// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
394// in your kernel configuration.
395bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
396  // Synchronously reading files in /proc is safe.
397  base::ThreadRestrictions::ScopedAllowIO allow_io;
398
399  std::string proc_io_contents;
400  FilePath io_file("/proc");
401  io_file = io_file.Append(base::IntToString(process_));
402  io_file = io_file.Append("io");
403  if (!file_util::ReadFileToString(io_file, &proc_io_contents))
404    return false;
405
406  (*io_counters).OtherOperationCount = 0;
407  (*io_counters).OtherTransferCount = 0;
408
409  StringTokenizer tokenizer(proc_io_contents, ": \n");
410  ParsingState state = KEY_NAME;
411  std::string last_key_name;
412  while (tokenizer.GetNext()) {
413    switch (state) {
414      case KEY_NAME:
415        last_key_name = tokenizer.token();
416        state = KEY_VALUE;
417        break;
418      case KEY_VALUE:
419        DCHECK(!last_key_name.empty());
420        if (last_key_name == "syscr") {
421          base::StringToInt64(tokenizer.token(),
422              reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
423        } else if (last_key_name == "syscw") {
424          base::StringToInt64(tokenizer.token(),
425              reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
426        } else if (last_key_name == "rchar") {
427          base::StringToInt64(tokenizer.token(),
428              reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
429        } else if (last_key_name == "wchar") {
430          base::StringToInt64(tokenizer.token(),
431              reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
432        }
433        state = KEY_NAME;
434        break;
435    }
436  }
437  return true;
438}
439
440
441// Exposed for testing.
442int ParseProcStatCPU(const std::string& input) {
443  // /proc/<pid>/stat contains the process name in parens.  In case the
444  // process name itself contains parens, skip past them.
445  std::string::size_type rparen = input.rfind(')');
446  if (rparen == std::string::npos)
447    return -1;
448
449  // From here, we expect a bunch of space-separated fields, where the
450  // 0-indexed 11th and 12th are utime and stime.  On two different machines
451  // I found 42 and 39 fields, so let's just expect the ones we need.
452  std::vector<std::string> fields;
453  base::SplitString(input.substr(rparen + 2), ' ', &fields);
454  if (fields.size() < 13)
455    return -1;  // Output not in the format we expect.
456
457  int fields11, fields12;
458  base::StringToInt(fields[11], &fields11);
459  base::StringToInt(fields[12], &fields12);
460  return fields11 + fields12;
461}
462
463// Get the total CPU of a single process.  Return value is number of jiffies
464// on success or -1 on error.
465static int GetProcessCPU(pid_t pid) {
466  // Synchronously reading files in /proc is safe.
467  base::ThreadRestrictions::ScopedAllowIO allow_io;
468
469  // Use /proc/<pid>/task to find all threads and parse their /stat file.
470  FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid));
471
472  DIR* dir = opendir(path.value().c_str());
473  if (!dir) {
474    PLOG(ERROR) << "opendir(" << path.value() << ")";
475    return -1;
476  }
477
478  int total_cpu = 0;
479  while (struct dirent* ent = readdir(dir)) {
480    if (ent->d_name[0] == '.')
481      continue;
482
483    FilePath stat_path = path.AppendASCII(ent->d_name).AppendASCII("stat");
484    std::string stat;
485    if (file_util::ReadFileToString(stat_path, &stat)) {
486      int cpu = ParseProcStatCPU(stat);
487      if (cpu > 0)
488        total_cpu += cpu;
489    }
490  }
491  closedir(dir);
492
493  return total_cpu;
494}
495
496double ProcessMetrics::GetCPUUsage() {
497  // This queries the /proc-specific scaling factor which is
498  // conceptually the system hertz.  To dump this value on another
499  // system, try
500  //   od -t dL /proc/self/auxv
501  // and look for the number after 17 in the output; mine is
502  //   0000040          17         100           3   134512692
503  // which means the answer is 100.
504  // It may be the case that this value is always 100.
505  static const int kHertz = sysconf(_SC_CLK_TCK);
506
507  struct timeval now;
508  int retval = gettimeofday(&now, NULL);
509  if (retval)
510    return 0;
511  int64 time = TimeValToMicroseconds(now);
512
513  if (last_time_ == 0) {
514    // First call, just set the last values.
515    last_time_ = time;
516    last_cpu_ = GetProcessCPU(process_);
517    return 0;
518  }
519
520  int64 time_delta = time - last_time_;
521  DCHECK_NE(time_delta, 0);
522  if (time_delta == 0)
523    return 0;
524
525  int cpu = GetProcessCPU(process_);
526
527  // We have the number of jiffies in the time period.  Convert to percentage.
528  // Note this means we will go *over* 100 in the case where multiple threads
529  // are together adding to more than one CPU's worth.
530  int percentage = 100 * (cpu - last_cpu_) /
531      (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF());
532
533  last_time_ = time;
534  last_cpu_ = cpu;
535
536  return percentage;
537}
538
539namespace {
540
541// The format of /proc/meminfo is:
542//
543// MemTotal:      8235324 kB
544// MemFree:       1628304 kB
545// Buffers:        429596 kB
546// Cached:        4728232 kB
547// ...
548const size_t kMemTotalIndex = 1;
549const size_t kMemFreeIndex = 4;
550const size_t kMemBuffersIndex = 7;
551const size_t kMemCacheIndex = 10;
552
553}  // namespace
554
555size_t GetSystemCommitCharge() {
556  // Synchronously reading files in /proc is safe.
557  base::ThreadRestrictions::ScopedAllowIO allow_io;
558
559  // Used memory is: total - free - buffers - caches
560  FilePath meminfo_file("/proc/meminfo");
561  std::string meminfo_data;
562  if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) {
563    LOG(WARNING) << "Failed to open /proc/meminfo.";
564    return 0;
565  }
566  std::vector<std::string> meminfo_fields;
567  SplitStringAlongWhitespace(meminfo_data, &meminfo_fields);
568
569  if (meminfo_fields.size() < kMemCacheIndex) {
570    LOG(WARNING) << "Failed to parse /proc/meminfo.  Only found " <<
571      meminfo_fields.size() << " fields.";
572    return 0;
573  }
574
575  DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:");
576  DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:");
577  DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
578  DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:");
579
580  int mem_total, mem_free, mem_buffers, mem_cache;
581  base::StringToInt(meminfo_fields[kMemTotalIndex], &mem_total);
582  base::StringToInt(meminfo_fields[kMemFreeIndex], &mem_free);
583  base::StringToInt(meminfo_fields[kMemBuffersIndex], &mem_buffers);
584  base::StringToInt(meminfo_fields[kMemCacheIndex], &mem_cache);
585
586  return mem_total - mem_free - mem_buffers - mem_cache;
587}
588
589namespace {
590
591void OnNoMemorySize(size_t size) {
592  if (size != 0)
593    LOG(FATAL) << "Out of memory, size = " << size;
594  LOG(FATAL) << "Out of memory.";
595}
596
597void OnNoMemory() {
598  OnNoMemorySize(0);
599}
600
601}  // namespace
602
603extern "C" {
604#if !defined(USE_TCMALLOC)
605
606extern "C" {
607void* __libc_malloc(size_t size);
608void* __libc_realloc(void* ptr, size_t size);
609void* __libc_calloc(size_t nmemb, size_t size);
610void* __libc_valloc(size_t size);
611void* __libc_pvalloc(size_t size);
612void* __libc_memalign(size_t alignment, size_t size);
613}  // extern "C"
614
615// Overriding the system memory allocation functions:
616//
617// For security reasons, we want malloc failures to be fatal. Too much code
618// doesn't check for a NULL return value from malloc and unconditionally uses
619// the resulting pointer. If the first offset that they try to access is
620// attacker controlled, then the attacker can direct the code to access any
621// part of memory.
622//
623// Thus, we define all the standard malloc functions here and mark them as
624// visibility 'default'. This means that they replace the malloc functions for
625// all Chromium code and also for all code in shared libraries. There are tests
626// for this in process_util_unittest.cc.
627//
628// If we are using tcmalloc, then the problem is moot since tcmalloc handles
629// this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
630//
631// We call the real libc functions in this code by using __libc_malloc etc.
632// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
633// the link order. Since ld.so needs calloc during symbol resolution, it
634// defines its own versions of several of these functions in dl-minimal.c.
635// Depending on the runtime library order, dlsym ended up giving us those
636// functions and bad things happened. See crbug.com/31809
637//
638// This means that any code which calls __libc_* gets the raw libc versions of
639// these functions.
640
641#define DIE_ON_OOM_1(function_name) \
642  void* function_name(size_t) __attribute__ ((visibility("default"))); \
643  \
644  void* function_name(size_t size) { \
645    void* ret = __libc_##function_name(size); \
646    if (ret == NULL && size != 0) \
647      OnNoMemorySize(size); \
648    return ret; \
649  }
650
651#define DIE_ON_OOM_2(function_name, arg1_type) \
652  void* function_name(arg1_type, size_t) \
653      __attribute__ ((visibility("default"))); \
654  \
655  void* function_name(arg1_type arg1, size_t size) { \
656    void* ret = __libc_##function_name(arg1, size); \
657    if (ret == NULL && size != 0) \
658      OnNoMemorySize(size); \
659    return ret; \
660  }
661
662DIE_ON_OOM_1(malloc)
663DIE_ON_OOM_1(valloc)
664DIE_ON_OOM_1(pvalloc)
665
666DIE_ON_OOM_2(calloc, size_t)
667DIE_ON_OOM_2(realloc, void*)
668DIE_ON_OOM_2(memalign, size_t)
669
670// posix_memalign has a unique signature and doesn't have a __libc_ variant.
671int posix_memalign(void** ptr, size_t alignment, size_t size)
672    __attribute__ ((visibility("default")));
673
674int posix_memalign(void** ptr, size_t alignment, size_t size) {
675  // This will use the safe version of memalign, above.
676  *ptr = memalign(alignment, size);
677  return 0;
678}
679
680#endif  // !defined(USE_TCMALLOC)
681}  // extern C
682
683void EnableTerminationOnOutOfMemory() {
684  // Set the new-out of memory handler.
685  std::set_new_handler(&OnNoMemory);
686  // If we're using glibc's allocator, the above functions will override
687  // malloc and friends and make them die on out of memory.
688}
689
690bool AdjustOOMScore(ProcessId process, int score) {
691  if (score < 0 || score > 15)
692    return false;
693
694  FilePath oom_adj("/proc");
695  oom_adj = oom_adj.Append(base::Int64ToString(process));
696  oom_adj = oom_adj.AppendASCII("oom_adj");
697
698  if (!file_util::PathExists(oom_adj))
699    return false;
700
701  std::string score_str = base::IntToString(score);
702  return (static_cast<int>(score_str.length()) ==
703          file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length()));
704}
705
706}  // namespace base
707