Added CPU, mutex, process, thread, timer
This commit is contained in:
parent
06891d9454
commit
f557d26b40
20 changed files with 299 additions and 41 deletions
2
externals/boost
vendored
2
externals/boost
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 19ccdcc6fbd026f98ed83dea32ff0398120fbb32
|
||||
Subproject commit f4850c2975a0d977b7479664b8d4a6f03300a042
|
|
@ -91,6 +91,7 @@ add_library(common STATIC
|
|||
scm_rev.h
|
||||
scope_exit.h
|
||||
serialization/atomic.h
|
||||
serialization/boost_flat_set.h
|
||||
serialization/boost_vector.hpp
|
||||
string_util.cpp
|
||||
string_util.h
|
||||
|
|
37
src/common/serialization/boost_flat_set.h
Normal file
37
src/common/serialization/boost_flat_set.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/serialization/split_free.hpp>
|
||||
|
||||
namespace boost::serialization {
|
||||
|
||||
template <class Archive, class T>
|
||||
void save(Archive& ar, const boost::container::flat_set<T>& set, const unsigned int file_version)
|
||||
{
|
||||
ar << static_cast<u64>(set.size());
|
||||
for (auto &v : set) {
|
||||
ar << v;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class T>
|
||||
void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version)
|
||||
{
|
||||
u64 count{};
|
||||
ar >> count;
|
||||
set.clear();
|
||||
for (auto i = 0; i < count; i++) {
|
||||
T value{};
|
||||
ar >> value;
|
||||
set.insert(value);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class T>
|
||||
void serialize(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version)
|
||||
{
|
||||
boost::serialization::split_free(ar, set, file_version);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <boost/serialization/deque.hpp>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
|
@ -156,6 +159,34 @@ private:
|
|||
Queue* first;
|
||||
// The priority level queues of thread ids.
|
||||
std::array<Queue, NUM_QUEUES> queues;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void save(Archive& ar, const unsigned int file_version) const
|
||||
{
|
||||
s32 idx = first == UnlinkedTag() ? -1 : static_cast<s32>(first - &queues[0]);
|
||||
ar << idx;
|
||||
for (auto i = 0; i < NUM_QUEUES; i++) {
|
||||
s32 idx1 = first == UnlinkedTag() ? -1 : static_cast<s32>(queues[i].next_nonempty - &queues[0]);
|
||||
ar << idx1;
|
||||
ar << queues[i].data;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
s32 idx;
|
||||
ar >> idx;
|
||||
first = idx < 0 ? UnlinkedTag() : &queues[idx];
|
||||
for (auto i = 0; i < NUM_QUEUES; i++) {
|
||||
ar >> idx;
|
||||
queues[i].next_nonempty = idx < 0 ? UnlinkedTag() : &queues[idx];
|
||||
ar >> queues[i].data;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/skyeye_common/arm_regformat.h"
|
||||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
|
@ -16,6 +17,48 @@ public:
|
|||
virtual ~ARM_Interface() {}
|
||||
|
||||
class ThreadContext {
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <class Archive>
|
||||
void save(Archive& ar, const unsigned int file_version) const
|
||||
{
|
||||
for (auto i = 0; i < 16; i++) {
|
||||
auto r = GetCpuRegister(i);
|
||||
ar << r;
|
||||
}
|
||||
for (auto i = 0; i < 16; i++) {
|
||||
auto r = GetFpuRegister(i);
|
||||
ar << r;
|
||||
}
|
||||
auto r1 = GetCpsr();
|
||||
ar << r1;
|
||||
auto r2 = GetFpscr();
|
||||
ar << r2;
|
||||
auto r3 = GetFpexc();
|
||||
ar << r3;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
u32 r;
|
||||
for (auto i = 0; i < 16; i++) {
|
||||
ar >> r;
|
||||
SetCpuRegister(i, r);
|
||||
}
|
||||
for (auto i = 0; i < 16; i++) {
|
||||
ar >> r;
|
||||
SetFpuRegister(i, r);
|
||||
}
|
||||
ar >> r;
|
||||
SetCpsr(r);
|
||||
ar >> r;
|
||||
SetFpscr(r);
|
||||
ar >> r;
|
||||
SetFpexc(r);
|
||||
}
|
||||
|
||||
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
||||
public:
|
||||
virtual ~ThreadContext() = default;
|
||||
|
||||
|
@ -143,7 +186,7 @@ public:
|
|||
* @param reg The CP15 register to retrieve the value from.
|
||||
* @return the value stored in the given CP15 register.
|
||||
*/
|
||||
virtual u32 GetCP15Register(CP15Register reg) = 0;
|
||||
virtual u32 GetCP15Register(CP15Register reg) const = 0;
|
||||
|
||||
/**
|
||||
* Stores the given value into the indicated CP15 register.
|
||||
|
@ -172,4 +215,61 @@ public:
|
|||
|
||||
/// Prepare core for thread reschedule (if needed to correctly handle state)
|
||||
virtual void PrepareReschedule() = 0;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <class Archive>
|
||||
void save(Archive& ar, const unsigned int file_version) const
|
||||
{
|
||||
for (auto i = 0; i < 15; i++) {
|
||||
auto r = GetReg(i);
|
||||
ar << r;
|
||||
}
|
||||
auto pc = GetPC();
|
||||
ar << pc;
|
||||
auto cpsr = GetCPSR();
|
||||
ar << cpsr;
|
||||
for (auto i = 0; i < 32; i++) {
|
||||
auto r = GetVFPReg(i);
|
||||
ar << r;
|
||||
}
|
||||
for (auto i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
|
||||
auto r = GetVFPSystemReg(static_cast<VFPSystemRegister>(i));
|
||||
ar << r;
|
||||
}
|
||||
for (auto i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
|
||||
auto r = GetCP15Register(static_cast<CP15Register>(i));
|
||||
ar << r;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
u32 r;
|
||||
for (auto i = 0; i < 15; i++) {
|
||||
ar >> r;
|
||||
SetReg(i, r);
|
||||
}
|
||||
ar >> r;
|
||||
SetPC(r);
|
||||
ar >> r;
|
||||
SetCPSR(r);
|
||||
for (auto i = 0; i < 32; i++) {
|
||||
ar >> r;
|
||||
SetVFPReg(i, r);
|
||||
}
|
||||
for (auto i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
|
||||
ar >> r;
|
||||
SetVFPSystemReg(static_cast<VFPSystemRegister>(i), r);
|
||||
}
|
||||
for (auto i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
|
||||
ar >> r;
|
||||
SetCP15Register(static_cast<CP15Register>(i), r);
|
||||
}
|
||||
// TODO: Clear caches etc?
|
||||
}
|
||||
|
||||
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
||||
};
|
||||
|
|
|
@ -235,7 +235,7 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) {
|
|||
jit->SetCpsr(cpsr);
|
||||
}
|
||||
|
||||
u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) {
|
||||
u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const {
|
||||
return interpreter_state->CP15[reg];
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
|
||||
u32 GetCPSR() const override;
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
u32 GetCP15Register(CP15Register reg) override;
|
||||
u32 GetCP15Register(CP15Register reg) const override;
|
||||
void SetCP15Register(CP15Register reg, u32 value) override;
|
||||
|
||||
std::unique_ptr<ThreadContext> NewContext() const override;
|
||||
|
|
|
@ -138,7 +138,7 @@ void ARM_DynCom::SetCPSR(u32 cpsr) {
|
|||
state->Cpsr = cpsr;
|
||||
}
|
||||
|
||||
u32 ARM_DynCom::GetCP15Register(CP15Register reg) {
|
||||
u32 ARM_DynCom::GetCP15Register(CP15Register reg) const {
|
||||
return state->CP15[reg];
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
|
||||
u32 GetCPSR() const override;
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
u32 GetCP15Register(CP15Register reg) override;
|
||||
u32 GetCP15Register(CP15Register reg) const override;
|
||||
void SetCP15Register(CP15Register reg, u32 value) override;
|
||||
|
||||
std::unique_ptr<ThreadContext> NewContext() const override;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm
|
||||
// putting this as a subset of HLE for now.
|
||||
|
||||
#include <boost/serialization/binary_object.hpp>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
|
@ -56,6 +57,14 @@ public:
|
|||
|
||||
private:
|
||||
ConfigMemDef config_mem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
auto o_config_mem = boost::serialization::binary_object(&config_mem, sizeof(config_mem));
|
||||
ar & o_config_mem;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ConfigMem
|
||||
|
|
|
@ -109,17 +109,17 @@ template <class Archive>
|
|||
void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & named_ports;
|
||||
// TODO: CPU
|
||||
ar & *current_cpu.get();
|
||||
// NB: subsystem references and prepare_reschedule_callback are constant
|
||||
ar & *resource_limits.get();
|
||||
ar & next_object_id;
|
||||
//ar & *timer_manager.get();
|
||||
ar & *timer_manager.get();
|
||||
ar & next_process_id;
|
||||
ar & process_list;
|
||||
ar & current_process;
|
||||
// ar & *thread_manager.get();
|
||||
//ar & *config_mem_handler.get();
|
||||
//ar & *shared_page_handler.get();
|
||||
ar & *thread_manager.get();
|
||||
ar & *config_mem_handler.get();
|
||||
ar & *shared_page_handler.get();
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(KernelSystem)
|
||||
|
|
|
@ -23,11 +23,12 @@ void ReleaseThreadMutexes(Thread* thread) {
|
|||
thread->held_mutexes.clear();
|
||||
}
|
||||
|
||||
Mutex::Mutex(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
|
||||
Mutex::Mutex() : kernel(*g_kernel) {}
|
||||
Mutex::~Mutex() {}
|
||||
|
||||
std::shared_ptr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name) {
|
||||
auto mutex{std::make_shared<Mutex>(*this)};
|
||||
auto mutex{std::make_shared<Mutex>()};
|
||||
mutex->Init(*this);
|
||||
|
||||
mutex->lock_count = 0;
|
||||
mutex->name = std::move(name);
|
||||
|
|
|
@ -17,7 +17,7 @@ class Thread;
|
|||
|
||||
class Mutex final : public WaitObject {
|
||||
public:
|
||||
explicit Mutex(KernelSystem& kernel);
|
||||
explicit Mutex();
|
||||
~Mutex() override;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
|
@ -68,7 +68,6 @@ private:
|
|||
ar & priority;
|
||||
ar & name;
|
||||
ar & holding_thread;
|
||||
ar & kernel; // TODO: Check that this works!
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/bitset.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/serialization/boost_vector.hpp"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
|
@ -17,6 +21,28 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
template <class Archive>
|
||||
void Process::serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & boost::serialization::base_object<Object>(*this);
|
||||
ar & handle_table;
|
||||
ar & codeset;
|
||||
ar & resource_limit;
|
||||
ar & svc_access_mask;
|
||||
ar & handle_table_size;
|
||||
ar & (boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8> >&)address_mappings;
|
||||
ar & flags.raw;
|
||||
ar & kernel_version;
|
||||
ar & ideal_processor;
|
||||
ar & process_id;
|
||||
ar & vm_manager;
|
||||
ar & memory_used;
|
||||
ar & memory_region;
|
||||
ar & tls_slots;
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(Process)
|
||||
|
||||
std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
|
||||
auto codeset{std::make_shared<CodeSet>()};
|
||||
codeset->Init(*this);
|
||||
|
|
|
@ -11,13 +11,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/bitset.hpp>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/serialization/boost_vector.hpp"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
|
@ -234,23 +231,6 @@ private:
|
|||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & boost::serialization::base_object<Object>(*this);
|
||||
ar & handle_table;
|
||||
ar & codeset;
|
||||
ar & resource_limit;
|
||||
ar & svc_access_mask;
|
||||
ar & handle_table_size;
|
||||
ar & (boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8> >&)address_mappings;
|
||||
ar & flags.raw;
|
||||
ar & kernel_version;
|
||||
ar & ideal_processor;
|
||||
ar & process_id;
|
||||
ar & vm_manager;
|
||||
ar & memory_used;
|
||||
ar & memory_region;
|
||||
ar & tls_slots;
|
||||
}
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <boost/serialization/binary_object.hpp>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
@ -104,6 +105,14 @@ private:
|
|||
std::chrono::seconds init_time;
|
||||
|
||||
SharedPageDef shared_page;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
auto o_shared_page = boost::serialization::binary_object(&shared_page, sizeof(shared_page));
|
||||
ar & o_shared_page;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SharedPage
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/serialization/boost_flat_set.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/skyeye_common/armstate.h"
|
||||
#include "core/core.h"
|
||||
|
@ -25,6 +27,30 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
template <class Archive>
|
||||
void Thread::serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & *context.get();
|
||||
ar & thread_id;
|
||||
ar & status;
|
||||
ar & entry_point;
|
||||
ar & stack_top;
|
||||
ar & nominal_priority;
|
||||
ar & current_priority;
|
||||
ar & last_running_ticks;
|
||||
ar & processor_id;
|
||||
ar & tls_address;
|
||||
ar & held_mutexes;
|
||||
ar & pending_mutexes;
|
||||
ar & owner_process;
|
||||
ar & wait_objects;
|
||||
ar & wait_address;
|
||||
ar & name;
|
||||
// TODO: How the hell to do wakeup_callback
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(Thread)
|
||||
|
||||
bool Thread::ShouldWait(const Thread* thread) const {
|
||||
return status != ThreadStatus::Dead;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/thread_queue_list.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
@ -145,6 +148,17 @@ private:
|
|||
|
||||
friend class Thread;
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & next_thread_id;
|
||||
ar & current_thread;
|
||||
ar & ready_queue;
|
||||
ar & wakeup_callback_table;
|
||||
ar & thread_list;
|
||||
}
|
||||
};
|
||||
|
||||
class Thread final : public WaitObject {
|
||||
|
@ -305,6 +319,10 @@ public:
|
|||
|
||||
private:
|
||||
ThreadManager& thread_manager;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
Timer::Timer(KernelSystem& kernel)
|
||||
: WaitObject(kernel), kernel(kernel), timer_manager(kernel.GetTimerManager()) {}
|
||||
Timer::Timer() : kernel(*g_kernel), timer_manager(g_kernel->GetTimerManager()) {}
|
||||
Timer::~Timer() {
|
||||
Cancel();
|
||||
timer_manager.timer_callback_table.erase(callback_id);
|
||||
}
|
||||
|
||||
std::shared_ptr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string name) {
|
||||
auto timer{std::make_shared<Timer>(*this)};
|
||||
auto timer{std::make_shared<Timer>()};
|
||||
timer->Init(*this);
|
||||
|
||||
timer->reset_type = reset_type;
|
||||
timer->signaled = false;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
@ -33,11 +34,19 @@ private:
|
|||
|
||||
friend class Timer;
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & next_timer_callback_id;
|
||||
ar & timer_callback_table;
|
||||
}
|
||||
};
|
||||
|
||||
class Timer final : public WaitObject {
|
||||
public:
|
||||
explicit Timer(KernelSystem& kernel);
|
||||
explicit Timer();
|
||||
~Timer() override;
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
|
@ -103,6 +112,18 @@ private:
|
|||
TimerManager& timer_manager;
|
||||
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{
|
||||
ar & reset_type;
|
||||
ar & initial_delay;
|
||||
ar & interval_delay;
|
||||
ar & signaled;
|
||||
ar & name;
|
||||
ar & callback_id;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
Loading…
Reference in a new issue