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