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 namespace internal {
54 extern std::atomic<uint32_t> g_cached_page_size;
55 uint32_t GetSysPageSizeSlowpath();
56 } // namespace internal
57
58 // Returns the system's page size. Use this when dealing with mmap, madvise and
59 // similar mm-related syscalls.
60 // This function might be called in hot paths. Avoid calling getpagesize() all
61 // the times, in many implementations getpagesize() calls sysconf() which is
62 // not cheap.
GetSysPageSize()63 inline uint32_t GetSysPageSize() {
64 const uint32_t page_size =
65 internal::g_cached_page_size.load(std::memory_order_relaxed);
66 return page_size != 0 ? page_size : internal::GetSysPageSizeSlowpath();
67 }
68
69 template <typename T, size_t TSize>
ArraySize(const T (&)[TSize])70 constexpr size_t ArraySize(const T (&)[TSize]) {
71 return TSize;
72 }
73
74 // Function object which invokes 'free' on its parameter, which must be
75 // a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
76 //
77 // std::unique_ptr<int, base::FreeDeleter> foo_ptr(
78 // static_cast<int*>(malloc(sizeof(int))));
79 struct FreeDeleter {
operatorFreeDeleter80 inline void operator()(void* ptr) const { free(ptr); }
81 };
82
83 template <typename T>
AssumeLittleEndian(T value)84 constexpr T AssumeLittleEndian(T value) {
85 #if !PERFETTO_IS_LITTLE_ENDIAN()
86 static_assert(false, "Unimplemented on big-endian archs");
87 #endif
88 return value;
89 }
90
91 // Round up |size| to a multiple of |alignment| (must be a power of two).
AlignUp(size_t size,size_t alignment)92 inline constexpr size_t AlignUp(size_t size, size_t alignment) {
93 return (size + alignment - 1) & ~(alignment - 1);
94 }
95
96 // TODO(primiano): clean this up and move all existing usages to the constexpr
97 // version above.
98 template <size_t alignment>
AlignUp(size_t size)99 constexpr size_t AlignUp(size_t size) {
100 static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2");
101 return AlignUp(size, alignment);
102 }
103
IsAgain(int err)104 inline bool IsAgain(int err) {
105 return err == EAGAIN || err == EWOULDBLOCK;
106 }
107
108 // setenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
109 void SetEnv(const std::string& key, const std::string& value);
110
111 // unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
112 void UnsetEnv(const std::string& key);
113
114 // Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms.
115 // This forces the allocator to release freed memory. This is used to work
116 // around various Scudo inefficiencies. See b/170217718.
117 void MaybeReleaseAllocatorMemToOS();
118
119 // geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc).
120 uid_t GetCurrentUserId();
121
122 // Forks the process.
123 // Parent: prints the PID of the child, calls |parent_cb| and exits from the
124 // process with its return value.
125 // Child: redirects stdio onto /dev/null, chdirs into / and returns.
126 void Daemonize(std::function<int()> parent_cb);
127
128 // Returns the path of the current executable, e.g. /foo/bar/exe.
129 std::string GetCurExecutablePath();
130
131 // Returns the directory where the current executable lives in, e.g. /foo/bar.
132 // This is independent of cwd().
133 std::string GetCurExecutableDir();
134
135 // Memory returned by AlignedAlloc() must be freed via AlignedFree() not just
136 // free. It makes a difference on Windows where _aligned_malloc() and
137 // _aligned_free() must be paired.
138 // Prefer using the AlignedAllocTyped() below which takes care of the pairing.
139 void* AlignedAlloc(size_t alignment, size_t size);
140 void AlignedFree(void*);
141
142 // Detects Sync-mode MTE (currently being tested in some Android builds).
143 // This is known to use extra memory for the stack history buffer.
144 bool IsSyncMemoryTaggingEnabled();
145
146 // A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}.
147 template <typename T>
148 struct AlignedDeleter {
operatorAlignedDeleter149 inline void operator()(T* ptr) const { AlignedFree(ptr); }
150 };
151
152 // The remove_extent<T> here and below is to allow defining unique_ptr<T[]>.
153 // As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes
154 // always a T*, not a T[]*.
155 template <typename T>
156 using AlignedUniquePtr =
157 std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;
158
159 template <typename T>
AlignedAllocTyped(size_t n_membs)160 AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
161 using TU = typename std::remove_extent<T>::type;
162 return AlignedUniquePtr<T>(
163 static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
164 }
165
166 // A RAII wrapper to invoke a function when leaving a function/scope.
167 template <typename Func>
168 class OnScopeExitWrapper {
169 public:
OnScopeExitWrapper(Func f)170 explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {}
OnScopeExitWrapper(OnScopeExitWrapper && other)171 OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept
172 : f_(std::move(other.f_)), active_(other.active_) {
173 other.active_ = false;
174 }
~OnScopeExitWrapper()175 ~OnScopeExitWrapper() {
176 if (active_)
177 f_();
178 }
179
180 private:
181 Func f_;
182 bool active_;
183 };
184
185 template <typename Func>
OnScopeExit(Func f)186 PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper<Func> OnScopeExit(Func f) {
187 return OnScopeExitWrapper<Func>(std::move(f));
188 }
189
190 // Returns a xxd-style hex dump (hex + ascii chars) of the input data.
191 std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16);
192 inline std::string HexDump(const std::string& data,
193 size_t bytes_per_line = 16) {
194 return HexDump(data.data(), data.size(), bytes_per_line);
195 }
196
197 } // namespace base
198 } // namespace perfetto
199
200 #endif // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
201