dynarmic-android/include/dynarmic/A64/exclusive_monitor.h

84 lines
2.5 KiB
C
Raw Permalink Normal View History

2018-06-05 12:27:37 +01:00
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
2020-04-23 15:25:11 +01:00
* SPDX-License-Identifier: 0BSD
2018-06-05 12:27:37 +01:00
*/
#pragma once
#include <atomic>
#include <array>
2018-06-05 12:27:37 +01:00
#include <cstddef>
#include <cstdint>
#include <cstring>
2018-06-05 12:27:37 +01:00
#include <vector>
namespace Dynarmic {
namespace A64 {
using VAddr = std::uint64_t;
using Vector = std::array<std::uint64_t, 2>;
2018-06-05 12:27:37 +01:00
class ExclusiveMonitor {
public:
/// @param processor_count Maximum number of processors using this global
/// exclusive monitor. Each processor must have a
/// unique id.
explicit ExclusiveMonitor(size_t processor_count);
size_t GetProcessorCount() const;
/// Marks a region containing [address, address+size) to be exclusive to
/// processor processor_id.
template <typename T, typename Function>
T ReadAndMark(size_t processor_id, VAddr address, Function op) {
static_assert(std::is_trivially_copyable_v<T>);
const VAddr masked_address = address & RESERVATION_GRANULE_MASK;
Lock();
exclusive_addresses[processor_id] = masked_address;
const T value = op();
std::memcpy(exclusive_values[processor_id].data(), &value, sizeof(T));
Unlock();
return value;
}
2018-06-05 12:27:37 +01:00
/// Checks to see if processor processor_id has exclusive access to the
/// specified region. If it does, executes the operation then clears
/// the exclusive state for processors if their exclusive region(s)
/// contain [address, address+size).
template <typename T, typename Function>
bool DoExclusiveOperation(size_t processor_id, VAddr address, Function op) {
static_assert(std::is_trivially_copyable_v<T>);
if (!CheckAndClear(processor_id, address)) {
2018-06-05 12:27:37 +01:00
return false;
}
T saved_value;
std::memcpy(&saved_value, exclusive_values[processor_id].data(), sizeof(T));
const bool result = op(saved_value);
2018-06-05 12:27:37 +01:00
Unlock();
return result;
2018-06-05 12:27:37 +01:00
}
/// Unmark everything.
void Clear();
/// Unmark processor id
void ClearProcessor(size_t processor_id);
2018-06-05 12:27:37 +01:00
private:
bool CheckAndClear(size_t processor_id, VAddr address);
2018-06-05 12:27:37 +01:00
void Lock();
void Unlock();
static constexpr VAddr RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFFFull;
2018-06-05 12:27:37 +01:00
static constexpr VAddr INVALID_EXCLUSIVE_ADDRESS = 0xDEAD'DEAD'DEAD'DEADull;
std::atomic_flag is_locked;
std::vector<VAddr> exclusive_addresses;
std::vector<Vector> exclusive_values;
2018-06-05 12:27:37 +01:00
};
} // namespace A64
} // namespace Dynarmic