mozmemory_stall.h (2497B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozjemalloc_stall_h 8 #define mozjemalloc_stall_h 9 10 #include <optional> 11 12 #if defined(MOZ_MEMORY) && defined(XP_WIN) 13 # include "mozmemory_wrap.h" 14 #endif 15 16 // See 17 // https://hacks.mozilla.org/2022/11/improving-firefox-stability-with-this-one-weird-trick/ 18 19 namespace mozilla { 20 21 namespace detail { 22 // Helper for StallAndRetry error messages. 23 template <typename T> 24 constexpr bool is_std_optional = false; 25 template <typename T> 26 constexpr bool is_std_optional<std::optional<T>> = true; 27 } // namespace detail 28 29 struct StallSpecs { 30 // Maximum number of retry-attempts before giving up. 31 size_t maxAttempts; 32 // Delay time between successive events. 33 size_t delayMs; 34 35 // Retry a fallible operation until it succeeds or until we've run out of 36 // retries. 37 // 38 // Note that this invokes `aDelayFunc` immediately upon being called! It's 39 // intended for use in the unhappy path, after an initial attempt has failed. 40 // 41 // The function type here may be read: 42 // ``` 43 // fn StallAndRetry<R>( 44 // delay_func: impl Fn(usize) -> (), 45 // operation: impl Fn() -> Option<R>, 46 // ) -> Option<R>; 47 // ``` 48 // 49 template <typename DelayFunc, typename OpFunc> 50 auto StallAndRetry(DelayFunc&& aDelayFunc, OpFunc&& aOperation) const 51 -> decltype(aOperation()) { 52 { 53 // Explicit typecheck for OpFunc, to provide an explicit error message. 54 using detail::is_std_optional; 55 static_assert(is_std_optional<decltype(aOperation())>, 56 "aOperation() must return std::optional"); 57 58 // (clang's existing error messages suffice for aDelayFunc.) 59 } 60 61 for (size_t i = 0; i < maxAttempts; ++i) { 62 aDelayFunc(delayMs); 63 if (const auto opt = aOperation()) { 64 return opt; 65 } 66 } 67 return std::nullopt; 68 } 69 }; 70 71 #if defined(MOZ_MEMORY) && defined(XP_WIN) 72 MOZ_JEMALLOC_API StallSpecs GetAllocatorStallSpecs(); 73 MOZ_JEMALLOC_API_NODISCARD void* MozVirtualAlloc(void* lpAddress, size_t dwSize, 74 uint32_t flAllocationType, 75 uint32_t flProtect); 76 #endif 77 78 } // namespace mozilla 79 80 #endif // mozjemalloc_stall_h