1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-11-15 08:26:56 +00:00

kern: update for new interrupt event locking scheme

This commit is contained in:
Michael Scire 2020-12-01 14:17:25 -08:00
parent e81025af2e
commit 6ea1955e94
2 changed files with 32 additions and 27 deletions

View file

@ -27,11 +27,10 @@ namespace ams::kern {
class KInterruptEvent final : public KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent> { class KInterruptEvent final : public KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent> {
MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent); MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent);
private: private:
KInterruptEventTask *task;
s32 interrupt_id; s32 interrupt_id;
bool is_initialized; bool is_initialized;
public: public:
constexpr KInterruptEvent() : task(nullptr), interrupt_id(-1), is_initialized(false) { /* ... */ } constexpr KInterruptEvent() : interrupt_id(-1), is_initialized(false) { /* ... */ }
virtual ~KInterruptEvent() { /* ... */ } virtual ~KInterruptEvent() { /* ... */ }
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type); Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
@ -49,17 +48,19 @@ namespace ams::kern {
class KInterruptEventTask : public KSlabAllocated<KInterruptEventTask>, public KInterruptTask { class KInterruptEventTask : public KSlabAllocated<KInterruptEventTask>, public KInterruptTask {
private: private:
KInterruptEvent *event; KInterruptEvent *event;
s32 interrupt_id; KLightLock lock;
public: public:
constexpr KInterruptEventTask() : event(nullptr), interrupt_id(-1) { /* ... */ } constexpr KInterruptEventTask() : event(nullptr), lock() { /* ... */ }
~KInterruptEventTask() { /* ... */ } ~KInterruptEventTask() { /* ... */ }
KLightLock &GetLock() { return this->lock; }
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override; virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override;
virtual void DoTask() override; virtual void DoTask() override;
void Unregister(); void Unregister(s32 interrupt_id);
public: public:
static Result Register(KInterruptEventTask **out, s32 interrupt_id, bool level, KInterruptEvent *event); static Result Register(s32 interrupt_id, bool level, KInterruptEvent *event);
}; };
} }

View file

@ -34,7 +34,7 @@ namespace ams::kern {
KReadableEvent::Initialize(nullptr); KReadableEvent::Initialize(nullptr);
/* Try to register the task. */ /* Try to register the task. */
R_TRY(KInterruptEventTask::Register(std::addressof(this->task), this->interrupt_id, type == ams::svc::InterruptType_Level, this)); R_TRY(KInterruptEventTask::Register(this->interrupt_id, type == ams::svc::InterruptType_Level, this));
/* Mark initialized. */ /* Mark initialized. */
this->is_initialized = true; this->is_initialized = true;
@ -44,15 +44,17 @@ namespace ams::kern {
void KInterruptEvent::Finalize() { void KInterruptEvent::Finalize() {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(this->task != nullptr); g_interrupt_event_task_table[this->interrupt_id]->Unregister(this->interrupt_id);
this->task->Unregister();
/* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>::Finalize();
} }
Result KInterruptEvent::Reset() { Result KInterruptEvent::Reset() {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
/* Lock the task table. */ /* Lock the task. */
KScopedLightLock lk(g_interrupt_event_lock); KScopedLightLock lk(g_interrupt_event_task_table[this->interrupt_id]->GetLock());
/* Clear the event. */ /* Clear the event. */
R_TRY(KReadableEvent::Reset()); R_TRY(KReadableEvent::Reset());
@ -63,7 +65,7 @@ namespace ams::kern {
return ResultSuccess(); return ResultSuccess();
} }
Result KInterruptEventTask::Register(KInterruptEventTask **out, s32 interrupt_id, bool level, KInterruptEvent *event) { Result KInterruptEventTask::Register(s32 interrupt_id, bool level, KInterruptEvent *event) {
/* Verify the interrupt id is defined and global. */ /* Verify the interrupt id is defined and global. */
R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(interrupt_id), svc::ResultOutOfRange()); R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(interrupt_id), svc::ResultOutOfRange());
R_UNLESS(Kernel::GetInterruptManager().IsGlobal(interrupt_id), svc::ResultOutOfRange()); R_UNLESS(Kernel::GetInterruptManager().IsGlobal(interrupt_id), svc::ResultOutOfRange());
@ -85,45 +87,47 @@ namespace ams::kern {
allocated = true; allocated = true;
} }
/* Register/bind the interrupt task. */
{
/* Ensure that the task is cleaned up if anything goes wrong. */ /* Ensure that the task is cleaned up if anything goes wrong. */
auto task_guard = SCOPE_GUARD { if (allocated) { KInterruptEventTask::Free(task); } }; auto task_guard = SCOPE_GUARD { if (allocated) { KInterruptEventTask::Free(task); } };
/* Register/bind the interrupt task. */
{
/* Acqquire exclusive access to the task. */
KScopedLightLock tlk(task->lock);
/* Bind the interrupt handler. */ /* Bind the interrupt handler. */
R_TRY(Kernel::GetInterruptManager().BindHandler(task, interrupt_id, GetCurrentCoreId(), KInterruptController::PriorityLevel_High, true, level)); R_TRY(Kernel::GetInterruptManager().BindHandler(task, interrupt_id, GetCurrentCoreId(), KInterruptController::PriorityLevel_High, true, level));
/* We successfully registered, so we don't need to free the task. */
task_guard.Cancel();
}
/* Set the event. */ /* Set the event. */
task->event = event; task->event = event;
}
/* If we allocated, set the event in the table. */ /* If we allocated, set the event in the table. */
if (allocated) { if (allocated) {
task->interrupt_id = interrupt_id;
g_interrupt_event_task_table[interrupt_id] = task; g_interrupt_event_task_table[interrupt_id] = task;
} }
/* Set the output. */ /* We successfully registered, so we don't need to free the task. */
*out = task; task_guard.Cancel();
return ResultSuccess(); return ResultSuccess();
} }
void KInterruptEventTask::Unregister() { void KInterruptEventTask::Unregister(s32 interrupt_id) {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
/* Lock the task table. */ /* Lock the task table. */
KScopedLightLock lk(g_interrupt_event_lock); KScopedLightLock lk(g_interrupt_event_lock);
/* Lock the task. */
KScopedLightLock tlk(this->lock);
/* Ensure we can unregister. */ /* Ensure we can unregister. */
MESOSPHERE_ABORT_UNLESS(g_interrupt_event_task_table[this->interrupt_id] == this); MESOSPHERE_ABORT_UNLESS(g_interrupt_event_task_table[interrupt_id] == this);
MESOSPHERE_ABORT_UNLESS(this->event != nullptr); MESOSPHERE_ABORT_UNLESS(this->event != nullptr);
this->event = nullptr;
/* Unbind the interrupt. */ /* Unbind the interrupt. */
Kernel::GetInterruptManager().UnbindHandler(this->interrupt_id, GetCurrentCoreId()); this->event = nullptr;
Kernel::GetInterruptManager().UnbindHandler(interrupt_id, GetCurrentCoreId());
} }
KInterruptTask *KInterruptEventTask::OnInterrupt(s32 interrupt_id) { KInterruptTask *KInterruptEventTask::OnInterrupt(s32 interrupt_id) {
@ -136,7 +140,7 @@ namespace ams::kern {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
/* Lock the task table. */ /* Lock the task table. */
KScopedLightLock lk(g_interrupt_event_lock); KScopedLightLock lk(this->lock);
if (this->event != nullptr) { if (this->event != nullptr) {
this->event->Signal(); this->event->Signal();