summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/svc/svc_event.cpp
blob: 8692b00f272c756df4c7af96d9e277924a5b9c15 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// 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_event.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc.h"

namespace Kernel::Svc {

Result SignalEvent(Core::System& system, Handle event_handle) {
    LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);

    // Get the current handle table.
    const KHandleTable& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();

    // Get the event.
    KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
    R_UNLESS(event.IsNotNull(), ResultInvalidHandle);

    return event->Signal();
}

Result ClearEvent(Core::System& system, Handle event_handle) {
    LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);

    // Get the current handle table.
    const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();

    // Try to clear the writable event.
    {
        KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
        if (event.IsNotNull()) {
            return event->Clear();
        }
    }

    // Try to clear the readable event.
    {
        KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
        if (readable_event.IsNotNull()) {
            return readable_event->Clear();
        }
    }

    LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);

    return ResultInvalidHandle;
}

Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
    LOG_DEBUG(Kernel_SVC, "called");

    // Get the kernel reference and handle table.
    auto& kernel = system.Kernel();
    auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();

    // Reserve a new event from the process resource limit
    KScopedResourceReservation event_reservation(GetCurrentProcessPointer(kernel),
                                                 LimitableResource::EventCountMax);
    R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);

    // Create a new event.
    KEvent* event = KEvent::Create(kernel);
    R_UNLESS(event != nullptr, ResultOutOfResource);

    // Initialize the event.
    event->Initialize(GetCurrentProcessPointer(kernel));

    // Commit the thread reservation.
    event_reservation.Commit();

    // Ensure that we clean up the event (and its only references are handle table) on function end.
    SCOPE_EXIT({
        event->GetReadableEvent().Close();
        event->Close();
    });

    // Register the event.
    KEvent::Register(kernel, event);

    // Add the event to the handle table.
    R_TRY(handle_table.Add(out_write, event));

    // Ensure that we maintain 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;
}

Result SignalEvent64(Core::System& system, Handle event_handle) {
    R_RETURN(SignalEvent(system, event_handle));
}

Result ClearEvent64(Core::System& system, Handle event_handle) {
    R_RETURN(ClearEvent(system, event_handle));
}

Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle) {
    R_RETURN(CreateEvent(system, out_write_handle, out_read_handle));
}

Result SignalEvent64From32(Core::System& system, Handle event_handle) {
    R_RETURN(SignalEvent(system, event_handle));
}

Result ClearEvent64From32(Core::System& system, Handle event_handle) {
    R_RETURN(ClearEvent(system, event_handle));
}

Result CreateEvent64From32(Core::System& system, Handle* out_write_handle,
                           Handle* out_read_handle) {
    R_RETURN(CreateEvent(system, out_write_handle, out_read_handle));
}

} // namespace Kernel::Svc