/* * Copyright (c) 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 . */ #include namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result SignalEvent(ams::svc::Handle event_handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Get the writable event. */ KScopedAutoObject event = handle_table.GetObject(event_handle); R_UNLESS(event.IsNotNull(), svc::ResultInvalidHandle()); return event->Signal(); } Result ClearEvent(ams::svc::Handle event_handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Try to clear the writable event. */ { KScopedAutoObject event = handle_table.GetObject(event_handle); if (event.IsNotNull()) { return event->Clear(); } } /* Try to clear the readable event. */ { KScopedAutoObject readable_event = handle_table.GetObject(event_handle); if (readable_event.IsNotNull()) { if (auto * const interrupt_event = readable_event->DynamicCast(); interrupt_event != nullptr) { return interrupt_event->Clear(); } else { return readable_event->Clear(); } } } return svc::ResultInvalidHandle(); } Result CreateEvent(ams::svc::Handle *out_write, ams::svc::Handle *out_read) { /* Get the current process and handle table. */ auto &process = GetCurrentProcess(); auto &handle_table = process.GetHandleTable(); /* Declare the event we're going to allocate. */ KEvent *event; /* Reserve a new event from the process resource limit. */ KScopedResourceReservation event_reservation(std::addressof(process), ams::svc::LimitableResource_EventCountMax); if (event_reservation.Succeeded()) { /* Allocate an event normally. */ event = KEvent::Create(); } else { /* We couldn't reserve an event. Check that we support dynamically expanding the resource limit. */ R_UNLESS(process.GetResourceLimit() == std::addressof(Kernel::GetSystemResourceLimit()), svc::ResultLimitReached()); R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), svc::ResultLimitReached()); /* Try to allocate an event from unused slab memory. */ event = KEvent::CreateFromUnusedSlabMemory(); R_UNLESS(event != nullptr, svc::ResultLimitReached()); /* We successfully allocated an event, so add the object we allocated to the resource limit. */ Kernel::GetSystemResourceLimit().Add(ams::svc::LimitableResource_EventCountMax, 1); } /* Check that we successfully created an event. */ R_UNLESS(event != nullptr, svc::ResultOutOfResource()); /* Initialize the event. */ event->Initialize(); /* Commit the event reservation. */ event_reservation.Commit(); /* Ensure that we clean up the event (and its only references are handle table) on function end. */ ON_SCOPE_EXIT { event->GetReadableEvent().Close(); event->Close(); }; /* Register the event. */ KEvent::Register(event); /* Add the event to the handle table. */ R_TRY(handle_table.Add(out_write, event)); /* Ensure that we maintaing a clean handle state on exit. */ auto handle_guard = SCOPE_GUARD { handle_table.Remove(*out_write); }; /* Add the readable event to the handle table. */ R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); /* We succeeded! */ handle_guard.Cancel(); return ResultSuccess(); } } /* ============================= 64 ABI ============================= */ Result SignalEvent64(ams::svc::Handle event_handle) { return SignalEvent(event_handle); } Result ClearEvent64(ams::svc::Handle event_handle) { return ClearEvent(event_handle); } Result CreateEvent64(ams::svc::Handle *out_write_handle, ams::svc::Handle *out_read_handle) { return CreateEvent(out_write_handle, out_read_handle); } /* ============================= 64From32 ABI ============================= */ Result SignalEvent64From32(ams::svc::Handle event_handle) { return SignalEvent(event_handle); } Result ClearEvent64From32(ams::svc::Handle event_handle) { return ClearEvent(event_handle); } Result CreateEvent64From32(ams::svc::Handle *out_write_handle, ams::svc::Handle *out_read_handle) { return CreateEvent(out_write_handle, out_read_handle); } }