| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include "common/scope_exit.h"
- #include "core/core.h"
- #include "core/hle/kernel/k_process.h"
- #include "core/hle/kernel/k_readable_event.h"
- #include "core/hle/kernel/svc.h"
- namespace Kernel::Svc {
- /// Close a handle
- Result CloseHandle(Core::System& system, Handle handle) {
- LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
- // Remove the handle.
- R_UNLESS(GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(handle),
- ResultInvalidHandle);
- R_SUCCEED();
- }
- /// Clears the signaled state of an event or process.
- Result ResetSignal(Core::System& system, Handle handle) {
- LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
- // Get the current handle table.
- const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
- // Try to reset as readable event.
- {
- KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
- if (readable_event.IsNotNull()) {
- R_RETURN(readable_event->Reset());
- }
- }
- // Try to reset as process.
- {
- KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
- if (process.IsNotNull()) {
- R_RETURN(process->Reset());
- }
- }
- R_THROW(ResultInvalidHandle);
- }
- static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles,
- int32_t num_handles, int64_t timeout_ns) {
- // Ensure number of handles is valid.
- R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
- // Get the synchronization context.
- auto& kernel = system.Kernel();
- auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
- std::vector<KSynchronizationObject*> objs(num_handles);
- // Copy user handles.
- if (num_handles > 0) {
- // Convert the handles to objects.
- R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
- num_handles),
- ResultInvalidHandle);
- }
- // Ensure handles are closed when we're done.
- SCOPE_EXIT({
- for (auto i = 0; i < num_handles; ++i) {
- objs[i]->Close();
- }
- });
- // Wait on the objects.
- Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(),
- static_cast<s32>(objs.size()), timeout_ns);
- R_SUCCEED_IF(res == ResultSessionClosed);
- R_RETURN(res);
- }
- /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
- Result WaitSynchronization(Core::System& system, int32_t* out_index, VAddr user_handles,
- int32_t num_handles, int64_t timeout_ns) {
- LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
- num_handles, timeout_ns);
- // Ensure number of handles is valid.
- R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
- std::vector<Handle> handles(num_handles);
- if (num_handles > 0) {
- system.Memory().ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle));
- }
- R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns));
- }
- /// Resumes a thread waiting on WaitSynchronization
- Result CancelSynchronization(Core::System& system, Handle handle) {
- LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
- // Get the thread from its handle.
- KScopedAutoObject thread =
- GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
- // Cancel the thread's wait.
- thread->WaitCancel();
- R_SUCCEED();
- }
- void SynchronizePreemptionState(Core::System& system) {
- auto& kernel = system.Kernel();
- // Lock the scheduler.
- KScopedSchedulerLock sl{kernel};
- // If the current thread is pinned, unpin it.
- KProcess* cur_process = GetCurrentProcessPointer(kernel);
- const auto core_id = GetCurrentCoreId(kernel);
- if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
- // Clear the current thread's interrupt flag.
- GetCurrentThread(kernel).ClearInterruptFlag();
- // Unpin the current thread.
- cur_process->UnpinCurrentThread(core_id);
- }
- }
- Result CloseHandle64(Core::System& system, Handle handle) {
- R_RETURN(CloseHandle(system, handle));
- }
- Result ResetSignal64(Core::System& system, Handle handle) {
- R_RETURN(ResetSignal(system, handle));
- }
- Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles,
- int32_t num_handles, int64_t timeout_ns) {
- R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
- }
- Result CancelSynchronization64(Core::System& system, Handle handle) {
- R_RETURN(CancelSynchronization(system, handle));
- }
- void SynchronizePreemptionState64(Core::System& system) {
- SynchronizePreemptionState(system);
- }
- Result CloseHandle64From32(Core::System& system, Handle handle) {
- R_RETURN(CloseHandle(system, handle));
- }
- Result ResetSignal64From32(Core::System& system, Handle handle) {
- R_RETURN(ResetSignal(system, handle));
- }
- Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles,
- int32_t num_handles, int64_t timeout_ns) {
- R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
- }
- Result CancelSynchronization64From32(Core::System& system, Handle handle) {
- R_RETURN(CancelSynchronization(system, handle));
- }
- void SynchronizePreemptionState64From32(Core::System& system) {
- SynchronizePreemptionState(system);
- }
- } // namespace Kernel::Svc
|