process_util_linux.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
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 FilePath exe_name; 115 if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) { 116 // No such process. Happens frequently in e.g. TerminateAllChromeProcesses 117 return FilePath(); 118 } 119 return exe_name; 120} 121 122ProcessIterator::ProcessIterator(const ProcessFilter* filter) 123 : filter_(filter) { 124 procfs_dir_ = opendir("/proc"); 125} 126 127ProcessIterator::~ProcessIterator() { 128 if (procfs_dir_) { 129 closedir(procfs_dir_); 130 procfs_dir_ = NULL; 131 } 132} 133 134bool ProcessIterator::CheckForNextProcess() { 135 // TODO(port): skip processes owned by different UID 136 137 dirent* slot = 0; 138 const char* openparen; 139 const char* closeparen; 140 std::vector<std::string> cmd_line_args; 141 142 // Arbitrarily guess that there will never be more than 200 non-process 143 // files in /proc. Hardy has 53. 144 int skipped = 0; 145 const int kSkipLimit = 200; 146 while (skipped < kSkipLimit) { 147 slot = readdir(procfs_dir_); 148 // all done looking through /proc? 149 if (!slot) 150 return false; 151 152 // If not a process, keep looking for one. 153 bool notprocess = false; 154 int i; 155 for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) { 156 if (!isdigit(slot->d_name[i])) { 157 notprocess = true; 158 break; 159 } 160 } 161 if (i == NAME_MAX || notprocess) { 162 skipped++; 163 continue; 164 } 165 166 // Read the process's command line. 167 std::string pid_string(slot->d_name); 168 int pid; 169 if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args)) 170 return false; 171 172 // Read the process's status. 173 char buf[NAME_MAX + 12]; 174 sprintf(buf, "/proc/%s/stat", slot->d_name); 175 FILE *fp = fopen(buf, "r"); 176 if (!fp) 177 return false; 178 const char* result = fgets(buf, sizeof(buf), fp); 179 fclose(fp); 180 if (!result) 181 return false; 182 183 // Parse the status. It is formatted like this: 184 // %d (%s) %c %d %d ... 185 // pid (name) runstate ppid gid 186 // To avoid being fooled by names containing a closing paren, scan 187 // backwards. 188 openparen = strchr(buf, '('); 189 closeparen = strrchr(buf, ')'); 190 if (!openparen || !closeparen) 191 return false; 192 char runstate = closeparen[2]; 193 194 // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped? 195 // Allowed values: D R S T Z 196 if (runstate != 'Z') 197 break; 198 199 // Nope, it's a zombie; somebody isn't cleaning up after their children. 200 // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.) 201 // There could be a lot of zombies, can't really decrement i here. 202 } 203 if (skipped >= kSkipLimit) { 204 NOTREACHED(); 205 return false; 206 } 207 208 // This seems fragile. 209 entry_.pid_ = atoi(slot->d_name); 210 entry_.ppid_ = atoi(closeparen + 3); 211 entry_.gid_ = atoi(strchr(closeparen + 4, ' ')); 212 213 entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end()); 214 215 // TODO(port): read pid's commandline's $0, like killall does. Using the 216 // short name between openparen and closeparen won't work for long names! 217 int len = closeparen - openparen - 1; 218 entry_.exe_file_.assign(openparen + 1, len); 219 return true; 220} 221 222bool NamedProcessIterator::IncludeEntry() { 223 if (executable_name_ != entry().exe_file()) 224 return false; 225 return ProcessIterator::IncludeEntry(); 226} 227 228 229ProcessMetrics::ProcessMetrics(ProcessHandle process) 230 : process_(process), 231 last_time_(0), 232 last_system_time_(0), 233 last_cpu_(0) { 234 processor_count_ = base::SysInfo::NumberOfProcessors(); 235} 236 237// static 238ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { 239 return new ProcessMetrics(process); 240} 241 242// On linux, we return vsize. 243size_t ProcessMetrics::GetPagefileUsage() const { 244 std::vector<std::string> proc_stats; 245 if (!GetProcStats(process_, &proc_stats)) 246 LOG(WARNING) << "Failed to get process stats."; 247 const size_t kVmSize = 22; 248 if (proc_stats.size() > kVmSize) { 249 int vm_size; 250 base::StringToInt(proc_stats[kVmSize], &vm_size); 251 return static_cast<size_t>(vm_size); 252 } 253 return 0; 254} 255 256// On linux, we return the high water mark of vsize. 257size_t ProcessMetrics::GetPeakPagefileUsage() const { 258 std::vector<std::string> proc_stats; 259 if (!GetProcStats(process_, &proc_stats)) 260 LOG(WARNING) << "Failed to get process stats."; 261 const size_t kVmPeak = 21; 262 if (proc_stats.size() > kVmPeak) { 263 int vm_peak; 264 if (base::StringToInt(proc_stats[kVmPeak], &vm_peak)) 265 return vm_peak; 266 } 267 return 0; 268} 269 270// On linux, we return RSS. 271size_t ProcessMetrics::GetWorkingSetSize() const { 272 std::vector<std::string> proc_stats; 273 if (!GetProcStats(process_, &proc_stats)) 274 LOG(WARNING) << "Failed to get process stats."; 275 const size_t kVmRss = 23; 276 if (proc_stats.size() > kVmRss) { 277 int num_pages; 278 if (base::StringToInt(proc_stats[kVmRss], &num_pages)) 279 return static_cast<size_t>(num_pages) * getpagesize(); 280 } 281 return 0; 282} 283 284// On linux, we return the high water mark of RSS. 285size_t ProcessMetrics::GetPeakWorkingSetSize() const { 286 std::vector<std::string> proc_stats; 287 if (!GetProcStats(process_, &proc_stats)) 288 LOG(WARNING) << "Failed to get process stats."; 289 const size_t kVmHwm = 23; 290 if (proc_stats.size() > kVmHwm) { 291 int num_pages; 292 base::StringToInt(proc_stats[kVmHwm], &num_pages); 293 return static_cast<size_t>(num_pages) * getpagesize(); 294 } 295 return 0; 296} 297 298bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, 299 size_t* shared_bytes) { 300 WorkingSetKBytes ws_usage; 301 if (!GetWorkingSetKBytes(&ws_usage)) 302 return false; 303 304 if (private_bytes) 305 *private_bytes = ws_usage.priv << 10; 306 307 if (shared_bytes) 308 *shared_bytes = ws_usage.shared * 1024; 309 310 return true; 311} 312 313// Private and Shared working set sizes are obtained from /proc/<pid>/smaps. 314// When that's not available, use the values from /proc<pid>/statm as a 315// close approximation. 316// See http://www.pixelbeat.org/scripts/ps_mem.py 317bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { 318 // Synchronously reading files in /proc is safe. 319 base::ThreadRestrictions::ScopedAllowIO allow_io; 320 321 FilePath proc_dir = FilePath("/proc").Append(base::IntToString(process_)); 322 std::string smaps; 323 int private_kb = 0; 324 int pss_kb = 0; 325 bool have_pss = false; 326 bool ret; 327 328 { 329 FilePath smaps_file = proc_dir.Append("smaps"); 330 // Synchronously reading files in /proc is safe. 331 base::ThreadRestrictions::ScopedAllowIO allow_io; 332 ret = file_util::ReadFileToString(smaps_file, &smaps); 333 } 334 if (ret && smaps.length() > 0) { 335 const std::string private_prefix = "Private_"; 336 const std::string pss_prefix = "Pss"; 337 StringTokenizer tokenizer(smaps, ":\n"); 338 StringPiece last_key_name; 339 ParsingState state = KEY_NAME; 340 while (tokenizer.GetNext()) { 341 switch (state) { 342 case KEY_NAME: 343 last_key_name = tokenizer.token_piece(); 344 state = KEY_VALUE; 345 break; 346 case KEY_VALUE: 347 if (last_key_name.empty()) { 348 NOTREACHED(); 349 return false; 350 } 351 if (last_key_name.starts_with(private_prefix)) { 352 int cur; 353 base::StringToInt(tokenizer.token(), &cur); 354 private_kb += cur; 355 } else if (last_key_name.starts_with(pss_prefix)) { 356 have_pss = true; 357 int cur; 358 base::StringToInt(tokenizer.token(), &cur); 359 pss_kb += cur; 360 } 361 state = KEY_NAME; 362 break; 363 } 364 } 365 } else { 366 // Try statm if smaps is empty because of the SUID sandbox. 367 // First we need to get the page size though. 368 int page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; 369 if (page_size_kb <= 0) 370 return false; 371 372 std::string statm; 373 { 374 FilePath statm_file = proc_dir.Append("statm"); 375 // Synchronously reading files in /proc is safe. 376 base::ThreadRestrictions::ScopedAllowIO allow_io; 377 ret = file_util::ReadFileToString(statm_file, &statm); 378 } 379 if (!ret || statm.length() == 0) 380 return false; 381 382 std::vector<std::string> statm_vec; 383 base::SplitString(statm, ' ', &statm_vec); 384 if (statm_vec.size() != 7) 385 return false; // Not the format we expect. 386 387 int statm1, statm2; 388 base::StringToInt(statm_vec[1], &statm1); 389 base::StringToInt(statm_vec[2], &statm2); 390 private_kb = (statm1 - statm2) * page_size_kb; 391 } 392 ws_usage->priv = private_kb; 393 // Sharable is not calculated, as it does not provide interesting data. 394 ws_usage->shareable = 0; 395 396 ws_usage->shared = 0; 397 if (have_pss) 398 ws_usage->shared = pss_kb; 399 return true; 400} 401 402// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING 403// in your kernel configuration. 404bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { 405 // Synchronously reading files in /proc is safe. 406 base::ThreadRestrictions::ScopedAllowIO allow_io; 407 408 std::string proc_io_contents; 409 FilePath io_file("/proc"); 410 io_file = io_file.Append(base::IntToString(process_)); 411 io_file = io_file.Append("io"); 412 if (!file_util::ReadFileToString(io_file, &proc_io_contents)) 413 return false; 414 415 (*io_counters).OtherOperationCount = 0; 416 (*io_counters).OtherTransferCount = 0; 417 418 StringTokenizer tokenizer(proc_io_contents, ": \n"); 419 ParsingState state = KEY_NAME; 420 std::string last_key_name; 421 while (tokenizer.GetNext()) { 422 switch (state) { 423 case KEY_NAME: 424 last_key_name = tokenizer.token(); 425 state = KEY_VALUE; 426 break; 427 case KEY_VALUE: 428 DCHECK(!last_key_name.empty()); 429 if (last_key_name == "syscr") { 430 base::StringToInt64(tokenizer.token(), 431 reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount)); 432 } else if (last_key_name == "syscw") { 433 base::StringToInt64(tokenizer.token(), 434 reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount)); 435 } else if (last_key_name == "rchar") { 436 base::StringToInt64(tokenizer.token(), 437 reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount)); 438 } else if (last_key_name == "wchar") { 439 base::StringToInt64(tokenizer.token(), 440 reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount)); 441 } 442 state = KEY_NAME; 443 break; 444 } 445 } 446 return true; 447} 448 449 450// Exposed for testing. 451int ParseProcStatCPU(const std::string& input) { 452 // /proc/<pid>/stat contains the process name in parens. In case the 453 // process name itself contains parens, skip past them. 454 std::string::size_type rparen = input.rfind(')'); 455 if (rparen == std::string::npos) 456 return -1; 457 458 // From here, we expect a bunch of space-separated fields, where the 459 // 0-indexed 11th and 12th are utime and stime. On two different machines 460 // I found 42 and 39 fields, so let's just expect the ones we need. 461 std::vector<std::string> fields; 462 base::SplitString(input.substr(rparen + 2), ' ', &fields); 463 if (fields.size() < 13) 464 return -1; // Output not in the format we expect. 465 466 int fields11, fields12; 467 base::StringToInt(fields[11], &fields11); 468 base::StringToInt(fields[12], &fields12); 469 return fields11 + fields12; 470} 471 472// Get the total CPU of a single process. Return value is number of jiffies 473// on success or -1 on error. 474static int GetProcessCPU(pid_t pid) { 475 // Synchronously reading files in /proc is safe. 476 base::ThreadRestrictions::ScopedAllowIO allow_io; 477 478 // Use /proc/<pid>/task to find all threads and parse their /stat file. 479 FilePath path = FilePath(StringPrintf("/proc/%d/task/", pid)); 480 481 DIR* dir = opendir(path.value().c_str()); 482 if (!dir) { 483 PLOG(ERROR) << "opendir(" << path.value() << ")"; 484 return -1; 485 } 486 487 int total_cpu = 0; 488 while (struct dirent* ent = readdir(dir)) { 489 if (ent->d_name[0] == '.') 490 continue; 491 492 FilePath stat_path = path.AppendASCII(ent->d_name).AppendASCII("stat"); 493 std::string stat; 494 if (file_util::ReadFileToString(stat_path, &stat)) { 495 int cpu = ParseProcStatCPU(stat); 496 if (cpu > 0) 497 total_cpu += cpu; 498 } 499 } 500 closedir(dir); 501 502 return total_cpu; 503} 504 505double ProcessMetrics::GetCPUUsage() { 506 // This queries the /proc-specific scaling factor which is 507 // conceptually the system hertz. To dump this value on another 508 // system, try 509 // od -t dL /proc/self/auxv 510 // and look for the number after 17 in the output; mine is 511 // 0000040 17 100 3 134512692 512 // which means the answer is 100. 513 // It may be the case that this value is always 100. 514 static const int kHertz = sysconf(_SC_CLK_TCK); 515 516 struct timeval now; 517 int retval = gettimeofday(&now, NULL); 518 if (retval) 519 return 0; 520 int64 time = TimeValToMicroseconds(now); 521 522 if (last_time_ == 0) { 523 // First call, just set the last values. 524 last_time_ = time; 525 last_cpu_ = GetProcessCPU(process_); 526 return 0; 527 } 528 529 int64 time_delta = time - last_time_; 530 DCHECK_NE(time_delta, 0); 531 if (time_delta == 0) 532 return 0; 533 534 int cpu = GetProcessCPU(process_); 535 536 // We have the number of jiffies in the time period. Convert to percentage. 537 // Note this means we will go *over* 100 in the case where multiple threads 538 // are together adding to more than one CPU's worth. 539 int percentage = 100 * (cpu - last_cpu_) / 540 (kHertz * TimeDelta::FromMicroseconds(time_delta).InSecondsF()); 541 542 last_time_ = time; 543 last_cpu_ = cpu; 544 545 return percentage; 546} 547 548namespace { 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// ... 557const size_t kMemTotalIndex = 1; 558const size_t kMemFreeIndex = 4; 559const size_t kMemBuffersIndex = 7; 560const size_t kMemCacheIndex = 10; 561 562} // namespace 563 564size_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 598namespace { 599 600void OnNoMemorySize(size_t size) { 601 if (size != 0) 602 LOG(FATAL) << "Out of memory, size = " << size; 603 LOG(FATAL) << "Out of memory."; 604} 605 606void OnNoMemory() { 607 OnNoMemorySize(0); 608} 609 610} // namespace 611 612extern "C" { 613#if !defined(USE_TCMALLOC) 614 615extern "C" { 616void* __libc_malloc(size_t size); 617void* __libc_realloc(void* ptr, size_t size); 618void* __libc_calloc(size_t nmemb, size_t size); 619void* __libc_valloc(size_t size); 620void* __libc_pvalloc(size_t size); 621void* __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 671DIE_ON_OOM_1(malloc) 672DIE_ON_OOM_1(valloc) 673DIE_ON_OOM_1(pvalloc) 674 675DIE_ON_OOM_2(calloc, size_t) 676DIE_ON_OOM_2(realloc, void*) 677DIE_ON_OOM_2(memalign, size_t) 678 679// posix_memalign has a unique signature and doesn't have a __libc_ variant. 680int posix_memalign(void** ptr, size_t alignment, size_t size) 681 __attribute__ ((visibility("default"))); 682 683int 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 692void 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 699bool 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