PageRenderTime 26ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/3rdparty/stout/include/stout/os/linux.hpp

https://gitlab.com/wilane/mesos
C++ Header | 170 lines | 97 code | 33 blank | 40 comment | 9 complexity | e155a80bb8d2681e41dd7200f7ca2379 MD5 | raw 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. #ifndef __STOUT_OS_POSIX_HPP__
  13. #define __STOUT_OS_POSIX_HPP__
  14. // This file contains Linux-only OS utilities.
  15. #ifndef __linux__
  16. #error "stout/os/linux.hpp is only available on Linux systems."
  17. #endif
  18. #include <sys/types.h> // For pid_t.
  19. #include <list>
  20. #include <queue>
  21. #include <set>
  22. #include <string>
  23. #include <stout/error.hpp>
  24. #include <stout/foreach.hpp>
  25. #include <stout/lambda.hpp>
  26. #include <stout/option.hpp>
  27. #include <stout/proc.hpp>
  28. #include <stout/result.hpp>
  29. #include <stout/try.hpp>
  30. #include <stout/os/pagesize.hpp>
  31. #include <stout/os/process.hpp>
  32. namespace os {
  33. // Helper for clone() which expects an int(void*).
  34. static int childMain(void* _func)
  35. {
  36. const lambda::function<int()>* func =
  37. static_cast<const lambda::function<int()>*> (_func);
  38. return (*func)();
  39. }
  40. inline pid_t clone(const lambda::function<int()>& func, int flags)
  41. {
  42. // Stack for the child.
  43. // - unsigned long long used for best alignment.
  44. // - 8 MiB appears to be the default for "ulimit -s" on OSX and Linux.
  45. //
  46. // NOTE: We need to allocate the stack dynamically. This is because
  47. // glibc's 'clone' will modify the stack passed to it, therefore the
  48. // stack must NOT be shared as multiple 'clone's can be invoked
  49. // simultaneously.
  50. int stackSize = 8 * 1024 * 1024;
  51. unsigned long long *stack =
  52. new unsigned long long[stackSize/sizeof(unsigned long long)];
  53. pid_t pid = ::clone(
  54. childMain,
  55. &stack[stackSize/sizeof(stack[0]) - 1], // stack grows down.
  56. flags,
  57. (void*) &func);
  58. // If CLONE_VM is not set, ::clone would create a process which runs in a
  59. // separate copy of the memory space of the calling process. So we destroy the
  60. // stack here to avoid memory leak. If CLONE_VM is set, ::clone would create a
  61. // thread which runs in the same memory space with the calling process.
  62. if (!(flags & CLONE_VM)) {
  63. delete[] stack;
  64. }
  65. return pid;
  66. }
  67. inline Result<Process> process(pid_t pid)
  68. {
  69. // Page size, used for memory accounting.
  70. static const int pageSize = os::pagesize();
  71. if (pageSize <= 0) {
  72. return Error("Failed to get `os::pagesize`");
  73. }
  74. // Number of clock ticks per second, used for cpu accounting.
  75. static const long ticks = sysconf(_SC_CLK_TCK);
  76. if (ticks <= 0) {
  77. return Error("Failed to get sysconf(_SC_CLK_TCK)");
  78. }
  79. const Result<proc::ProcessStatus> status = proc::status(pid);
  80. if (status.isError()) {
  81. return Error(status.error());
  82. }
  83. if (status.isNone()) {
  84. return None();
  85. }
  86. // There are known bugs with invalid utime / stime values coming
  87. // from /proc/<pid>/stat on some Linux systems.
  88. // See the following thread for details:
  89. // http://mail-archives.apache.org/mod_mbox/incubator-mesos-dev/
  90. // 201307.mbox/%3CCA+2n2er-Nemh0CsKLbHRkaHd=YCrNt17NLUPM2=TtEfsKOw4
  91. // Rg@mail.gmail.com%3E
  92. // These are similar reports:
  93. // http://lkml.indiana.edu/hypermail/linux/kernel/1207.1/01388.html
  94. // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1023214
  95. Try<Duration> utime = Duration::create(status.get().utime / (double) ticks);
  96. Try<Duration> stime = Duration::create(status.get().stime / (double) ticks);
  97. // The command line from 'status.get().comm' is only "arg0" from
  98. // "argv" (i.e., the canonical executable name). To get the entire
  99. // command line we grab '/proc/[pid]/cmdline'.
  100. Result<std::string> cmdline = proc::cmdline(pid);
  101. return Process(status.get().pid,
  102. status.get().ppid,
  103. status.get().pgrp,
  104. status.get().session,
  105. Bytes(status.get().rss * pageSize),
  106. utime.isSome() ? utime.get() : Option<Duration>::none(),
  107. stime.isSome() ? stime.get() : Option<Duration>::none(),
  108. cmdline.isSome() ? cmdline.get() : status.get().comm,
  109. status.get().state == 'Z');
  110. }
  111. inline Try<std::set<pid_t>> pids()
  112. {
  113. return proc::pids();
  114. }
  115. // Returns the total size of main and free memory.
  116. inline Try<Memory> memory()
  117. {
  118. Memory memory;
  119. struct sysinfo info;
  120. if (sysinfo(&info) != 0) {
  121. return ErrnoError();
  122. }
  123. # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 23)
  124. memory.total = Bytes(info.totalram * info.mem_unit);
  125. memory.free = Bytes(info.freeram * info.mem_unit);
  126. memory.totalSwap = Bytes(info.totalswap * info.mem_unit);
  127. memory.freeSwap = Bytes(info.freeswap * info.mem_unit);
  128. # else
  129. memory.total = Bytes(info.totalram);
  130. memory.free = Bytes(info.freeram);
  131. memory.totalSwap = Bytes(info.totalswap);
  132. memory.freeSwap = Bytes(info.freeswap);
  133. # endif
  134. return memory;
  135. }
  136. } // namespace os {
  137. #endif // __STOUT_OS_POSIX_HPP__