summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/k_object_name.cpp
blob: df3a1c4c56c8c3e66a3185d119fa1f9afc553978 (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
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/kernel/k_object_name.h"

namespace Kernel {

KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {}
KObjectNameGlobalData::~KObjectNameGlobalData() = default;

void KObjectName::Initialize(KAutoObject* obj, const char* name) {
    // Set member variables.
    m_object = obj;
    std::strncpy(m_name.data(), name, sizeof(m_name) - 1);
    m_name[sizeof(m_name) - 1] = '\x00';

    // Open a reference to the object we hold.
    m_object->Open();
}

bool KObjectName::MatchesName(const char* name) const {
    return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0;
}

Result KObjectName::NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name) {
    // Create a new object name.
    KObjectName* new_name = KObjectName::Allocate(kernel);
    R_UNLESS(new_name != nullptr, ResultOutOfResource);

    // Initialize the new name.
    new_name->Initialize(obj, name);

    // Check if there's an existing name.
    {
        // Get the global data.
        KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};

        // Ensure we have exclusive access to the global list.
        KScopedLightLock lk{gd.GetObjectListLock()};

        // If the object doesn't exist, put it into the list.
        KScopedAutoObject existing_object = FindImpl(kernel, name);
        if (existing_object.IsNull()) {
            gd.GetObjectList().push_back(*new_name);
            R_SUCCEED();
        }
    }

    // The object already exists, which is an error condition. Perform cleanup.
    obj->Close();
    KObjectName::Free(kernel, new_name);
    R_THROW(ResultInvalidState);
}

Result KObjectName::Delete(KernelCore& kernel, KAutoObject* obj, const char* compare_name) {
    // Get the global data.
    KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};

    // Ensure we have exclusive access to the global list.
    KScopedLightLock lk{gd.GetObjectListLock()};

    // Find a matching entry in the list, and delete it.
    for (auto& name : gd.GetObjectList()) {
        if (name.MatchesName(compare_name) && obj == name.GetObject()) {
            // We found a match, clean up its resources.
            obj->Close();
            gd.GetObjectList().erase(gd.GetObjectList().iterator_to(name));
            KObjectName::Free(kernel, std::addressof(name));
            R_SUCCEED();
        }
    }

    // We didn't find the object in the list.
    R_THROW(ResultNotFound);
}

KScopedAutoObject<KAutoObject> KObjectName::Find(KernelCore& kernel, const char* name) {
    // Get the global data.
    KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};

    // Ensure we have exclusive access to the global list.
    KScopedLightLock lk{gd.GetObjectListLock()};

    return FindImpl(kernel, name);
}

KScopedAutoObject<KAutoObject> KObjectName::FindImpl(KernelCore& kernel, const char* compare_name) {
    // Get the global data.
    KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};

    // Try to find a matching object in the global list.
    for (const auto& name : gd.GetObjectList()) {
        if (name.MatchesName(compare_name)) {
            return name.GetObject();
        }
    }

    // There's no matching entry in the list.
    return nullptr;
}

} // namespace Kernel