mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
kern: update for new interrupt event locking scheme
This commit is contained in:
parent
c7f37f81ee
commit
b60054dba1
2 changed files with 32 additions and 27 deletions
|
@ -27,11 +27,10 @@ namespace ams::kern {
|
|||
class KInterruptEvent final : public KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent> {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent);
|
||||
private:
|
||||
KInterruptEventTask *task;
|
||||
s32 interrupt_id;
|
||||
bool is_initialized;
|
||||
public:
|
||||
constexpr KInterruptEvent() : task(nullptr), interrupt_id(-1), is_initialized(false) { /* ... */ }
|
||||
constexpr KInterruptEvent() : interrupt_id(-1), is_initialized(false) { /* ... */ }
|
||||
virtual ~KInterruptEvent() { /* ... */ }
|
||||
|
||||
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
|
||||
|
@ -49,17 +48,19 @@ namespace ams::kern {
|
|||
class KInterruptEventTask : public KSlabAllocated<KInterruptEventTask>, public KInterruptTask {
|
||||
private:
|
||||
KInterruptEvent *event;
|
||||
s32 interrupt_id;
|
||||
KLightLock lock;
|
||||
public:
|
||||
constexpr KInterruptEventTask() : event(nullptr), interrupt_id(-1) { /* ... */ }
|
||||
constexpr KInterruptEventTask() : event(nullptr), lock() { /* ... */ }
|
||||
~KInterruptEventTask() { /* ... */ }
|
||||
|
||||
KLightLock &GetLock() { return this->lock; }
|
||||
|
||||
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override;
|
||||
virtual void DoTask() override;
|
||||
|
||||
void Unregister();
|
||||
void Unregister(s32 interrupt_id);
|
||||
public:
|
||||
static Result Register(KInterruptEventTask **out, s32 interrupt_id, bool level, KInterruptEvent *event);
|
||||
static Result Register(s32 interrupt_id, bool level, KInterruptEvent *event);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace ams::kern {
|
|||
KReadableEvent::Initialize(nullptr);
|
||||
|
||||
/* 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. */
|
||||
this->is_initialized = true;
|
||||
|
@ -44,15 +44,17 @@ namespace ams::kern {
|
|||
void KInterruptEvent::Finalize() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
MESOSPHERE_ASSERT(this->task != nullptr);
|
||||
this->task->Unregister();
|
||||
g_interrupt_event_task_table[this->interrupt_id]->Unregister(this->interrupt_id);
|
||||
|
||||
/* Perform inherited finalization. */
|
||||
KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>::Finalize();
|
||||
}
|
||||
|
||||
Result KInterruptEvent::Reset() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock the task table. */
|
||||
KScopedLightLock lk(g_interrupt_event_lock);
|
||||
/* Lock the task. */
|
||||
KScopedLightLock lk(g_interrupt_event_task_table[this->interrupt_id]->GetLock());
|
||||
|
||||
/* Clear the event. */
|
||||
R_TRY(KReadableEvent::Reset());
|
||||
|
@ -63,7 +65,7 @@ namespace ams::kern {
|
|||
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. */
|
||||
R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(interrupt_id), svc::ResultOutOfRange());
|
||||
R_UNLESS(Kernel::GetInterruptManager().IsGlobal(interrupt_id), svc::ResultOutOfRange());
|
||||
|
@ -85,45 +87,47 @@ namespace ams::kern {
|
|||
allocated = true;
|
||||
}
|
||||
|
||||
/* Register/bind the interrupt task. */
|
||||
{
|
||||
/* Ensure that the task is cleaned up if anything goes wrong. */
|
||||
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. */
|
||||
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. */
|
||||
task->event = event;
|
||||
}
|
||||
|
||||
/* If we allocated, set the event in the table. */
|
||||
if (allocated) {
|
||||
task->interrupt_id = interrupt_id;
|
||||
g_interrupt_event_task_table[interrupt_id] = task;
|
||||
}
|
||||
|
||||
/* Set the output. */
|
||||
*out = task;
|
||||
/* We successfully registered, so we don't need to free the task. */
|
||||
task_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void KInterruptEventTask::Unregister() {
|
||||
void KInterruptEventTask::Unregister(s32 interrupt_id) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock the task table. */
|
||||
KScopedLightLock lk(g_interrupt_event_lock);
|
||||
|
||||
/* Lock the task. */
|
||||
KScopedLightLock tlk(this->lock);
|
||||
|
||||
/* 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);
|
||||
this->event = nullptr;
|
||||
|
||||
/* 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) {
|
||||
|
@ -136,7 +140,7 @@ namespace ams::kern {
|
|||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock the task table. */
|
||||
KScopedLightLock lk(g_interrupt_event_lock);
|
||||
KScopedLightLock lk(this->lock);
|
||||
|
||||
if (this->event != nullptr) {
|
||||
this->event->Signal();
|
||||
|
|
Loading…
Reference in a new issue