kern: KAutoObject destruction is now scheduled for next dpc-time
This commit is contained in:
@@ -69,11 +69,12 @@ namespace ams::kern {
|
||||
private:
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
||||
private:
|
||||
KAutoObject *m_next_closed_object;
|
||||
std::atomic<u32> m_ref_count;
|
||||
public:
|
||||
static KAutoObject *Create(KAutoObject *ptr);
|
||||
public:
|
||||
constexpr ALWAYS_INLINE explicit KAutoObject() : m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
|
||||
constexpr ALWAYS_INLINE explicit KAutoObject() : m_next_closed_object(nullptr), m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
|
||||
virtual ~KAutoObject() { MESOSPHERE_ASSERT_THIS(); }
|
||||
|
||||
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
|
||||
@@ -120,7 +121,7 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Open() {
|
||||
NOINLINE bool Open() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Atomically increment the reference count, only if it's positive. */
|
||||
@@ -136,7 +137,7 @@ namespace ams::kern {
|
||||
return true;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Close() {
|
||||
NOINLINE void Close() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Atomically decrement the reference count, not allowing it to become negative. */
|
||||
@@ -145,11 +146,19 @@ namespace ams::kern {
|
||||
MESOSPHERE_ABORT_UNLESS(cur_ref_count > 0);
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, std::memory_order_relaxed));
|
||||
|
||||
/* If ref count hits zero, destroy the object. */
|
||||
/* If ref count hits zero, schedule the object for destruction. */
|
||||
if (cur_ref_count - 1 == 0) {
|
||||
this->Destroy();
|
||||
this->ScheduleDestruction();
|
||||
}
|
||||
}
|
||||
private:
|
||||
/* NOTE: This has to be defined *after* KThread is defined. */
|
||||
/* Nintendo seems to handle this by defining Open/Close() in a cpp, but we'd like them to remain in headers. */
|
||||
/* Implementation for this will be inside kern_k_thread.hpp, so it can be ALWAYS_INLINE. */
|
||||
void ScheduleDestruction();
|
||||
public:
|
||||
/* Getter, for KThread. */
|
||||
ALWAYS_INLINE KAutoObject *GetNextClosedObject() { return m_next_closed_object; }
|
||||
};
|
||||
|
||||
class KAutoObjectWithListContainer;
|
||||
@@ -198,7 +207,7 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
~KScopedAutoObject() {
|
||||
ALWAYS_INLINE ~KScopedAutoObject() {
|
||||
if (m_obj != nullptr) {
|
||||
m_obj->Close();
|
||||
}
|
||||
|
||||
@@ -77,8 +77,9 @@ namespace ams::kern {
|
||||
};
|
||||
|
||||
enum DpcFlag : u32 {
|
||||
DpcFlag_Terminating = (1 << 0),
|
||||
DpcFlag_Terminated = (1 << 1),
|
||||
DpcFlag_Terminating = (1 << 0),
|
||||
DpcFlag_Terminated = (1 << 1),
|
||||
DpcFlag_PerformDestruction = (1 << 2),
|
||||
};
|
||||
|
||||
struct StackParameters {
|
||||
@@ -203,6 +204,7 @@ namespace ams::kern {
|
||||
WaiterList m_pinned_waiter_list{};
|
||||
KThread *m_lock_owner{};
|
||||
uintptr_t m_debug_params[3]{};
|
||||
KAutoObject *m_closed_object{};
|
||||
u32 m_address_key_value{};
|
||||
u32 m_suspend_request_flags{};
|
||||
u32 m_suspend_allowed_flags{};
|
||||
@@ -324,15 +326,15 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
|
||||
this->GetStackParameters().dpc_flags |= flag;
|
||||
this->GetStackParameters().dpc_flags.fetch_or(flag);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
|
||||
this->GetStackParameters().dpc_flags &= ~flag;
|
||||
this->GetStackParameters().dpc_flags.fetch_and(~flag);;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u8 GetDpc() const {
|
||||
return this->GetStackParameters().dpc_flags;
|
||||
return this->GetStackParameters().dpc_flags.load();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool HasDpc() const {
|
||||
@@ -491,6 +493,39 @@ namespace ams::kern {
|
||||
void SetInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 1; }
|
||||
void ClearInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 0; }
|
||||
|
||||
ALWAYS_INLINE KAutoObject *GetClosedObject() { return m_closed_object; }
|
||||
|
||||
ALWAYS_INLINE void SetClosedObject(KAutoObject *object) {
|
||||
MESOSPHERE_ASSERT(object != nullptr);
|
||||
|
||||
/* Set the object to destroy. */
|
||||
m_closed_object = object;
|
||||
|
||||
/* Schedule destruction DPC. */
|
||||
if ((this->GetStackParameters().dpc_flags.load(std::memory_order_relaxed) & DpcFlag_PerformDestruction) == 0) {
|
||||
this->RegisterDpc(DpcFlag_PerformDestruction);
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DestroyClosedObjects() {
|
||||
/* Destroy all objects that have been closed. */
|
||||
if (KAutoObject *cur = m_closed_object; cur != nullptr) {
|
||||
do {
|
||||
/* Set our closed object as the next to close. */
|
||||
m_closed_object = cur->GetNextClosedObject();
|
||||
|
||||
/* Destroy the current object. */
|
||||
cur->Destroy();
|
||||
|
||||
/* Advance. */
|
||||
cur = m_closed_object;
|
||||
} while (cur != nullptr);
|
||||
|
||||
/* Clear the pending DPC. */
|
||||
this->ClearDpc(DpcFlag_PerformDestruction);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void SetDebugAttached() { m_debug_attached = true; }
|
||||
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
|
||||
|
||||
@@ -603,4 +638,14 @@ namespace ams::kern {
|
||||
return GetCurrentThread().GetCurrentCore();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void KAutoObject::ScheduleDestruction() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Set our object to destroy. */
|
||||
m_next_closed_object = GetCurrentThread().GetClosedObject();
|
||||
|
||||
/* Set ourselves as the thread's next object to destroy. */
|
||||
GetCurrentThread().SetClosedObject(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user