From 44418cb35138ce2af09ec2945a4ae8c9cb816feb Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 4 Jun 2021 12:59:53 +0200 Subject: [PATCH] AK: Allow deferring clear() for the Function class Ideally a Function should not be clear()ed while it's running. Unfortunately a number of callers do just that and identifying all of them would require inspecting all call sites for operator() and clear(). Instead this adds support for deferring clear() until after the function has finished executing. --- AK/Function.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/AK/Function.h b/AK/Function.h index 5e4f639966..85ee9de9b1 100644 --- a/AK/Function.h +++ b/AK/Function.h @@ -48,7 +48,7 @@ public: ~Function() { - clear(); + clear(false); } template && IsFunction>)&&IsRvalueReference>::Type> @@ -74,7 +74,8 @@ public: VERIFY(wrapper); ++m_call_nesting_level; ScopeGuard guard([this] { - --m_call_nesting_level; + if (--m_call_nesting_level == 0 && m_deferred_clear) + const_cast(this)->clear(false); }); return wrapper->call(forward(in)...); } @@ -181,8 +182,15 @@ private: } } - void clear() + void clear(bool may_defer = true) { + bool called_from_inside_function = m_call_nesting_level > 0; + VERIFY(may_defer || !called_from_inside_function); + if (called_from_inside_function && may_defer) { + m_deferred_clear = true; + return; + } + m_deferred_clear = false; auto* wrapper = callable_wrapper(); if (m_kind == FunctionKind::Inline) { VERIFY(wrapper); @@ -229,6 +237,7 @@ private: } FunctionKind m_kind { FunctionKind::NullPointer }; + bool m_deferred_clear { false }; mutable Atomic m_call_nesting_level { 0 }; // Empirically determined to fit most lambdas and functions. static constexpr size_t inline_capacity = 4 * sizeof(void*);