| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 | 5 |
| 6 #include "base/process_util.h" | 6 #include "base/process_util.h" |
| 7 | 7 |
| 8 #import <Cocoa/Cocoa.h> | 8 #import <Cocoa/Cocoa.h> |
| 9 #include <crt_externs.h> | 9 #include <crt_externs.h> |
| 10 #include <dlfcn.h> | 10 #include <dlfcn.h> |
| 11 #include <mach/mach.h> | 11 #include <mach/mach.h> |
| 12 #include <mach/mach_init.h> | 12 #include <mach/mach_init.h> |
| 13 #include <mach/task.h> | 13 #include <mach/task.h> |
| 14 #include <malloc/malloc.h> | 14 #include <malloc/malloc.h> |
| 15 #import <objc/runtime.h> | 15 #import <objc/runtime.h> |
| 16 #include <spawn.h> | 16 #include <spawn.h> |
| 17 #include <sys/mman.h> | 17 #include <sys/mman.h> |
| 18 #include <sys/sysctl.h> | 18 #include <sys/sysctl.h> |
| 19 #include <sys/types.h> | 19 #include <sys/types.h> |
| 20 #include <sys/utsname.h> | 20 #include <sys/utsname.h> |
| 21 #include <sys/wait.h> | 21 #include <sys/wait.h> |
| 22 | 22 |
| 23 #include <new> | 23 #include <new> |
| 24 #include <string> | 24 #include <string> |
| 25 | 25 |
| 26 #include "base/debug_util.h" | 26 #include "base/debug/debugger.h" |
| 27 #include "base/eintr_wrapper.h" | 27 #include "base/eintr_wrapper.h" |
| 28 #include "base/logging.h" | 28 #include "base/logging.h" |
| 29 #include "base/string_util.h" | 29 #include "base/string_util.h" |
| 30 #include "base/sys_info.h" | 30 #include "base/sys_info.h" |
| 31 #include "base/sys_string_conversions.h" | 31 #include "base/sys_string_conversions.h" |
| 32 #include "base/time.h" | 32 #include "base/time.h" |
| 33 #include "third_party/apple_apsl/CFBase.h" | 33 #include "third_party/apple_apsl/CFBase.h" |
| 34 #include "third_party/apple_apsl/malloc.h" | 34 #include "third_party/apple_apsl/malloc.h" |
| 35 | 35 |
| 36 namespace base { | 36 namespace base { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 exec_name_end - last_slash - 1); | 159 exec_name_end - last_slash - 1); |
| 160 // Start w/ the next entry next time through | 160 // Start w/ the next entry next time through |
| 161 ++index_of_kinfo_proc_; | 161 ++index_of_kinfo_proc_; |
| 162 // Done | 162 // Done |
| 163 return true; | 163 return true; |
| 164 } | 164 } |
| 165 return false; | 165 return false; |
| 166 } | 166 } |
| 167 | 167 |
| 168 bool NamedProcessIterator::IncludeEntry() { | 168 bool NamedProcessIterator::IncludeEntry() { |
| 169 return (base::SysWideToUTF8(executable_name_) == entry().exe_file() && | 169 return (SysWideToUTF8(executable_name_) == entry().exe_file() && |
| 170 ProcessIterator::IncludeEntry()); | 170 ProcessIterator::IncludeEntry()); |
| 171 } | 171 } |
| 172 | 172 |
| 173 | 173 |
| 174 // ------------------------------------------------------------------------ | 174 // ------------------------------------------------------------------------ |
| 175 // NOTE: about ProcessMetrics | 175 // NOTE: about ProcessMetrics |
| 176 // | 176 // |
| 177 // Getting a mach task from a pid for another process requires permissions in | 177 // Getting a mach task from a pid for another process requires permissions in |
| 178 // general, so there doesn't really seem to be a way to do these (and spinning | 178 // general, so there doesn't really seem to be a way to do these (and spinning |
| 179 // up ps to fetch each stats seems dangerous to put in a base api for anyone to | 179 // up ps to fetch each stats seems dangerous to put in a base api for anyone to |
| 180 // call). Child processes ipc their port, so return something if available, | 180 // call). Child processes ipc their port, so return something if available, |
| 181 // otherwise return 0. | 181 // otherwise return 0. |
| 182 // | 182 // |
| 183 | 183 |
| 184 ProcessMetrics::ProcessMetrics(ProcessHandle process, | 184 ProcessMetrics::ProcessMetrics(ProcessHandle process, |
| 185 ProcessMetrics::PortProvider* port_provider) | 185 ProcessMetrics::PortProvider* port_provider) |
| 186 : process_(process), | 186 : process_(process), |
| 187 last_time_(0), | 187 last_time_(0), |
| 188 last_system_time_(0), | 188 last_system_time_(0), |
| 189 port_provider_(port_provider) { | 189 port_provider_(port_provider) { |
| 190 processor_count_ = base::SysInfo::NumberOfProcessors(); | 190 processor_count_ = SysInfo::NumberOfProcessors(); |
| 191 } | 191 } |
| 192 | 192 |
| 193 // static | 193 // static |
| 194 ProcessMetrics* ProcessMetrics::CreateProcessMetrics( | 194 ProcessMetrics* ProcessMetrics::CreateProcessMetrics( |
| 195 ProcessHandle process, | 195 ProcessHandle process, |
| 196 ProcessMetrics::PortProvider* port_provider) { | 196 ProcessMetrics::PortProvider* port_provider) { |
| 197 return new ProcessMetrics(process, port_provider); | 197 return new ProcessMetrics(process, port_provider); |
| 198 } | 198 } |
| 199 | 199 |
| 200 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { | 200 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 malloc_type g_old_malloc_purgeable; | 395 malloc_type g_old_malloc_purgeable; |
| 396 calloc_type g_old_calloc_purgeable; | 396 calloc_type g_old_calloc_purgeable; |
| 397 valloc_type g_old_valloc_purgeable; | 397 valloc_type g_old_valloc_purgeable; |
| 398 realloc_type g_old_realloc_purgeable; | 398 realloc_type g_old_realloc_purgeable; |
| 399 memalign_type g_old_memalign_purgeable; | 399 memalign_type g_old_memalign_purgeable; |
| 400 | 400 |
| 401 void* oom_killer_malloc(struct _malloc_zone_t* zone, | 401 void* oom_killer_malloc(struct _malloc_zone_t* zone, |
| 402 size_t size) { | 402 size_t size) { |
| 403 void* result = g_old_malloc(zone, size); | 403 void* result = g_old_malloc(zone, size); |
| 404 if (!result && size) | 404 if (!result && size) |
| 405 DebugUtil::BreakDebugger(); | 405 debugger::BreakDebugger(); |
| 406 return result; | 406 return result; |
| 407 } | 407 } |
| 408 | 408 |
| 409 void* oom_killer_calloc(struct _malloc_zone_t* zone, | 409 void* oom_killer_calloc(struct _malloc_zone_t* zone, |
| 410 size_t num_items, | 410 size_t num_items, |
| 411 size_t size) { | 411 size_t size) { |
| 412 void* result = g_old_calloc(zone, num_items, size); | 412 void* result = g_old_calloc(zone, num_items, size); |
| 413 if (!result && num_items && size) | 413 if (!result && num_items && size) |
| 414 DebugUtil::BreakDebugger(); | 414 debugger::BreakDebugger(); |
| 415 return result; | 415 return result; |
| 416 } | 416 } |
| 417 | 417 |
| 418 void* oom_killer_valloc(struct _malloc_zone_t* zone, | 418 void* oom_killer_valloc(struct _malloc_zone_t* zone, |
| 419 size_t size) { | 419 size_t size) { |
| 420 void* result = g_old_valloc(zone, size); | 420 void* result = g_old_valloc(zone, size); |
| 421 if (!result && size) | 421 if (!result && size) |
| 422 DebugUtil::BreakDebugger(); | 422 debugger::BreakDebugger(); |
| 423 return result; | 423 return result; |
| 424 } | 424 } |
| 425 | 425 |
| 426 void* oom_killer_realloc(struct _malloc_zone_t* zone, | 426 void* oom_killer_realloc(struct _malloc_zone_t* zone, |
| 427 void* ptr, | 427 void* ptr, |
| 428 size_t size) { | 428 size_t size) { |
| 429 void* result = g_old_realloc(zone, ptr, size); | 429 void* result = g_old_realloc(zone, ptr, size); |
| 430 if (!result && size) | 430 if (!result && size) |
| 431 DebugUtil::BreakDebugger(); | 431 debugger::BreakDebugger(); |
| 432 return result; | 432 return result; |
| 433 } | 433 } |
| 434 | 434 |
| 435 void* oom_killer_memalign(struct _malloc_zone_t* zone, | 435 void* oom_killer_memalign(struct _malloc_zone_t* zone, |
| 436 size_t alignment, | 436 size_t alignment, |
| 437 size_t size) { | 437 size_t size) { |
| 438 void* result = g_old_memalign(zone, alignment, size); | 438 void* result = g_old_memalign(zone, alignment, size); |
| 439 // Only die if posix_memalign would have returned ENOMEM, since there are | 439 // Only die if posix_memalign would have returned ENOMEM, since there are |
| 440 // other reasons why NULL might be returned (see | 440 // other reasons why NULL might be returned (see |
| 441 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). | 441 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). |
| 442 if (!result && size && alignment >= sizeof(void*) | 442 if (!result && size && alignment >= sizeof(void*) |
| 443 && (alignment & (alignment - 1)) == 0) { | 443 && (alignment & (alignment - 1)) == 0) { |
| 444 DebugUtil::BreakDebugger(); | 444 debugger::BreakDebugger(); |
| 445 } | 445 } |
| 446 return result; | 446 return result; |
| 447 } | 447 } |
| 448 | 448 |
| 449 void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone, | 449 void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone, |
| 450 size_t size) { | 450 size_t size) { |
| 451 void* result = g_old_malloc_purgeable(zone, size); | 451 void* result = g_old_malloc_purgeable(zone, size); |
| 452 if (!result && size) | 452 if (!result && size) |
| 453 DebugUtil::BreakDebugger(); | 453 debugger::BreakDebugger(); |
| 454 return result; | 454 return result; |
| 455 } | 455 } |
| 456 | 456 |
| 457 void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone, | 457 void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone, |
| 458 size_t num_items, | 458 size_t num_items, |
| 459 size_t size) { | 459 size_t size) { |
| 460 void* result = g_old_calloc_purgeable(zone, num_items, size); | 460 void* result = g_old_calloc_purgeable(zone, num_items, size); |
| 461 if (!result && num_items && size) | 461 if (!result && num_items && size) |
| 462 DebugUtil::BreakDebugger(); | 462 debugger::BreakDebugger(); |
| 463 return result; | 463 return result; |
| 464 } | 464 } |
| 465 | 465 |
| 466 void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone, | 466 void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone, |
| 467 size_t size) { | 467 size_t size) { |
| 468 void* result = g_old_valloc_purgeable(zone, size); | 468 void* result = g_old_valloc_purgeable(zone, size); |
| 469 if (!result && size) | 469 if (!result && size) |
| 470 DebugUtil::BreakDebugger(); | 470 debugger::BreakDebugger(); |
| 471 return result; | 471 return result; |
| 472 } | 472 } |
| 473 | 473 |
| 474 void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone, | 474 void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone, |
| 475 void* ptr, | 475 void* ptr, |
| 476 size_t size) { | 476 size_t size) { |
| 477 void* result = g_old_realloc_purgeable(zone, ptr, size); | 477 void* result = g_old_realloc_purgeable(zone, ptr, size); |
| 478 if (!result && size) | 478 if (!result && size) |
| 479 DebugUtil::BreakDebugger(); | 479 debugger::BreakDebugger(); |
| 480 return result; | 480 return result; |
| 481 } | 481 } |
| 482 | 482 |
| 483 void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone, | 483 void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone, |
| 484 size_t alignment, | 484 size_t alignment, |
| 485 size_t size) { | 485 size_t size) { |
| 486 void* result = g_old_memalign_purgeable(zone, alignment, size); | 486 void* result = g_old_memalign_purgeable(zone, alignment, size); |
| 487 // Only die if posix_memalign would have returned ENOMEM, since there are | 487 // Only die if posix_memalign would have returned ENOMEM, since there are |
| 488 // other reasons why NULL might be returned (see | 488 // other reasons why NULL might be returned (see |
| 489 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). | 489 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). |
| 490 if (!result && size && alignment >= sizeof(void*) | 490 if (!result && size && alignment >= sizeof(void*) |
| 491 && (alignment & (alignment - 1)) == 0) { | 491 && (alignment & (alignment - 1)) == 0) { |
| 492 DebugUtil::BreakDebugger(); | 492 debugger::BreakDebugger(); |
| 493 } | 493 } |
| 494 return result; | 494 return result; |
| 495 } | 495 } |
| 496 | 496 |
| 497 // === C++ operator new === | 497 // === C++ operator new === |
| 498 | 498 |
| 499 void oom_killer_new() { | 499 void oom_killer_new() { |
| 500 DebugUtil::BreakDebugger(); | 500 debugger::BreakDebugger(); |
| 501 } | 501 } |
| 502 | 502 |
| 503 // === Core Foundation CFAllocators === | 503 // === Core Foundation CFAllocators === |
| 504 | 504 |
| 505 typedef ChromeCFAllocator* ChromeCFAllocatorRef; | 505 typedef ChromeCFAllocator* ChromeCFAllocatorRef; |
| 506 | 506 |
| 507 CFAllocatorAllocateCallBack g_old_cfallocator_system_default; | 507 CFAllocatorAllocateCallBack g_old_cfallocator_system_default; |
| 508 CFAllocatorAllocateCallBack g_old_cfallocator_malloc; | 508 CFAllocatorAllocateCallBack g_old_cfallocator_malloc; |
| 509 CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone; | 509 CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone; |
| 510 | 510 |
| 511 void* oom_killer_cfallocator_system_default(CFIndex alloc_size, | 511 void* oom_killer_cfallocator_system_default(CFIndex alloc_size, |
| 512 CFOptionFlags hint, | 512 CFOptionFlags hint, |
| 513 void* info) { | 513 void* info) { |
| 514 void* result = g_old_cfallocator_system_default(alloc_size, hint, info); | 514 void* result = g_old_cfallocator_system_default(alloc_size, hint, info); |
| 515 if (!result) | 515 if (!result) |
| 516 DebugUtil::BreakDebugger(); | 516 debugger::BreakDebugger(); |
| 517 return result; | 517 return result; |
| 518 } | 518 } |
| 519 | 519 |
| 520 void* oom_killer_cfallocator_malloc(CFIndex alloc_size, | 520 void* oom_killer_cfallocator_malloc(CFIndex alloc_size, |
| 521 CFOptionFlags hint, | 521 CFOptionFlags hint, |
| 522 void* info) { | 522 void* info) { |
| 523 void* result = g_old_cfallocator_malloc(alloc_size, hint, info); | 523 void* result = g_old_cfallocator_malloc(alloc_size, hint, info); |
| 524 if (!result) | 524 if (!result) |
| 525 DebugUtil::BreakDebugger(); | 525 debugger::BreakDebugger(); |
| 526 return result; | 526 return result; |
| 527 } | 527 } |
| 528 | 528 |
| 529 void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size, | 529 void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size, |
| 530 CFOptionFlags hint, | 530 CFOptionFlags hint, |
| 531 void* info) { | 531 void* info) { |
| 532 void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info); | 532 void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info); |
| 533 if (!result) | 533 if (!result) |
| 534 DebugUtil::BreakDebugger(); | 534 debugger::BreakDebugger(); |
| 535 return result; | 535 return result; |
| 536 } | 536 } |
| 537 | 537 |
| 538 // === Cocoa NSObject allocation === | 538 // === Cocoa NSObject allocation === |
| 539 | 539 |
| 540 typedef id (*allocWithZone_t)(id, SEL, NSZone*); | 540 typedef id (*allocWithZone_t)(id, SEL, NSZone*); |
| 541 allocWithZone_t g_old_allocWithZone; | 541 allocWithZone_t g_old_allocWithZone; |
| 542 | 542 |
| 543 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) | 543 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) |
| 544 { | 544 { |
| 545 id result = g_old_allocWithZone(self, _cmd, zone); | 545 id result = g_old_allocWithZone(self, _cmd, zone); |
| 546 if (!result) | 546 if (!result) |
| 547 DebugUtil::BreakDebugger(); | 547 debugger::BreakDebugger(); |
| 548 return result; | 548 return result; |
| 549 } | 549 } |
| 550 | 550 |
| 551 } // namespace | 551 } // namespace |
| 552 | 552 |
| 553 malloc_zone_t* GetPurgeableZone() { | 553 malloc_zone_t* GetPurgeableZone() { |
| 554 // malloc_default_purgeable_zone only exists on >= 10.6. Use dlsym to grab it | 554 // malloc_default_purgeable_zone only exists on >= 10.6. Use dlsym to grab it |
| 555 // at runtime because it may not be present in the SDK used for compilation. | 555 // at runtime because it may not be present in the SDK used for compilation. |
| 556 typedef malloc_zone_t* (*malloc_default_purgeable_zone_t)(void); | 556 typedef malloc_zone_t* (*malloc_default_purgeable_zone_t)(void); |
| 557 malloc_default_purgeable_zone_t malloc_purgeable_zone = | 557 malloc_default_purgeable_zone_t malloc_purgeable_zone = |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 @selector(allocWithZone:)); | 754 @selector(allocWithZone:)); |
| 755 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( | 755 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( |
| 756 method_getImplementation(orig_method)); | 756 method_getImplementation(orig_method)); |
| 757 CHECK(g_old_allocWithZone) | 757 CHECK(g_old_allocWithZone) |
| 758 << "Failed to get allocWithZone allocation function."; | 758 << "Failed to get allocWithZone allocation function."; |
| 759 method_setImplementation(orig_method, | 759 method_setImplementation(orig_method, |
| 760 reinterpret_cast<IMP>(oom_killer_allocWithZone)); | 760 reinterpret_cast<IMP>(oom_killer_allocWithZone)); |
| 761 } | 761 } |
| 762 | 762 |
| 763 } // namespace base | 763 } // namespace base |
| OLD | NEW |