Apache Mesos
proc.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_PROC_HPP__
14 #define __STOUT_PROC_HPP__
15 
16 // This file contains linux-only utilities for /proc.
17 #ifndef __linux__
18 #error "stout/proc.hpp is only available on Linux systems."
19 #endif
20 
21 #include <errno.h>
22 #include <signal.h>
23 
24 #include <sys/types.h> // For pid_t.
25 
26 #include <fstream>
27 #include <list>
28 #include <queue>
29 #include <set>
30 #include <sstream> // For 'std::istringstream'.
31 #include <string>
32 #include <vector>
33 
34 #include <stout/error.hpp>
35 #include <stout/foreach.hpp>
36 #include <stout/none.hpp>
37 #include <stout/numify.hpp>
38 #include <stout/option.hpp>
39 #include <stout/path.hpp>
40 #include <stout/strings.hpp>
41 #include <stout/try.hpp>
42 
43 #include <stout/os/exists.hpp>
44 #include <stout/os/ls.hpp>
45 #include <stout/os/read.hpp>
46 
47 namespace proc {
48 
49 // Snapshot of a process (modeled after /proc/[pid]/stat).
50 // For more information, see:
51 // http://www.kernel.org/doc/Documentation/filesystems/proc.txt
53 {
55  pid_t _pid,
56  const std::string& _comm,
57  char _state,
58  pid_t _ppid,
59  pid_t _pgrp,
60  pid_t _session,
61  int _tty_nr,
62  pid_t _tpgid,
63  unsigned int _flags,
64  unsigned long _minflt,
65  unsigned long _cminflt,
66  unsigned long _majflt,
67  unsigned long _cmajflt,
68  unsigned long _utime,
69  unsigned long _stime,
70  long _cutime,
71  long _cstime,
72  long _priority,
73  long _nice,
74  long _num_threads,
75  long _itrealvalue,
76  unsigned long long _starttime,
77  unsigned long _vsize,
78  long _rss,
79  unsigned long _rsslim,
80  unsigned long _startcode,
81  unsigned long _endcode,
82  unsigned long _startstack,
83  unsigned long _kstkeip,
84  unsigned long _signal,
85  unsigned long _blocked,
86  unsigned long _sigcatch,
87  unsigned long _wchan,
88  unsigned long _nswap,
89  unsigned long _cnswap)
90  : pid(_pid),
91  comm(_comm),
92  state(_state),
93  ppid(_ppid),
94  pgrp(_pgrp),
95  session(_session),
96  tty_nr(_tty_nr),
97  tpgid(_tpgid),
98  flags(_flags),
99  minflt(_minflt),
100  cminflt(_cminflt),
101  majflt(_majflt),
102  cmajflt(_cmajflt),
103  utime(_utime),
104  stime(_stime),
105  cutime(_cutime),
106  cstime(_cstime),
107  priority(_priority),
108  nice(_nice),
109  num_threads(_num_threads),
110  itrealvalue(_itrealvalue),
111  starttime(_starttime),
112  vsize(_vsize),
113  rss(_rss),
114  rsslim(_rsslim),
115  startcode(_startcode),
116  endcode(_endcode),
117  startstack(_startstack),
118  kstkeip(_kstkeip),
119  signal(_signal),
120  blocked(_blocked),
121  sigcatch(_sigcatch),
122  wchan(_wchan),
123  nswap(_nswap),
124  cnswap(_cnswap) {}
125 
126  const pid_t pid;
127  const std::string comm;
128  const char state;
129  const pid_t ppid;
130  const pid_t pgrp;
131  const pid_t session;
132  const int tty_nr;
133  const pid_t tpgid;
134  const unsigned int flags;
135  const unsigned long minflt;
136  const unsigned long cminflt;
137  const unsigned long majflt;
138  const unsigned long cmajflt;
139  const unsigned long utime;
140  const unsigned long stime;
141  const long cutime;
142  const long cstime;
143  const long priority;
144  const long nice;
145  const long num_threads;
146  const long itrealvalue;
147  const unsigned long long starttime;
148  const unsigned long vsize;
149  const long rss;
150  const unsigned long rsslim;
151  const unsigned long startcode;
152  const unsigned long endcode;
153  const unsigned long startstack;
154  const unsigned long kstkeip;
155  const unsigned long signal;
156  const unsigned long blocked;
157  const unsigned long sigcatch;
158  const unsigned long wchan;
159  const unsigned long nswap;
160  const unsigned long cnswap;
161 };
162 
163 
164 // Returns the process statistics from /proc/[pid]/stat.
165 // The return value is None if the process does not exist.
167 {
168  std::string path = "/proc/" + stringify(pid) + "/stat";
169 
171  if (read.isError()) {
172  // Need to check if file exists AFTER we open it to guarantee
173  // process hasn't terminated.
174  if (!os::exists(path)) {
175  return None();
176  }
177  return Error(read.error());
178  }
179 
180  std::istringstream data(read.get());
181 
182  std::string comm;
183  char state;
184  pid_t ppid;
185  pid_t pgrp;
186  pid_t session;
187  int tty_nr;
188  pid_t tpgid;
189  unsigned int flags;
190  unsigned long minflt;
191  unsigned long cminflt;
192  unsigned long majflt;
193  unsigned long cmajflt;
194  unsigned long utime;
195  unsigned long stime;
196  long cutime;
197  long cstime;
198  long priority;
199  long nice;
200  long num_threads;
201  long itrealvalue;
202  unsigned long long starttime;
203  unsigned long vsize;
204  long rss;
205  unsigned long rsslim;
206  unsigned long startcode;
207  unsigned long endcode;
208  unsigned long startstack;
209  unsigned long kstkeip;
210  unsigned long signal;
211  unsigned long blocked;
212  unsigned long sigcatch;
213  unsigned long wchan;
214  unsigned long nswap;
215  unsigned long cnswap;
216 
217  // NOTE: The following are unused for now.
218  // int exit_signal;
219  // int processor;
220  // unsigned int rt_priority;
221  // unsigned int policy;
222  // unsigned long long delayacct_blkio_ticks;
223  // unsigned long guest_time;
224  // unsigned int cguest_time;
225 
226  std::string _; // For ignoring fields.
227 
228  // Parse all fields from stat.
229  data >> _ >> comm >> state >> ppid >> pgrp >> session >> tty_nr
230  >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
231  >> utime >> stime >> cutime >> cstime >> priority >> nice
232  >> num_threads >> itrealvalue >> starttime >> vsize >> rss
233  >> rsslim >> startcode >> endcode >> startstack >> kstkeip
234  >> signal >> blocked >> sigcatch >> wchan >> nswap >> cnswap;
235 
236  // Check for any read/parse errors.
237  if (data.fail() && !data.eof()) {
238  return Error("Failed to read/parse '" + path + "'");
239  }
240 
241  // Remove the parentheses that is wrapped around 'comm' (when
242  // printing out the process in a process tree we use parentheses to
243  // indicate "zombie" processes).
244  comm = strings::remove(comm, "(", strings::PREFIX);
245  comm = strings::remove(comm, ")", strings::SUFFIX);
246 
247  return ProcessStatus(pid, comm, state, ppid, pgrp, session, tty_nr,
248  tpgid, flags, minflt, cminflt, majflt, cmajflt,
249  utime, stime, cutime, cstime, priority, nice,
250  num_threads, itrealvalue, starttime, vsize, rss,
251  rsslim, startcode, endcode, startstack, kstkeip,
252  signal, blocked, sigcatch, wchan, nswap, cnswap);
253 }
254 
255 
257 {
258  const std::string path = pid.isSome()
259  ? "/proc/" + stringify(pid.get()) + "/cmdline"
260  : "/proc/cmdline";
261 
262  std::ifstream file(path.c_str());
263 
264  if (!file.is_open()) {
265  // Need to check if file exists AFTER we open it to guarantee
266  // process hasn't terminated (or if it has, we at least have a
267  // file which the kernel _should_ respect until a close).
268  if (!os::exists(path)) {
269  return None();
270  }
271  return Error("Failed to open '" + path + "'");
272  }
273 
274  std::stringbuf buffer;
275 
276  do {
277  // Read each argument in "argv", separated by null bytes.
278  file.get(buffer, '\0');
279 
280  // Check for any read errors.
281  if (file.fail() && !file.eof()) {
282  return Error("Failed to read '" + path + "'");
283  } else if (!file.eof()) {
284  file.get(); // Read the null byte.
285  buffer.sputc(' '); // Put a space between each command line argument.
286  }
287  } while (!file.eof());
288 
289  return buffer.str();
290 }
291 
292 
293 // Reads from /proc and returns a list of all running processes.
295 {
296  std::set<pid_t> pids;
297 
298  Try<std::list<std::string>> entries = os::ls("/proc");
299  if (entries.isError()) {
300  return Error("Failed to list files in /proc: " + entries.error());
301  }
302 
303  foreach (const std::string& entry, entries.get()) {
304  Try<pid_t> pid = numify<pid_t>(entry);
305  if (pid.isSome()) {
306  pids.insert(pid.get()); // Ignore entries that can't be numified.
307  }
308  }
309 
310  if (!pids.empty()) {
311  return pids;
312  }
313 
314  return Error("Failed to determine pids from /proc");
315 }
316 
317 
318 // Reads from /proc/<pid>/task/* and returns a list of threads ids for pid.
320 {
321  const std::string path = path::join("/proc", stringify(pid), "task");
322 
323  std::set<pid_t> threads;
324 
325  Try<std::list<std::string>> entries = os::ls(path);
326  if (entries.isError()) {
327  return Error("Failed to list files in " + path + ": " + entries.error());
328  }
329 
330  foreach (const std::string& entry, entries.get()) {
331  Try<pid_t> thread = numify<pid_t>(entry);
332  if (thread.isSome()) {
333  threads.insert(thread.get());
334  }
335  }
336 
337  if (!threads.empty()) {
338  return threads;
339  }
340 
341  return Error("Failed to determine thread ids from /proc");
342 }
343 
344 
345 // Snapshot of a system (modeled after /proc/stat).
347 {
348  SystemStatus(unsigned long long _btime) : btime(_btime) {}
349 
350  const unsigned long long btime; // Boot time.
351  // TODO(benh): Add more.
352 };
353 
354 
355 // Returns the system statistics from /proc/stat.
357 {
358  unsigned long long btime = 0;
359 
360  std::ifstream file("/proc/stat");
361 
362  if (!file.is_open()) {
363  return Error("Failed to open /proc/stat");
364  }
365 
366  std::string line;
367  while (std::getline(file, line)) {
368  if (line.find("btime ") == 0) {
369  Try<unsigned long long> number =
370  numify<unsigned long long>(line.substr(6));
371 
372  if (number.isError()) {
373  return Error("Failed to parse /proc/stat: " + number.error());
374  }
375 
376  btime = number.get();
377  break;
378  }
379  }
380 
381  if (file.fail() && !file.eof()) {
382  return Error("Failed to read /proc/stat");
383  }
384 
385  return SystemStatus(btime);
386 }
387 
388 
389 // Representation of a processor (really an execution unit since this
390 // captures "hardware threads" as well) modeled after /proc/cpuinfo.
391 struct CPU
392 {
393  CPU(unsigned int _id, unsigned int _core, unsigned int _socket)
394  : id(_id), core(_core), socket(_socket) {}
395 
396  // These are non-const because we need the default assignment operator.
397  unsigned int id; // "processor"
398  unsigned int core; // "core id"
399  unsigned int socket; // "physical id"
400 };
401 
402 
403 inline bool operator==(const CPU& lhs, const CPU& rhs)
404 {
405  return (lhs.id == rhs.id) && (lhs.core == rhs.core) &&
406  (lhs.socket == rhs.socket);
407 }
408 
409 
410 inline bool operator<(const CPU& lhs, const CPU& rhs)
411 {
412  // Sort by (socket, core, id).
413  if (lhs.socket != rhs.socket) {
414  return lhs.socket < rhs.socket;
415  }
416 
417  // On the same socket.
418  if (lhs.core != rhs.core) {
419  return lhs.core < rhs.core;
420  }
421 
422  // On the same core.
423  return lhs.id < rhs.id;
424 }
425 
426 
427 inline std::ostream& operator<<(std::ostream& stream, const CPU& cpu)
428 {
429  return stream << "CPU (id:" << cpu.id << ", "
430  << "core:" << cpu.core << ", "
431  << "socket:" << cpu.socket << ")";
432 }
433 
434 
435 // Reads from /proc/cpuinfo and returns a list of CPUs.
437 {
438  std::list<CPU> results;
439 
440  std::ifstream file("/proc/cpuinfo");
441 
442  if (!file.is_open()) {
443  return Error("Failed to open /proc/cpuinfo");
444  }
445 
446  // Placeholders as we parse the file.
450 
451  std::string line;
452  while (std::getline(file, line)) {
453  if (line.find("processor") == 0 ||
454  line.find("physical id") == 0 ||
455  line.find("core id") == 0) {
456  // Get out and parse the value.
457  std::vector<std::string> tokens = strings::tokenize(line, ": ");
458 
459  if (tokens.size() < 2) {
460  return Error("Unexpected format in /proc/cpuinfo: " +
461  stringify(tokens));
462  }
463 
464  Try<unsigned int> value = numify<unsigned int>(tokens.back());
465  if (value.isError()) {
466  return Error(value.error());
467  }
468 
469  // Now save the value.
470  if (line.find("processor") == 0) {
471  if (id.isSome()) {
472  // The physical id and core id are not present in this case.
473  results.push_back(CPU(id.get(), 0, 0));
474  }
475  id = value.get();
476  } else if (line.find("physical id") == 0) {
477  if (socket.isSome()) {
478  return Error("Unexpected format in /proc/cpuinfo");
479  }
480  socket = value.get();
481  } else if (line.find("core id") == 0) {
482  if (core.isSome()) {
483  return Error("Unexpected format in /proc/cpuinfo");
484  }
485  core = value.get();
486  }
487 
488  // And finally create a CPU if we have all the information.
489  if (id.isSome() && core.isSome() && socket.isSome()) {
490  results.push_back(CPU(id.get(), core.get(), socket.get()));
491  id = None();
492  core = None();
493  socket = None();
494  }
495  }
496  }
497 
498  // Add the last processor if the physical id and core id were not present.
499  if (id.isSome()) {
500  // The physical id and core id are not present.
501  results.push_back(CPU(id.get(), 0, 0));
502  }
503 
504  if (file.fail() && !file.eof()) {
505  return Error("Failed to read /proc/cpuinfo");
506  }
507 
508  return results;
509 }
510 
511 } // namespace proc {
512 
513 #endif // __STOUT_PROC_HPP__
CPU(unsigned int _id, unsigned int _core, unsigned int _socket)
Definition: proc.hpp:393
Definition: path.hpp:29
Definition: proc.hpp:52
bool exists(const std::string &path)
Definition: exists.hpp:26
const pid_t pgrp
Definition: proc.hpp:130
const unsigned long signal
Definition: proc.hpp:155
const unsigned long cmajflt
Definition: proc.hpp:138
Definition: errorbase.hpp:36
const pid_t tpgid
Definition: proc.hpp:133
const unsigned long vsize
Definition: proc.hpp:148
const unsigned long long btime
Definition: proc.hpp:350
const unsigned long minflt
Definition: proc.hpp:135
T & get()&
Definition: try.hpp:80
Definition: check.hpp:33
const unsigned long majflt
Definition: proc.hpp:137
const unsigned long cnswap
Definition: proc.hpp:160
bool operator==(const CPU &lhs, const CPU &rhs)
Definition: proc.hpp:403
unsigned int core
Definition: proc.hpp:398
unsigned int id
Definition: proc.hpp:397
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: uuid.hpp:33
const pid_t ppid
Definition: proc.hpp:129
const unsigned long cminflt
Definition: proc.hpp:136
bool operator<(const CPU &lhs, const CPU &rhs)
Definition: proc.hpp:410
const unsigned long nswap
Definition: proc.hpp:159
const long num_threads
Definition: proc.hpp:145
std::string join(const std::string &path1, const std::string &path2, const char _separator=os::PATH_SEPARATOR)
Definition: path.hpp:116
Definition: check.hpp:30
const unsigned long endcode
Definition: proc.hpp:152
const long cutime
Definition: proc.hpp:141
const unsigned long blocked
Definition: proc.hpp:156
bool isSome() const
Definition: option.hpp:116
std::string remove(const std::string &from, const std::string &substring, Mode mode=ANY)
Definition: strings.hpp:41
const long rss
Definition: proc.hpp:149
const unsigned long startcode
Definition: proc.hpp:151
const unsigned long wchan
Definition: proc.hpp:158
DWORD pid_t
Definition: windows.hpp:181
std::vector< std::string > tokenize(const std::string &s, const std::string &delims, const Option< size_t > &maxTokens=None())
Definition: strings.hpp:139
const long priority
Definition: proc.hpp:143
Definition: strings.hpp:36
URI file(const std::string &path)
Creates a file URI with the given path on the local host.
Definition: file.hpp:33
const unsigned long utime
Definition: proc.hpp:139
SystemStatus(unsigned long long _btime)
Definition: proc.hpp:348
const long cstime
Definition: proc.hpp:142
Try< std::set< pid_t > > pids()
Definition: proc.hpp:294
const unsigned long long starttime
Definition: proc.hpp:147
bool isSome() const
Definition: try.hpp:77
const T & get() const &
Definition: option.hpp:119
Try< std::set< pid_t > > threads(pid_t pid)
Definition: proc.hpp:319
const pid_t session
Definition: proc.hpp:131
const unsigned long startstack
Definition: proc.hpp:153
std::ostream & operator<<(std::ostream &stream, const CPU &cpu)
Definition: proc.hpp:427
static Try error(const E &e)
Definition: try.hpp:43
const char state
Definition: proc.hpp:128
const unsigned int flags
Definition: proc.hpp:134
Result< std::string > read(int_fd fd, size_t size)
Definition: read.hpp:55
Result< std::string > cmdline(const Option< pid_t > &pid=None())
Definition: proc.hpp:256
const pid_t pid
Definition: proc.hpp:126
Definition: none.hpp:27
bool isError() const
Definition: try.hpp:78
Result< Credentials > read(const Path &path)
Definition: credentials.hpp:35
const long itrealvalue
Definition: proc.hpp:146
const std::string comm
Definition: proc.hpp:127
const long nice
Definition: proc.hpp:144
const unsigned long rsslim
Definition: proc.hpp:150
unsigned int socket
Definition: proc.hpp:399
const unsigned long stime
Definition: proc.hpp:140
ProcessStatus(pid_t _pid, const std::string &_comm, char _state, pid_t _ppid, pid_t _pgrp, pid_t _session, int _tty_nr, pid_t _tpgid, unsigned int _flags, unsigned long _minflt, unsigned long _cminflt, unsigned long _majflt, unsigned long _cmajflt, unsigned long _utime, unsigned long _stime, long _cutime, long _cstime, long _priority, long _nice, long _num_threads, long _itrealvalue, unsigned long long _starttime, unsigned long _vsize, long _rss, unsigned long _rsslim, unsigned long _startcode, unsigned long _endcode, unsigned long _startstack, unsigned long _kstkeip, unsigned long _signal, unsigned long _blocked, unsigned long _sigcatch, unsigned long _wchan, unsigned long _nswap, unsigned long _cnswap)
Definition: proc.hpp:54
const unsigned long sigcatch
Definition: proc.hpp:157
Definition: proc.hpp:346
const int tty_nr
Definition: proc.hpp:132
Definition: proc.hpp:47
Try< std::list< CPU > > cpus()
Definition: proc.hpp:436
Try< Netlink< struct nl_sock > > socket(int protocol=NETLINK_ROUTE)
Definition: internal.hpp:91
std::string stringify(int flags)
const unsigned long kstkeip
Definition: proc.hpp:154
Definition: proc.hpp:391
Definition: parse.hpp:33
Try< std::list< std::string > > ls(const std::string &directory)
Definition: ls.hpp:29
Definition: strings.hpp:35