/* * Copyright (c) 2018-2020 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include namespace ams::fssystem::buffers { namespace impl { constexpr inline auto RetryWait = TimeSpan::FromMilliSeconds(10); } template Result DoContinuouslyUntilBufferIsAllocated(F f, OnFailure on_failure, const char *function_name) { constexpr auto BufferAllocationRetryLogCountMax = 10; constexpr auto BufferAllocationRetryLogInterval = 100; for (auto count = 1; true; count++) { R_TRY_CATCH(f()) { R_CATCH(fs::ResultBufferAllocationFailed) { if ((1 <= count && count <= BufferAllocationRetryLogCountMax) || ((count % BufferAllocationRetryLogInterval) == 0)) { /* TODO: Log */ } R_TRY(on_failure()); /* TODO: os::SleepThread */ svc::SleepThread(impl::RetryWait.GetNanoSeconds()); continue; } } R_END_TRY_CATCH; return ResultSuccess(); } } template Result DoContinuouslyUntilBufferIsAllocated(F f, const char *function_name) { R_TRY(DoContinuouslyUntilBufferIsAllocated(f, []() ALWAYS_INLINE_LAMBDA { return ResultSuccess(); }, function_name)); return ResultSuccess(); } class BufferManagerContext { private: bool needs_blocking; public: constexpr BufferManagerContext() : needs_blocking(false) { /* ... */ } public: bool IsNeedBlocking() const { return this->needs_blocking; } void SetNeedBlocking(bool need) { this->needs_blocking = need; } }; void RegisterBufferManagerContext(const BufferManagerContext *context); BufferManagerContext *GetBufferManagerContext(); void EnableBlockingBufferManagerAllocation(); class ScopedBufferManagerContextRegistration { private: BufferManagerContext cur_context; const BufferManagerContext *old_context; public: ALWAYS_INLINE explicit ScopedBufferManagerContextRegistration() { this->old_context = GetBufferManagerContext(); if (this->old_context != nullptr) { this->cur_context = *this->old_context; } RegisterBufferManagerContext(std::addressof(this->cur_context)); } ALWAYS_INLINE ~ScopedBufferManagerContextRegistration() { RegisterBufferManagerContext(this->old_context); } }; }