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

#include "core/core.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/psc/time/shared_memory.h"

namespace Service::PSC::Time {
namespace {
template <typename T>
constexpr inline T ReadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
    while (true) {
        // Get the counter.
        auto counter = p->m_counter;

        // Get the value.
        auto value = p->m_value[counter % 2];

        // Fence memory.
        std::atomic_thread_fence(std::memory_order_acquire);

        // Check that the counter matches.
        if (counter == p->m_counter) {
            return value;
        }
    }
}

template <typename T>
constexpr inline void WriteToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
    // Get the current counter.
    auto counter = p->m_counter;

    // Increment the counter.
    ++counter;

    // Store the updated value.
    p->m_value[counter % 2] = value;

    // Fence memory.
    std::atomic_thread_fence(std::memory_order_release);

    // Set the updated counter.
    p->m_counter = counter;
}
} // namespace

SharedMemory::SharedMemory(Core::System& system)
    : m_system{system}, m_k_shared_memory{m_system.Kernel().GetTimeSharedMem()},
      m_shared_memory_ptr{reinterpret_cast<SharedMemoryStruct*>(m_k_shared_memory.GetPointer())} {
    std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr));
}

void SharedMemory::SetLocalSystemContext(const SystemClockContext& context) {
    WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context);
}

void SharedMemory::SetNetworkSystemContext(const SystemClockContext& context) {
    WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context);
}

void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_point) {
    WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points,
                              {time_point, clock_source_id});
}

void SharedMemory::SetContinuousAdjustment(const ContinuousAdjustmentTimePoint& time_point) {
    WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point);
}

void SharedMemory::SetAutomaticCorrection(bool automatic_correction) {
    WriteToLockFreeAtomicType(&m_shared_memory_ptr->automatic_corrections, automatic_correction);
}

void SharedMemory::UpdateBaseTime(s64 time) {
    SteadyClockTimePoint time_point{
        ReadFromLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points)};

    time_point.time_point = time;

    WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, time_point);
}

} // namespace Service::PSC::Time