• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
19 
20 #include <errno.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 
25 #include <atomic>
26 #include <functional>
27 #include <memory>
28 #include <string>
29 
30 #include "perfetto/base/build_config.h"
31 #include "perfetto/base/compiler.h"
32 #include "perfetto/ext/base/sys_types.h"
33 
34 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
35 // Even if Windows has errno.h, the all syscall-restart behavior does not apply.
36 // Trying to handle EINTR can cause more harm than good if errno is left stale.
37 // Chromium does the same.
38 #define PERFETTO_EINTR(x) (x)
39 #else
40 #define PERFETTO_EINTR(x)                                   \
41   ([&] {                                                    \
42     decltype(x) eintr_wrapper_result;                       \
43     do {                                                    \
44       eintr_wrapper_result = (x);                           \
45     } while (eintr_wrapper_result == -1 && errno == EINTR); \
46     return eintr_wrapper_result;                            \
47   }())
48 #endif
49 
50 namespace perfetto {
51 namespace base {
52 
53 // Do not add new usages of kPageSize, consider using GetSysPageSize() below.
54 // TODO(primiano): over time the semantic of kPageSize became too ambiguous.
55 // Strictly speaking, this constant is incorrect on some new devices where the
56 // page size can be 16K (e.g., crbug.com/1116576). Unfortunately too much code
57 // ended up depending on kPageSize for purposes that are not strictly related
58 // with the kernel's mm subsystem.
59 constexpr size_t kPageSize = 4096;
60 
61 // Returns the system's page size. Use this when dealing with mmap, madvise and
62 // similar mm-related syscalls.
63 uint32_t GetSysPageSize();
64 
65 template <typename T, size_t TSize>
ArraySize(const T (&)[TSize])66 constexpr size_t ArraySize(const T (&)[TSize]) {
67   return TSize;
68 }
69 
70 // Function object which invokes 'free' on its parameter, which must be
71 // a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
72 //
73 // std::unique_ptr<int, base::FreeDeleter> foo_ptr(
74 //     static_cast<int*>(malloc(sizeof(int))));
75 struct FreeDeleter {
operatorFreeDeleter76   inline void operator()(void* ptr) const { free(ptr); }
77 };
78 
79 template <typename T>
AssumeLittleEndian(T value)80 constexpr T AssumeLittleEndian(T value) {
81 #if !PERFETTO_IS_LITTLE_ENDIAN()
82   static_assert(false, "Unimplemented on big-endian archs");
83 #endif
84   return value;
85 }
86 
87 // Round up |size| to a multiple of |alignment| (must be a power of two).
88 template <size_t alignment>
AlignUp(size_t size)89 constexpr size_t AlignUp(size_t size) {
90   static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2");
91   return (size + alignment - 1) & ~(alignment - 1);
92 }
93 
IsAgain(int err)94 inline bool IsAgain(int err) {
95   return err == EAGAIN || err == EWOULDBLOCK;
96 }
97 
98 // setenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
99 void SetEnv(const std::string& key, const std::string& value);
100 
101 // unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
102 void UnsetEnv(const std::string& key);
103 
104 // Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms.
105 // This forces the allocator to release freed memory. This is used to work
106 // around various Scudo inefficiencies. See b/170217718.
107 void MaybeReleaseAllocatorMemToOS();
108 
109 // geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc).
110 uid_t GetCurrentUserId();
111 
112 // Forks the process.
113 // Parent: prints the PID of the child, calls |parent_cb| and exits from the
114 //         process with its return value.
115 // Child: redirects stdio onto /dev/null, chdirs into / and returns.
116 void Daemonize(std::function<int()> parent_cb);
117 
118 // Returns the path of the current executable, e.g. /foo/bar/exe.
119 std::string GetCurExecutablePath();
120 
121 // Returns the directory where the current executable lives in, e.g. /foo/bar.
122 // This is independent of cwd().
123 std::string GetCurExecutableDir();
124 
125 // Memory returned by AlignedAlloc() must be freed via AlignedFree() not just
126 // free. It makes a difference on Windows where _aligned_malloc() and
127 // _aligned_free() must be paired.
128 // Prefer using the AlignedAllocTyped() below which takes care of the pairing.
129 void* AlignedAlloc(size_t alignment, size_t size);
130 void AlignedFree(void*);
131 
132 // A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}.
133 template <typename T>
134 struct AlignedDeleter {
operatorAlignedDeleter135   inline void operator()(T* ptr) const { AlignedFree(ptr); }
136 };
137 
138 // The remove_extent<T> here and below is to allow defining unique_ptr<T[]>.
139 // As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes
140 // always a T*, not a T[]*.
141 template <typename T>
142 using AlignedUniquePtr =
143     std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;
144 
145 template <typename T>
AlignedAllocTyped(size_t n_membs)146 AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
147   using TU = typename std::remove_extent<T>::type;
148   return AlignedUniquePtr<T>(
149       static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
150 }
151 
152 // A RAII wrapper to invoke a function when leaving a function/scope.
153 template <typename Func>
154 class OnScopeExitWrapper {
155  public:
OnScopeExitWrapper(Func f)156   explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {}
OnScopeExitWrapper(OnScopeExitWrapper && other)157   OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept
158       : f_(std::move(other.f_)), active_(other.active_) {
159     other.active_ = false;
160   }
~OnScopeExitWrapper()161   ~OnScopeExitWrapper() {
162     if (active_)
163       f_();
164   }
165 
166  private:
167   Func f_;
168   bool active_;
169 };
170 
171 template <typename Func>
OnScopeExit(Func f)172 PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper<Func> OnScopeExit(Func f) {
173   return OnScopeExitWrapper<Func>(std::move(f));
174 }
175 
176 // Returns a xxd-style hex dump (hex + ascii chars) of the input data.
177 std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16);
178 inline std::string HexDump(const std::string& data,
179                            size_t bytes_per_line = 16) {
180   return HexDump(data.data(), data.size(), bytes_per_line);
181 }
182 
183 }  // namespace base
184 }  // namespace perfetto
185 
186 #endif  // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
187