Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: base/process_util_mac.mm

Issue 1689012: Move common code into process_util.cc (Closed)
Patch Set: More fixes Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/process_util_linux.cc ('k') | base/process_util_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <mach/mach.h> 10 #include <mach/mach.h>
(...skipping 30 matching lines...) Expand all
41 EXC_MASK_BREAKPOINT; 41 EXC_MASK_BREAKPOINT;
42 42
43 // Setting the exception port to MACH_PORT_NULL may not be entirely 43 // Setting the exception port to MACH_PORT_NULL may not be entirely
44 // kosher to restore the default exception handler, but in practice, 44 // kosher to restore the default exception handler, but in practice,
45 // it results in the exception port being set to Apple Crash Reporter, 45 // it results in the exception port being set to Apple Crash Reporter,
46 // the desired behavior. 46 // the desired behavior.
47 task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL, 47 task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL,
48 EXCEPTION_DEFAULT, THREAD_STATE_NONE); 48 EXCEPTION_DEFAULT, THREAD_STATE_NONE);
49 } 49 }
50 50
51 NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name, 51 ProcessIterator::ProcessIterator(const ProcessFilter* filter)
52 const ProcessFilter* filter) 52 : index_of_kinfo_proc_(0),
53 : executable_name_(executable_name),
54 index_of_kinfo_proc_(0),
55 filter_(filter) { 53 filter_(filter) {
56 // Get a snapshot of all of my processes (yes, as we loop it can go stale, but 54 // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
57 // but trying to find where we were in a constantly changing list is basically 55 // but trying to find where we were in a constantly changing list is basically
58 // impossible. 56 // impossible.
59 57
60 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() }; 58 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
61 59
62 // Since more processes could start between when we get the size and when 60 // Since more processes could start between when we get the size and when
63 // we get the list, we do a loop to keep trying until we get it. 61 // we get the list, we do a loop to keep trying until we get it.
64 bool done = false; 62 bool done = false;
65 int try_num = 1; 63 int try_num = 1;
66 const int max_tries = 10; 64 const int max_tries = 10;
67 do { 65 do {
68 // Get the size of the buffer 66 // Get the size of the buffer
69 size_t len = 0; 67 size_t len = 0;
70 if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) { 68 if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
71 LOG(ERROR) << "failed to get the size needed for the process list"; 69 LOG(ERROR) << "failed to get the size needed for the process list";
72 kinfo_procs_.resize(0); 70 kinfo_procs_.resize(0);
73 done = true; 71 done = true;
74 } else { 72 } else {
75 size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); 73 size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
76 // Leave some spare room for process table growth (more could show up 74 // Leave some spare room for process table growth (more could show up
77 // between when we check and now) 75 // between when we check and now)
78 num_of_kinfo_proc += 4; 76 num_of_kinfo_proc += 16;
79 kinfo_procs_.resize(num_of_kinfo_proc); 77 kinfo_procs_.resize(num_of_kinfo_proc);
80 len = num_of_kinfo_proc * sizeof(struct kinfo_proc); 78 len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
81 // Load the list of processes 79 // Load the list of processes
82 if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) { 80 if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
83 // If we get a mem error, it just means we need a bigger buffer, so 81 // If we get a mem error, it just means we need a bigger buffer, so
84 // loop around again. Anything else is a real error and give up. 82 // loop around again. Anything else is a real error and give up.
85 if (errno != ENOMEM) { 83 if (errno != ENOMEM) {
86 LOG(ERROR) << "failed to get the process list"; 84 LOG(ERROR) << "failed to get the process list";
87 kinfo_procs_.resize(0); 85 kinfo_procs_.resize(0);
88 done = true; 86 done = true;
89 } 87 }
90 } else { 88 } else {
91 // Got the list, just make sure we're sized exactly right 89 // Got the list, just make sure we're sized exactly right
92 size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); 90 size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
93 kinfo_procs_.resize(num_of_kinfo_proc); 91 kinfo_procs_.resize(num_of_kinfo_proc);
94 done = true; 92 done = true;
95 } 93 }
96 } 94 }
97 } while (!done && (try_num++ < max_tries)); 95 } while (!done && (try_num++ < max_tries));
98 96
99 if (!done) { 97 if (!done) {
100 LOG(ERROR) << "failed to collect the process list in a few tries"; 98 LOG(ERROR) << "failed to collect the process list in a few tries";
101 kinfo_procs_.resize(0); 99 kinfo_procs_.resize(0);
102 } 100 }
103 } 101 }
104 102
105 NamedProcessIterator::~NamedProcessIterator() { 103 ProcessIterator::~ProcessIterator() {
106 } 104 }
107 105
108 const ProcessEntry* NamedProcessIterator::NextProcessEntry() { 106 bool ProcessIterator::CheckForNextProcess() {
109 bool result = false;
110 do {
111 result = CheckForNextProcess();
112 } while (result && !IncludeEntry());
113
114 if (result) {
115 return &entry_;
116 }
117
118 return NULL;
119 }
120
121 bool NamedProcessIterator::CheckForNextProcess() {
122 std::string executable_name_utf8(base::SysWideToUTF8(executable_name_));
123
124 std::string data; 107 std::string data;
125 std::string exec_name;
126
127 for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) { 108 for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
128 kinfo_proc* kinfo = &kinfo_procs_[index_of_kinfo_proc_]; 109 kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
129 110
130 // Skip processes just awaiting collection 111 // Skip processes just awaiting collection
131 if ((kinfo->kp_proc.p_pid > 0) && (kinfo->kp_proc.p_stat == SZOMB)) 112 if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB))
132 continue; 113 continue;
133 114
134 int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo->kp_proc.p_pid }; 115 int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
135 116
136 // Found out what size buffer we need 117 // Find out what size buffer we need.
137 size_t data_len = 0; 118 size_t data_len = 0;
138 if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) { 119 if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
139 LOG(ERROR) << "failed to figure out the buffer size for a commandline"; 120 LOG(ERROR) << "failed to figure out the buffer size for a commandline";
140 continue; 121 continue;
141 } 122 }
142 123
143 data.resize(data_len); 124 data.resize(data_len);
144 if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) { 125 if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
145 LOG(ERROR) << "failed to fetch a commandline"; 126 LOG(ERROR) << "failed to fetch a commandline";
146 continue; 127 continue;
147 } 128 }
148 129
149 // Data starts w/ the full path null termed, so we have to extract just the 130 // Data starts w/ the full path null termed, so we have to extract just the
150 // executable name from the path. 131 // executable name from the path.
151 132
152 size_t exec_name_end = data.find('\0'); 133 size_t exec_name_end = data.find('\0');
153 if (exec_name_end == std::string::npos) { 134 if (exec_name_end == std::string::npos) {
154 LOG(ERROR) << "command line data didn't match expected format"; 135 LOG(ERROR) << "command line data didn't match expected format";
155 continue; 136 continue;
156 } 137 }
138 entry_.pid_ = kinfo.kp_proc.p_pid;
139 entry_.ppid_ = kinfo.kp_eproc.e_ppid;
140 entry_.gid_ = kinfo.kp_eproc.e_pgid;
157 size_t last_slash = data.rfind('/', exec_name_end); 141 size_t last_slash = data.rfind('/', exec_name_end);
158 if (last_slash == std::string::npos) 142 if (last_slash == std::string::npos)
159 exec_name = data.substr(0, exec_name_end); 143 entry_.exe_file_.assign(data, 0, exec_name_end);
160 else 144 else
161 exec_name = data.substr(last_slash + 1, exec_name_end - last_slash - 1); 145 entry_.exe_file_.assign(data, last_slash + 1,
162 146 exec_name_end - last_slash - 1);
163 // Check the name 147 // Start w/ the next entry next time through
164 if (executable_name_utf8 == exec_name) { 148 ++index_of_kinfo_proc_;
165 entry_.pid = kinfo->kp_proc.p_pid; 149 // Done
166 entry_.ppid = kinfo->kp_eproc.e_ppid; 150 return true;
167 base::strlcpy(entry_.szExeFile, exec_name.c_str(),
168 sizeof(entry_.szExeFile));
169 // Start w/ the next entry next time through
170 ++index_of_kinfo_proc_;
171 // Done
172 return true;
173 }
174 } 151 }
175 return false; 152 return false;
176 } 153 }
177 154
178 bool NamedProcessIterator::IncludeEntry() { 155 bool NamedProcessIterator::IncludeEntry() {
179 // Don't need to check the name, we did that w/in CheckForNextProcess. 156 return (base::SysWideToUTF8(executable_name_) == entry().exe_file() &&
180 if (!filter_) 157 ProcessIterator::IncludeEntry());
181 return true;
182 return filter_->Includes(entry_.pid, entry_.ppid);
183 } 158 }
184 159
185 160
186 // ------------------------------------------------------------------------ 161 // ------------------------------------------------------------------------
187 // NOTE: about ProcessMetrics 162 // NOTE: about ProcessMetrics
188 // 163 //
189 // Getting a mach task from a pid for another process requires permissions in 164 // Getting a mach task from a pid for another process requires permissions in
190 // general, so there doesn't really seem to be a way to do these (and spinning 165 // general, so there doesn't really seem to be a way to do these (and spinning
191 // up ps to fetch each stats seems dangerous to put in a base api for anyone to 166 // up ps to fetch each stats seems dangerous to put in a base api for anyone to
192 // call). Child processes ipc their port, so return something if available, 167 // call). Child processes ipc their port, so return something if available,
193 // otherwise return 0. 168 // otherwise return 0.
194 // 169 //
170
171 ProcessMetrics::ProcessMetrics(ProcessHandle process,
172 ProcessMetrics::PortProvider* port_provider)
173 : process_(process),
174 last_time_(0),
175 last_system_time_(0),
176 port_provider_(port_provider) {
177 processor_count_ = base::SysInfo::NumberOfProcessors();
178 }
179
180 // static
181 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
182 ProcessHandle process,
183 ProcessMetrics::PortProvider* port_provider) {
184 return new ProcessMetrics(process, port_provider);
185 }
186
195 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { 187 bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
196 return false; 188 return false;
197 } 189 }
198 190
199 static bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) { 191 static bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) {
200 if (task == MACH_PORT_NULL) 192 if (task == MACH_PORT_NULL)
201 return false; 193 return false;
202 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; 194 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
203 kern_return_t kr = task_info(task, 195 kern_return_t kr = task_info(task,
204 TASK_BASIC_INFO_64, 196 TASK_BASIC_INFO_64,
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 @selector(allocWithZone:)); 569 @selector(allocWithZone:));
578 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( 570 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>(
579 method_getImplementation(orig_method)); 571 method_getImplementation(orig_method));
580 CHECK(g_old_allocWithZone) 572 CHECK(g_old_allocWithZone)
581 << "Failed to get allocWithZone allocation function."; 573 << "Failed to get allocWithZone allocation function.";
582 method_setImplementation(orig_method, 574 method_setImplementation(orig_method,
583 reinterpret_cast<IMP>(oom_killer_allocWithZone)); 575 reinterpret_cast<IMP>(oom_killer_allocWithZone));
584 } 576 }
585 577
586 } // namespace base 578 } // namespace base
OLDNEW
« no previous file with comments | « base/process_util_linux.cc ('k') | base/process_util_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698