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