Refactor out the wakeup_callback function pointer
This commit is contained in:
parent
7019561fd5
commit
116d22d562
24 changed files with 533 additions and 295 deletions
3
TODO
3
TODO
|
@ -46,6 +46,7 @@
|
||||||
✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
|
✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
|
||||||
☐ Review constructor/initialization code
|
☐ Review constructor/initialization code
|
||||||
☐ Review core timing events
|
☐ Review core timing events
|
||||||
|
☐ Review base class serialization everywhere
|
||||||
✔ Fix CI @done(19-12-31 21:32)
|
✔ Fix CI @done(19-12-31 21:32)
|
||||||
✔ HW @done(19-08-13 15:41)
|
✔ HW @done(19-08-13 15:41)
|
||||||
✔ GPU regs @done(19-08-13 15:41)
|
✔ GPU regs @done(19-08-13 15:41)
|
||||||
|
@ -87,7 +88,7 @@
|
||||||
✔ Shared page @done(20-01-04 21:09)
|
✔ Shared page @done(20-01-04 21:09)
|
||||||
✔ SVC @done(19-12-22 21:32)
|
✔ SVC @done(19-12-22 21:32)
|
||||||
Nothing to do - all data is constant
|
Nothing to do - all data is constant
|
||||||
☐ Thread @started(19-08-13 16:45)
|
✔ Thread @started(19-08-13 16:45) @done(20-01-06 20:01) @lasted(20w6d4h16m22s)
|
||||||
This requires refactoring wakeup_callback to be an object ref
|
This requires refactoring wakeup_callback to be an object ref
|
||||||
✔ Timer @done(19-08-13 16:45)
|
✔ Timer @done(19-08-13 16:45)
|
||||||
✔ VM Manager @started(19-08-13 16:46) @done(20-01-04 21:09) @lasted(20w4d5h23m42s)
|
✔ VM Manager @started(19-08-13 16:46) @done(20-01-04 21:09) @lasted(20w4d5h23m42s)
|
||||||
|
|
|
@ -96,6 +96,7 @@ add_library(common STATIC
|
||||||
serialization/atomic.h
|
serialization/atomic.h
|
||||||
serialization/boost_discrete_interval.hpp
|
serialization/boost_discrete_interval.hpp
|
||||||
serialization/boost_flat_set.h
|
serialization/boost_flat_set.h
|
||||||
|
serialization/boost_small_vector.hpp
|
||||||
serialization/boost_vector.hpp
|
serialization/boost_vector.hpp
|
||||||
string_util.cpp
|
string_util.cpp
|
||||||
string_util.h
|
string_util.h
|
||||||
|
|
144
src/common/serialization/boost_small_vector.hpp
Normal file
144
src/common/serialization/boost_small_vector.hpp
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
#ifndef BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
|
||||||
|
#define BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
|
||||||
|
|
||||||
|
// MS compatible compilers support #pragma once
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||||
|
// boost_vector.hpp: serialization for boost vector templates
|
||||||
|
|
||||||
|
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
||||||
|
// fast array serialization (C) Copyright 2005 Matthias Troyer
|
||||||
|
// Use, modification and distribution is subject to the Boost Software
|
||||||
|
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// See http://www.boost.org for updates, documentation, and revision history.
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
|
||||||
|
#include <boost/archive/detail/basic_iarchive.hpp>
|
||||||
|
#include <boost/serialization/access.hpp>
|
||||||
|
#include <boost/serialization/collection_size_type.hpp>
|
||||||
|
#include <boost/serialization/item_version_type.hpp>
|
||||||
|
#include <boost/serialization/nvp.hpp>
|
||||||
|
|
||||||
|
#include <boost/mpl/bool_fwd.hpp>
|
||||||
|
#include <boost/mpl/if.hpp>
|
||||||
|
#include <boost/serialization/array_wrapper.hpp>
|
||||||
|
#include <boost/serialization/collections_load_imp.hpp>
|
||||||
|
#include <boost/serialization/collections_save_imp.hpp>
|
||||||
|
#include <boost/serialization/split_free.hpp>
|
||||||
|
|
||||||
|
// default is being compatible with version 1.34.1 files, not 1.35 files
|
||||||
|
#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
|
||||||
|
#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace serialization {
|
||||||
|
|
||||||
|
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||||
|
// vector< T >
|
||||||
|
|
||||||
|
// the default versions
|
||||||
|
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int /* file_version */, mpl::false_) {
|
||||||
|
boost::serialization::stl::save_collection<Archive, boost::container::small_vector<U, N>>(ar,
|
||||||
|
t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int /* file_version */, mpl::false_) {
|
||||||
|
const boost::archive::library_version_type library_version(ar.get_library_version());
|
||||||
|
// retrieve number of elements
|
||||||
|
item_version_type item_version(0);
|
||||||
|
collection_size_type count;
|
||||||
|
ar >> BOOST_SERIALIZATION_NVP(count);
|
||||||
|
if (boost::archive::library_version_type(3) < library_version) {
|
||||||
|
ar >> BOOST_SERIALIZATION_NVP(item_version);
|
||||||
|
}
|
||||||
|
t.reserve(count);
|
||||||
|
stl::collection_load_impl(ar, t, count, item_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the optimized versions
|
||||||
|
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int /* file_version */, mpl::true_) {
|
||||||
|
const collection_size_type count(t.size());
|
||||||
|
ar << BOOST_SERIALIZATION_NVP(count);
|
||||||
|
if (!t.empty())
|
||||||
|
// explict template arguments to pass intel C++ compiler
|
||||||
|
ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]),
|
||||||
|
count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int /* file_version */, mpl::true_) {
|
||||||
|
collection_size_type count(t.size());
|
||||||
|
ar >> BOOST_SERIALIZATION_NVP(count);
|
||||||
|
t.resize(count);
|
||||||
|
unsigned int item_version = 0;
|
||||||
|
if (BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
|
||||||
|
ar >> BOOST_SERIALIZATION_NVP(item_version);
|
||||||
|
}
|
||||||
|
if (!t.empty())
|
||||||
|
// explict template arguments to pass intel C++ compiler
|
||||||
|
ar >> serialization::make_array<U, collection_size_type>(static_cast<U*>(&t[0]), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispatch to either default or optimized versions
|
||||||
|
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int file_version) {
|
||||||
|
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
|
||||||
|
typename remove_const<U>::type>::type use_optimized;
|
||||||
|
save(ar, t, file_version, use_optimized());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int file_version) {
|
||||||
|
#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
|
||||||
|
if (ar.get_library_version() == boost::archive::library_version_type(5)) {
|
||||||
|
load(ar, t, file_version, boost::is_arithmetic<U>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
|
||||||
|
typename remove_const<U>::type>::type use_optimized;
|
||||||
|
load(ar, t, file_version, use_optimized());
|
||||||
|
}
|
||||||
|
|
||||||
|
// split non-intrusive serialization function member into separate
|
||||||
|
// non intrusive save/load member functions
|
||||||
|
template <class Archive, class U, std::size_t N>
|
||||||
|
inline void serialize(Archive& ar, boost::container::small_vector<U, N>& t,
|
||||||
|
const unsigned int file_version) {
|
||||||
|
boost::serialization::split_free(ar, t, file_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// split non-intrusive serialization function member into separate
|
||||||
|
// non intrusive save/load member functions
|
||||||
|
template <class Archive, std::size_t N>
|
||||||
|
inline void serialize(Archive& ar, boost::container::small_vector<bool, N>& t,
|
||||||
|
const unsigned int file_version) {
|
||||||
|
boost::serialization::split_free(ar, t, file_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace serialization
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
|
|
@ -24,16 +24,16 @@
|
||||||
|
|
||||||
#include <boost/archive/detail/basic_iarchive.hpp>
|
#include <boost/archive/detail/basic_iarchive.hpp>
|
||||||
#include <boost/serialization/access.hpp>
|
#include <boost/serialization/access.hpp>
|
||||||
#include <boost/serialization/nvp.hpp>
|
|
||||||
#include <boost/serialization/collection_size_type.hpp>
|
#include <boost/serialization/collection_size_type.hpp>
|
||||||
#include <boost/serialization/item_version_type.hpp>
|
#include <boost/serialization/item_version_type.hpp>
|
||||||
|
#include <boost/serialization/nvp.hpp>
|
||||||
|
|
||||||
#include <boost/serialization/collections_save_imp.hpp>
|
|
||||||
#include <boost/serialization/collections_load_imp.hpp>
|
|
||||||
#include <boost/serialization/split_free.hpp>
|
|
||||||
#include <boost/serialization/array_wrapper.hpp>
|
|
||||||
#include <boost/mpl/bool_fwd.hpp>
|
#include <boost/mpl/bool_fwd.hpp>
|
||||||
#include <boost/mpl/if.hpp>
|
#include <boost/mpl/if.hpp>
|
||||||
|
#include <boost/serialization/array_wrapper.hpp>
|
||||||
|
#include <boost/serialization/collections_load_imp.hpp>
|
||||||
|
#include <boost/serialization/collections_save_imp.hpp>
|
||||||
|
#include <boost/serialization/split_free.hpp>
|
||||||
|
|
||||||
// default is being compatible with version 1.34.1 files, not 1.35 files
|
// default is being compatible with version 1.34.1 files, not 1.35 files
|
||||||
#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
|
#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
|
||||||
|
@ -48,28 +48,18 @@ namespace serialization {
|
||||||
|
|
||||||
// the default versions
|
// the default versions
|
||||||
|
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void save(
|
inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int /* file_version */, mpl::false_) {
|
||||||
const boost::container::vector<U, Allocator> &t,
|
boost::serialization::stl::save_collection<Archive,
|
||||||
const unsigned int /* file_version */,
|
boost::container::vector<U, Allocator, Options>>(ar,
|
||||||
mpl::false_
|
t);
|
||||||
){
|
|
||||||
boost::serialization::stl::save_collection<Archive, boost::container::vector<U, Allocator> >(
|
|
||||||
ar, t
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void load(
|
inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int /* file_version */, mpl::false_) {
|
||||||
boost::container::vector<U, Allocator> &t,
|
const boost::archive::library_version_type library_version(ar.get_library_version());
|
||||||
const unsigned int /* file_version */,
|
|
||||||
mpl::false_
|
|
||||||
){
|
|
||||||
const boost::archive::library_version_type library_version(
|
|
||||||
ar.get_library_version()
|
|
||||||
);
|
|
||||||
// retrieve number of elements
|
// retrieve number of elements
|
||||||
item_version_type item_version(0);
|
item_version_type item_version(0);
|
||||||
collection_size_type count;
|
collection_size_type count;
|
||||||
|
@ -83,30 +73,20 @@ inline void load(
|
||||||
|
|
||||||
// the optimized versions
|
// the optimized versions
|
||||||
|
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void save(
|
inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int /* file_version */, mpl::true_) {
|
||||||
const boost::container::vector<U, Allocator> &t,
|
|
||||||
const unsigned int /* file_version */,
|
|
||||||
mpl::true_
|
|
||||||
){
|
|
||||||
const collection_size_type count(t.size());
|
const collection_size_type count(t.size());
|
||||||
ar << BOOST_SERIALIZATION_NVP(count);
|
ar << BOOST_SERIALIZATION_NVP(count);
|
||||||
if (!t.empty())
|
if (!t.empty())
|
||||||
// explict template arguments to pass intel C++ compiler
|
// explict template arguments to pass intel C++ compiler
|
||||||
ar << serialization::make_array<const U, collection_size_type>(
|
ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]),
|
||||||
static_cast<const U *>(&t[0]),
|
count);
|
||||||
count
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void load(
|
inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int /* file_version */, mpl::true_) {
|
||||||
boost::container::vector<U, Allocator> &t,
|
|
||||||
const unsigned int /* file_version */,
|
|
||||||
mpl::true_
|
|
||||||
){
|
|
||||||
collection_size_type count(t.size());
|
collection_size_type count(t.size());
|
||||||
ar >> BOOST_SERIALIZATION_NVP(count);
|
ar >> BOOST_SERIALIZATION_NVP(count);
|
||||||
t.resize(count);
|
t.resize(count);
|
||||||
|
@ -116,74 +96,54 @@ inline void load(
|
||||||
}
|
}
|
||||||
if (!t.empty())
|
if (!t.empty())
|
||||||
// explict template arguments to pass intel C++ compiler
|
// explict template arguments to pass intel C++ compiler
|
||||||
ar >> serialization::make_array<U, collection_size_type>(
|
ar >> serialization::make_array<U, collection_size_type>(static_cast<U*>(&t[0]), count);
|
||||||
static_cast<U *>(&t[0]),
|
|
||||||
count
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dispatch to either default or optimized versions
|
// dispatch to either default or optimized versions
|
||||||
|
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void save(
|
inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int file_version) {
|
||||||
const boost::container::vector<U, Allocator> &t,
|
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
|
||||||
const unsigned int file_version
|
typename remove_const<U>::type>::type use_optimized;
|
||||||
){
|
|
||||||
typedef typename
|
|
||||||
boost::serialization::use_array_optimization<Archive>::template apply<
|
|
||||||
typename remove_const<U>::type
|
|
||||||
>::type use_optimized;
|
|
||||||
save(ar, t, file_version, use_optimized());
|
save(ar, t, file_version, use_optimized());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void load(
|
inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int file_version) {
|
||||||
boost::container::vector<U, Allocator> &t,
|
|
||||||
const unsigned int file_version
|
|
||||||
){
|
|
||||||
#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
|
#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
|
||||||
if (ar.get_library_version()==boost::archive::library_version_type(5))
|
if (ar.get_library_version() == boost::archive::library_version_type(5)) {
|
||||||
{
|
|
||||||
load(ar, t, file_version, boost::is_arithmetic<U>());
|
load(ar, t, file_version, boost::is_arithmetic<U>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
typedef typename
|
typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
|
||||||
boost::serialization::use_array_optimization<Archive>::template apply<
|
typename remove_const<U>::type>::type use_optimized;
|
||||||
typename remove_const<U>::type
|
|
||||||
>::type use_optimized;
|
|
||||||
load(ar, t, file_version, use_optimized());
|
load(ar, t, file_version, use_optimized());
|
||||||
}
|
}
|
||||||
|
|
||||||
// split non-intrusive serialization function member into separate
|
// split non-intrusive serialization function member into separate
|
||||||
// non intrusive save/load member functions
|
// non intrusive save/load member functions
|
||||||
template<class Archive, class U, class Allocator>
|
template <class Archive, class U, class Allocator, class Options>
|
||||||
inline void serialize(
|
inline void serialize(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int file_version) {
|
||||||
boost::container::vector<U, Allocator> & t,
|
|
||||||
const unsigned int file_version
|
|
||||||
){
|
|
||||||
boost::serialization::split_free(ar, t, file_version);
|
boost::serialization::split_free(ar, t, file_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
// split non-intrusive serialization function member into separate
|
// split non-intrusive serialization function member into separate
|
||||||
// non intrusive save/load member functions
|
// non intrusive save/load member functions
|
||||||
template<class Archive, class Allocator>
|
template <class Archive, class Allocator, class Options>
|
||||||
inline void serialize(
|
inline void serialize(Archive& ar, boost::container::vector<bool, Allocator, Options>& t,
|
||||||
Archive & ar,
|
const unsigned int file_version) {
|
||||||
boost::container::vector<bool, Allocator> & t,
|
|
||||||
const unsigned int file_version
|
|
||||||
){
|
|
||||||
boost::serialization::split_free(ar, t, file_version);
|
boost::serialization::split_free(ar, t, file_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // serialization
|
} // namespace serialization
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#include <boost/serialization/collection_traits.hpp>
|
#include <boost/serialization/collection_traits.hpp>
|
||||||
|
|
||||||
BOOST_SERIALIZATION_COLLECTION_TRAITS(boost::container::vector)
|
BOOST_SERIALIZATION_COLLECTION_TRAITS(boost::container::vector)
|
||||||
|
|
||||||
#endif // BOOST_SERIALIZATION_VECTOR_HPP
|
#endif // BOOST_SERIALIZATION_BOOST_VECTOR_HPP
|
||||||
|
|
|
@ -80,10 +80,7 @@ std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string n
|
||||||
return address_arbiter;
|
return address_arbiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type,
|
void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
VAddr address, s32 value, u64 nanoseconds) {
|
|
||||||
|
|
||||||
auto timeout_callback = [this](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
|
||||||
std::shared_ptr<WaitObject> object) {
|
std::shared_ptr<WaitObject> object) {
|
||||||
ASSERT(reason == ThreadWakeupReason::Timeout);
|
ASSERT(reason == ThreadWakeupReason::Timeout);
|
||||||
// Remove the newly-awakened thread from the Arbiter's waiting list.
|
// Remove the newly-awakened thread from the Arbiter's waiting list.
|
||||||
|
@ -91,6 +88,11 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi
|
||||||
waiting_threads.end());
|
waiting_threads.end());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type,
|
||||||
|
VAddr address, s32 value, u64 nanoseconds) {
|
||||||
|
|
||||||
|
auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this());
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
// Signal thread(s) waiting for arbitrate address...
|
// Signal thread(s) waiting for arbitrate address...
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <boost/serialization/vector.hpp>
|
#include <boost/serialization/vector.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
// Address arbiters are an underlying kernel synchronization object that can be created/used via
|
// Address arbiters are an underlying kernel synchronization object that can be created/used via
|
||||||
|
@ -34,7 +35,7 @@ enum class ArbitrationType : u32 {
|
||||||
DecrementAndWaitIfLessThanWithTimeout,
|
DecrementAndWaitIfLessThanWithTimeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressArbiter final : public Object {
|
class AddressArbiter final : public Object, public WakeupCallback {
|
||||||
public:
|
public:
|
||||||
explicit AddressArbiter(KernelSystem& kernel);
|
explicit AddressArbiter(KernelSystem& kernel);
|
||||||
~AddressArbiter() override;
|
~AddressArbiter() override;
|
||||||
|
@ -56,6 +57,9 @@ public:
|
||||||
ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address,
|
ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address,
|
||||||
s32 value, u64 nanoseconds);
|
s32 value, u64 nanoseconds);
|
||||||
|
|
||||||
|
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<WaitObject> object);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelSystem& kernel;
|
KernelSystem& kernel;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,46 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class HLERequestContext::ThreadCallback : public Kernel::WakeupCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
ThreadCallback(std::shared_ptr<HLERequestContext> context_,
|
||||||
|
std::shared_ptr<HLERequestContext::WakeupCallback> callback_)
|
||||||
|
: context(context_), callback(callback_) {}
|
||||||
|
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<WaitObject> object) {
|
||||||
|
ASSERT(thread->status == ThreadStatus::WaitHleEvent);
|
||||||
|
if (callback) {
|
||||||
|
callback->WakeUp(thread, *context, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& process = thread->owner_process;
|
||||||
|
// We must copy the entire command buffer *plus* the entire static buffers area, since
|
||||||
|
// the translation might need to read from it in order to retrieve the StaticBuffer
|
||||||
|
// target addresses.
|
||||||
|
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
||||||
|
Memory::MemorySystem& memory = context->kernel.memory;
|
||||||
|
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||||
|
cmd_buff.size() * sizeof(u32));
|
||||||
|
context->WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
||||||
|
// Copy the translated command buffer back into the thread's command buffer area.
|
||||||
|
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||||
|
cmd_buff.size() * sizeof(u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ThreadCallback() = default;
|
||||||
|
std::shared_ptr<HLERequestContext::WakeupCallback> callback{};
|
||||||
|
std::shared_ptr<HLERequestContext> context{};
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& callback;
|
||||||
|
ar& context;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
SessionRequestHandler::SessionInfo::SessionInfo(std::shared_ptr<ServerSession> session,
|
SessionRequestHandler::SessionInfo::SessionInfo(std::shared_ptr<ServerSession> session,
|
||||||
std::unique_ptr<SessionDataBase> data)
|
std::unique_ptr<SessionDataBase> data)
|
||||||
: session(std::move(session)), data(std::move(data)) {}
|
: session(std::move(session)), data(std::move(data)) {}
|
||||||
|
@ -33,34 +73,16 @@ void SessionRequestHandler::ClientDisconnected(std::shared_ptr<ServerSession> se
|
||||||
connected_sessions.end());
|
connected_sessions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& reason,
|
std::shared_ptr<Event> HLERequestContext::SleepClientThread(
|
||||||
std::chrono::nanoseconds timeout,
|
const std::string& reason, std::chrono::nanoseconds timeout,
|
||||||
WakeupCallback&& callback) {
|
std::shared_ptr<WakeupCallback> callback) {
|
||||||
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
||||||
thread->wakeup_callback = [context = *this,
|
thread->wakeup_callback = std::make_shared<ThreadCallback>(shared_from_this(), callback);
|
||||||
callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
|
||||||
std::shared_ptr<WaitObject> object) mutable {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitHleEvent);
|
|
||||||
callback(thread, context, reason);
|
|
||||||
|
|
||||||
auto& process = thread->owner_process;
|
|
||||||
// We must copy the entire command buffer *plus* the entire static buffers area, since
|
|
||||||
// the translation might need to read from it in order to retrieve the StaticBuffer
|
|
||||||
// target addresses.
|
|
||||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
|
||||||
Memory::MemorySystem& memory = context.kernel.memory;
|
|
||||||
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
|
||||||
cmd_buff.size() * sizeof(u32));
|
|
||||||
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
|
||||||
// Copy the translated command buffer back into the thread's command buffer area.
|
|
||||||
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
|
||||||
cmd_buff.size() * sizeof(u32));
|
|
||||||
};
|
|
||||||
|
|
||||||
auto event = kernel.CreateEvent(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
|
auto event = kernel.CreateEvent(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
|
||||||
thread->status = ThreadStatus::WaitHleEvent;
|
thread->status = ThreadStatus::WaitHleEvent;
|
||||||
thread->wait_objects = {event};
|
thread->wait_objects = {event};
|
||||||
event->AddWaitingThread(SharedFrom(thread));
|
event->AddWaitingThread(thread);
|
||||||
|
|
||||||
if (timeout.count() > 0)
|
if (timeout.count() > 0)
|
||||||
thread->WakeAfterDelay(timeout.count());
|
thread->WakeAfterDelay(timeout.count());
|
||||||
|
@ -68,8 +90,10 @@ std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& r
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HLERequestContext::HLERequestContext() : kernel(Core::Global<KernelSystem>()) {}
|
||||||
|
|
||||||
HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
|
HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
|
||||||
Thread* thread)
|
std::shared_ptr<Thread> thread)
|
||||||
: kernel(kernel), session(std::move(session)), thread(thread) {
|
: kernel(kernel), session(std::move(session)), thread(thread) {
|
||||||
cmd_buf[0] = 0;
|
cmd_buf[0] = 0;
|
||||||
}
|
}
|
||||||
|
@ -98,8 +122,9 @@ void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector<u8> data) {
|
||||||
static_buffers[buffer_id] = std::move(data);
|
static_buffers[buffer_id] = std::move(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
|
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(
|
||||||
Process& src_process) {
|
const u32_le* src_cmdbuf, std::shared_ptr<Process> src_process_) {
|
||||||
|
auto& src_process = *src_process_;
|
||||||
IPC::Header header{src_cmdbuf[0]};
|
IPC::Header header{src_cmdbuf[0]};
|
||||||
|
|
||||||
std::size_t untranslated_size = 1u + header.normal_params_size;
|
std::size_t untranslated_size = 1u + header.normal_params_size;
|
||||||
|
@ -158,7 +183,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
||||||
}
|
}
|
||||||
case IPC::DescriptorType::MappedBuffer: {
|
case IPC::DescriptorType::MappedBuffer: {
|
||||||
u32 next_id = static_cast<u32>(request_mapped_buffers.size());
|
u32 next_id = static_cast<u32>(request_mapped_buffers.size());
|
||||||
request_mapped_buffers.emplace_back(kernel.memory, src_process, descriptor,
|
request_mapped_buffers.emplace_back(kernel.memory, src_process_, descriptor,
|
||||||
src_cmdbuf[i], next_id);
|
src_cmdbuf[i], next_id);
|
||||||
cmd_buf[i++] = next_id;
|
cmd_buf[i++] = next_id;
|
||||||
break;
|
break;
|
||||||
|
@ -170,7 +195,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
||||||
|
|
||||||
if (should_record) {
|
if (should_record) {
|
||||||
std::vector<u32> translated_cmdbuf{cmd_buf.begin(), cmd_buf.begin() + command_size};
|
std::vector<u32> translated_cmdbuf{cmd_buf.begin(), cmd_buf.begin() + command_size};
|
||||||
kernel.GetIPCRecorder().SetRequestInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
|
kernel.GetIPCRecorder().SetRequestInfo(thread, std::move(untranslated_cmdbuf),
|
||||||
std::move(translated_cmdbuf));
|
std::move(translated_cmdbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +273,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
|
||||||
|
|
||||||
if (should_record) {
|
if (should_record) {
|
||||||
std::vector<u32> translated_cmdbuf{dst_cmdbuf, dst_cmdbuf + command_size};
|
std::vector<u32> translated_cmdbuf{dst_cmdbuf, dst_cmdbuf + command_size};
|
||||||
kernel.GetIPCRecorder().SetReplyInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
|
kernel.GetIPCRecorder().SetReplyInfo(thread, std::move(untranslated_cmdbuf),
|
||||||
std::move(translated_cmdbuf));
|
std::move(translated_cmdbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,13 +287,15 @@ MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) {
|
||||||
|
|
||||||
void HLERequestContext::ReportUnimplemented() const {
|
void HLERequestContext::ReportUnimplemented() const {
|
||||||
if (kernel.GetIPCRecorder().IsEnabled()) {
|
if (kernel.GetIPCRecorder().IsEnabled()) {
|
||||||
kernel.GetIPCRecorder().SetHLEUnimplemented(SharedFrom(thread));
|
kernel.GetIPCRecorder().SetHLEUnimplemented(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
|
MappedBuffer::MappedBuffer() : memory(&Core::Global<Core::System>().Memory()) {}
|
||||||
VAddr address, u32 id)
|
|
||||||
: memory(&memory), id(id), address(address), process(&process) {
|
MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process,
|
||||||
|
u32 descriptor, VAddr address, u32 id)
|
||||||
|
: memory(&memory), id(id), address(address), process(process) {
|
||||||
IPC::MappedBufferDescInfo desc{descriptor};
|
IPC::MappedBufferDescInfo desc{descriptor};
|
||||||
size = desc.size;
|
size = desc.size;
|
||||||
perms = desc.perms;
|
perms = desc.perms;
|
||||||
|
@ -287,3 +314,5 @@ void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
SERIALIZE_EXPORT_IMPL(Kernel::HLERequestContext::ThreadCallback)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <boost/serialization/unique_ptr.hpp>
|
#include <boost/serialization/unique_ptr.hpp>
|
||||||
#include <boost/serialization/vector.hpp>
|
#include <boost/serialization/vector.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/serialization/boost_small_vector.hpp"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
@ -127,7 +128,7 @@ private:
|
||||||
|
|
||||||
class MappedBuffer {
|
class MappedBuffer {
|
||||||
public:
|
public:
|
||||||
MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
|
MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process, u32 descriptor,
|
||||||
VAddr address, u32 id);
|
VAddr address, u32 id);
|
||||||
|
|
||||||
// interface for service
|
// interface for service
|
||||||
|
@ -151,9 +152,21 @@ private:
|
||||||
Memory::MemorySystem* memory;
|
Memory::MemorySystem* memory;
|
||||||
u32 id;
|
u32 id;
|
||||||
VAddr address;
|
VAddr address;
|
||||||
const Process* process;
|
std::shared_ptr<Process> process;
|
||||||
std::size_t size;
|
u32 size;
|
||||||
IPC::MappedBufferPermissions perms;
|
IPC::MappedBufferPermissions perms;
|
||||||
|
|
||||||
|
MappedBuffer();
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& id;
|
||||||
|
ar& address;
|
||||||
|
ar& process;
|
||||||
|
ar& size;
|
||||||
|
ar& perms;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,9 +198,10 @@ private:
|
||||||
* id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
|
* id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
|
||||||
* needed in this case, though.
|
* needed in this case, though.
|
||||||
*/
|
*/
|
||||||
class HLERequestContext {
|
class HLERequestContext : std::enable_shared_from_this<HLERequestContext> {
|
||||||
public:
|
public:
|
||||||
HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session, Thread* thread);
|
HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
|
||||||
|
std::shared_ptr<Thread> thread);
|
||||||
~HLERequestContext();
|
~HLERequestContext();
|
||||||
|
|
||||||
/// Returns a pointer to the IPC command buffer for this request.
|
/// Returns a pointer to the IPC command buffer for this request.
|
||||||
|
@ -203,8 +217,12 @@ public:
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
using WakeupCallback = std::function<void(
|
class WakeupCallback {
|
||||||
std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
|
public:
|
||||||
|
virtual ~WakeupCallback() = default;
|
||||||
|
virtual void WakeUp(std::shared_ptr<Thread> thread, HLERequestContext& context,
|
||||||
|
ThreadWakeupReason reason) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the specified guest thread to sleep until the returned event is signaled or until the
|
* Puts the specified guest thread to sleep until the returned event is signaled or until the
|
||||||
|
@ -219,7 +237,7 @@ public:
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<Event> SleepClientThread(const std::string& reason,
|
std::shared_ptr<Event> SleepClientThread(const std::string& reason,
|
||||||
std::chrono::nanoseconds timeout,
|
std::chrono::nanoseconds timeout,
|
||||||
WakeupCallback&& callback);
|
std::shared_ptr<WakeupCallback> callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a object id from the request command buffer into a pointer to an object. See the
|
* Resolves a object id from the request command buffer into a pointer to an object. See the
|
||||||
|
@ -259,26 +277,43 @@ public:
|
||||||
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
|
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
|
||||||
|
|
||||||
/// Populates this context with data from the requesting process/thread.
|
/// Populates this context with data from the requesting process/thread.
|
||||||
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process);
|
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
|
||||||
|
std::shared_ptr<Process> src_process);
|
||||||
/// Writes data from this context back to the requesting process/thread.
|
/// Writes data from this context back to the requesting process/thread.
|
||||||
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const;
|
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const;
|
||||||
|
|
||||||
/// Reports an unimplemented function.
|
/// Reports an unimplemented function.
|
||||||
void ReportUnimplemented() const;
|
void ReportUnimplemented() const;
|
||||||
|
|
||||||
|
class ThreadCallback;
|
||||||
|
friend class ThreadCallback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelSystem& kernel;
|
KernelSystem& kernel;
|
||||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||||
std::shared_ptr<ServerSession> session;
|
std::shared_ptr<ServerSession> session;
|
||||||
Thread* thread;
|
std::shared_ptr<Thread> thread;
|
||||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||||
boost::container::small_vector<std::shared_ptr<Object>, 8> request_handles;
|
boost::container::small_vector<std::shared_ptr<Object>, 8> request_handles;
|
||||||
// The static buffers will be created when the IPC request is translated.
|
// The static buffers will be created when the IPC request is translated.
|
||||||
std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers;
|
std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers;
|
||||||
// The mapped buffers will be created when the IPC request is translated
|
// The mapped buffers will be created when the IPC request is translated
|
||||||
boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers;
|
boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers;
|
||||||
|
|
||||||
|
HLERequestContext();
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& cmd_buf;
|
||||||
|
ar& session;
|
||||||
|
ar& thread;
|
||||||
|
ar& request_handles;
|
||||||
|
ar& static_buffers;
|
||||||
|
ar& request_mapped_buffers;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
BOOST_CLASS_EXPORT_KEY(Kernel::SessionRequestHandler::SessionDataBase)
|
BOOST_CLASS_EXPORT_KEY(Kernel::SessionRequestHandler::SessionDataBase)
|
||||||
|
BOOST_CLASS_EXPORT_KEY(Kernel::HLERequestContext::ThreadCallback)
|
||||||
|
|
|
@ -72,7 +72,7 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
||||||
if (handle == CurrentThread) {
|
if (handle == CurrentThread) {
|
||||||
object = src_thread;
|
object = src_thread;
|
||||||
} else if (handle == CurrentProcess) {
|
} else if (handle == CurrentProcess) {
|
||||||
object = SharedFrom(src_process);
|
object = src_process;
|
||||||
} else if (handle != 0) {
|
} else if (handle != 0) {
|
||||||
object = src_process->handle_table.GetGeneric(handle);
|
object = src_process->handle_table.GetGeneric(handle);
|
||||||
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ void Recorder::RegisterRequest(const std::shared_ptr<Kernel::ClientSession>& cli
|
||||||
|
|
||||||
RequestRecord record = {/* id */ ++record_count,
|
RequestRecord record = {/* id */ ++record_count,
|
||||||
/* status */ RequestStatus::Sent,
|
/* status */ RequestStatus::Sent,
|
||||||
/* client_process */ GetObjectInfo(client_thread->owner_process),
|
/* client_process */ GetObjectInfo(client_thread->owner_process.get()),
|
||||||
/* client_thread */ GetObjectInfo(client_thread.get()),
|
/* client_thread */ GetObjectInfo(client_thread.get()),
|
||||||
/* client_session */ GetObjectInfo(client_session.get()),
|
/* client_session */ GetObjectInfo(client_session.get()),
|
||||||
/* client_port */ GetObjectInfo(client_session->parent->port.get()),
|
/* client_port */ GetObjectInfo(client_session->parent->port.get()),
|
||||||
|
@ -82,7 +82,7 @@ void Recorder::SetRequestInfo(const std::shared_ptr<Kernel::Thread>& client_thre
|
||||||
record.translated_request_cmdbuf = std::move(translated_cmdbuf);
|
record.translated_request_cmdbuf = std::move(translated_cmdbuf);
|
||||||
|
|
||||||
if (server_thread) {
|
if (server_thread) {
|
||||||
record.server_process = GetObjectInfo(server_thread->owner_process);
|
record.server_process = GetObjectInfo(server_thread->owner_process.get());
|
||||||
record.server_thread = GetObjectInfo(server_thread.get());
|
record.server_thread = GetObjectInfo(server_thread.get());
|
||||||
} else {
|
} else {
|
||||||
record.is_hle = true;
|
record.is_hle = true;
|
||||||
|
|
|
@ -134,7 +134,7 @@ public:
|
||||||
*/
|
*/
|
||||||
ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point,
|
ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point,
|
||||||
u32 priority, u32 arg, s32 processor_id,
|
u32 priority, u32 arg, s32 processor_id,
|
||||||
VAddr stack_top, Process& owner_process);
|
VAddr stack_top, std::shared_ptr<Process> owner_process);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a semaphore.
|
* Creates a semaphore.
|
||||||
|
|
|
@ -71,12 +71,12 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
|
||||||
// If this ServerSession has an associated HLE handler, forward the request to it.
|
// If this ServerSession has an associated HLE handler, forward the request to it.
|
||||||
if (hle_handler != nullptr) {
|
if (hle_handler != nullptr) {
|
||||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buf;
|
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buf;
|
||||||
Kernel::Process* current_process = thread->owner_process;
|
auto current_process = thread->owner_process;
|
||||||
kernel.memory.ReadBlock(*current_process, thread->GetCommandBufferAddress(), cmd_buf.data(),
|
kernel.memory.ReadBlock(*current_process, thread->GetCommandBufferAddress(), cmd_buf.data(),
|
||||||
cmd_buf.size() * sizeof(u32));
|
cmd_buf.size() * sizeof(u32));
|
||||||
|
|
||||||
Kernel::HLERequestContext context(kernel, SharedFrom(this), thread.get());
|
Kernel::HLERequestContext context(kernel, SharedFrom(this), thread);
|
||||||
context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), *current_process);
|
context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process);
|
||||||
|
|
||||||
hle_handler->HandleSyncRequest(context);
|
hle_handler->HandleSyncRequest(context);
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,7 @@ void SVC::ExitProcess() {
|
||||||
// Stop all the process threads that are currently waiting for objects.
|
// Stop all the process threads that are currently waiting for objects.
|
||||||
auto& thread_list = kernel.GetThreadManager().GetThreadList();
|
auto& thread_list = kernel.GetThreadManager().GetThreadList();
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->owner_process != current_process.get())
|
if (thread->owner_process != current_process)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (thread.get() == kernel.GetThreadManager().GetCurrentThread())
|
if (thread.get() == kernel.GetThreadManager().GetCurrentThread())
|
||||||
|
@ -403,6 +403,73 @@ ResultCode SVC::CloseHandle(Handle handle) {
|
||||||
return kernel.GetCurrentProcess()->handle_table.Close(handle);
|
return kernel.GetCurrentProcess()->handle_table.Close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::MemorySystem& memory,
|
||||||
|
std::shared_ptr<ServerSession> server_session,
|
||||||
|
std::shared_ptr<Thread> thread);
|
||||||
|
|
||||||
|
class SVC_SyncCallback : public Kernel::WakeupCallback {
|
||||||
|
public:
|
||||||
|
SVC_SyncCallback(bool do_output_) : do_output(do_output_) {}
|
||||||
|
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<WaitObject> object) {
|
||||||
|
|
||||||
|
if (reason == ThreadWakeupReason::Timeout) {
|
||||||
|
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||||
|
|
||||||
|
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||||
|
|
||||||
|
// The wait_all case does not update the output index.
|
||||||
|
if (do_output) {
|
||||||
|
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool do_output;
|
||||||
|
|
||||||
|
SVC_SyncCallback() = default;
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& do_output;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SVC_IPCCallback : public Kernel::WakeupCallback {
|
||||||
|
public:
|
||||||
|
SVC_IPCCallback(Core::System& system_) : system(system_) {}
|
||||||
|
|
||||||
|
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<WaitObject> object) {
|
||||||
|
|
||||||
|
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||||
|
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||||
|
|
||||||
|
ResultCode result = RESULT_SUCCESS;
|
||||||
|
|
||||||
|
if (object->GetHandleType() == HandleType::ServerSession) {
|
||||||
|
auto server_session = DynamicObjectCast<ServerSession>(object);
|
||||||
|
result = ReceiveIPCRequest(system.Kernel(), system.Memory(), server_session, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->SetWaitSynchronizationResult(result);
|
||||||
|
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::System& system;
|
||||||
|
|
||||||
|
SVC_IPCCallback() : system(Core::Global<Core::System>()) {}
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {}
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
||||||
ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
||||||
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
|
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
|
||||||
|
@ -426,21 +493,7 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
||||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||||
thread->WakeAfterDelay(nano_seconds);
|
thread->WakeAfterDelay(nano_seconds);
|
||||||
|
|
||||||
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
|
||||||
std::shared_ptr<WaitObject> object) {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
|
||||||
|
|
||||||
if (reason == ThreadWakeupReason::Timeout) {
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
|
||||||
|
|
||||||
// WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
|
|
||||||
// don't have to do anything else here.
|
|
||||||
};
|
|
||||||
|
|
||||||
system.PrepareReschedule();
|
system.PrepareReschedule();
|
||||||
|
|
||||||
|
@ -515,20 +568,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
|
||||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||||
thread->WakeAfterDelay(nano_seconds);
|
thread->WakeAfterDelay(nano_seconds);
|
||||||
|
|
||||||
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
|
||||||
std::shared_ptr<WaitObject> object) {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitSynchAll);
|
|
||||||
|
|
||||||
if (reason == ThreadWakeupReason::Timeout) {
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
|
||||||
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
|
||||||
// The wait_all case does not update the output index.
|
|
||||||
};
|
|
||||||
|
|
||||||
system.PrepareReschedule();
|
system.PrepareReschedule();
|
||||||
|
|
||||||
|
@ -575,20 +615,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
|
||||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||||
thread->WakeAfterDelay(nano_seconds);
|
thread->WakeAfterDelay(nano_seconds);
|
||||||
|
|
||||||
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(true);
|
||||||
std::shared_ptr<WaitObject> object) {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
|
||||||
|
|
||||||
if (reason == ThreadWakeupReason::Timeout) {
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
|
||||||
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
|
||||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
|
||||||
};
|
|
||||||
|
|
||||||
system.PrepareReschedule();
|
system.PrepareReschedule();
|
||||||
|
|
||||||
|
@ -730,22 +757,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
|
|
||||||
thread->wait_objects = std::move(objects);
|
thread->wait_objects = std::move(objects);
|
||||||
|
|
||||||
thread->wakeup_callback = [& kernel = this->kernel, &memory = this->memory](
|
thread->wakeup_callback = std::make_shared<SVC_IPCCallback>(system);
|
||||||
ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
|
||||||
std::shared_ptr<WaitObject> object) {
|
|
||||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
|
||||||
|
|
||||||
ResultCode result = RESULT_SUCCESS;
|
|
||||||
|
|
||||||
if (object->GetHandleType() == HandleType::ServerSession) {
|
|
||||||
auto server_session = DynamicObjectCast<ServerSession>(object);
|
|
||||||
result = ReceiveIPCRequest(kernel, memory, server_session, thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->SetWaitSynchronizationResult(result);
|
|
||||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
|
||||||
};
|
|
||||||
|
|
||||||
system.PrepareReschedule();
|
system.PrepareReschedule();
|
||||||
|
|
||||||
|
@ -911,7 +923,7 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
|
||||||
|
|
||||||
CASCADE_RESULT(std::shared_ptr<Thread> thread,
|
CASCADE_RESULT(std::shared_ptr<Thread> thread,
|
||||||
kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top,
|
kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top,
|
||||||
*current_process));
|
current_process));
|
||||||
|
|
||||||
thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
|
thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
|
||||||
FPSCR_ROUND_TOZERO); // 0x03C00000
|
FPSCR_ROUND_TOZERO); // 0x03C00000
|
||||||
|
@ -1020,7 +1032,7 @@ ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
const std::shared_ptr<Process> process = SharedFrom(thread->owner_process);
|
const std::shared_ptr<Process> process = thread->owner_process;
|
||||||
|
|
||||||
ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle);
|
ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle);
|
||||||
|
|
||||||
|
@ -1611,3 +1623,6 @@ void SVCContext::CallSVC(u32 immediate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
SERIALIZE_EXPORT_IMPL(Kernel::SVC_SyncCallback)
|
||||||
|
SERIALIZE_EXPORT_IMPL(Kernel::SVC_IPCCallback)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <boost/serialization/export.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -25,4 +26,10 @@ private:
|
||||||
std::unique_ptr<SVC> impl;
|
std::unique_ptr<SVC> impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SVC_SyncCallback;
|
||||||
|
class SVC_IPCCallback;
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
BOOST_CLASS_EXPORT_KEY(Kernel::SVC_SyncCallback)
|
||||||
|
BOOST_CLASS_EXPORT_KEY(Kernel::SVC_IPCCallback)
|
||||||
|
|
|
@ -48,7 +48,7 @@ void Thread::serialize(Archive& ar, const unsigned int file_version) {
|
||||||
ar& wait_objects;
|
ar& wait_objects;
|
||||||
ar& wait_address;
|
ar& wait_address;
|
||||||
ar& name;
|
ar& name;
|
||||||
// TODO: How the hell to do wakeup_callback
|
ar& wakeup_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
SERIALIZE_IMPL(Thread)
|
SERIALIZE_IMPL(Thread)
|
||||||
|
@ -138,8 +138,8 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||||
ready_queue.remove(new_thread->current_priority, new_thread);
|
ready_queue.remove(new_thread->current_priority, new_thread);
|
||||||
new_thread->status = ThreadStatus::Running;
|
new_thread->status = ThreadStatus::Running;
|
||||||
|
|
||||||
if (previous_process.get() != current_thread->owner_process) {
|
if (previous_process != current_thread->owner_process) {
|
||||||
kernel.SetCurrentProcess(SharedFrom(current_thread->owner_process));
|
kernel.SetCurrentProcess(current_thread->owner_process);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->LoadContext(new_thread->context);
|
cpu->LoadContext(new_thread->context);
|
||||||
|
@ -196,7 +196,7 @@ void ThreadManager::ThreadWakeupCallback(u64 thread_id, s64 cycles_late) {
|
||||||
|
|
||||||
// Invoke the wakeup callback before clearing the wait objects
|
// Invoke the wakeup callback before clearing the wait objects
|
||||||
if (thread->wakeup_callback)
|
if (thread->wakeup_callback)
|
||||||
thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr);
|
thread->wakeup_callback->WakeUp(ThreadWakeupReason::Timeout, thread, nullptr);
|
||||||
|
|
||||||
// Remove the thread from each of its waiting objects' waitlists
|
// Remove the thread from each of its waiting objects' waitlists
|
||||||
for (auto& object : thread->wait_objects)
|
for (auto& object : thread->wait_objects)
|
||||||
|
@ -313,10 +313,9 @@ static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContex
|
||||||
context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
|
context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point,
|
ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
|
||||||
u32 priority, u32 arg,
|
std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top,
|
||||||
s32 processor_id, VAddr stack_top,
|
std::shared_ptr<Process> owner_process) {
|
||||||
Process& owner_process) {
|
|
||||||
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
||||||
if (priority > ThreadPrioLowest) {
|
if (priority > ThreadPrioLowest) {
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
||||||
|
@ -330,7 +329,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
||||||
|
|
||||||
// TODO(yuriks): Other checks, returning 0xD9001BEA
|
// TODO(yuriks): Other checks, returning 0xD9001BEA
|
||||||
|
|
||||||
if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
|
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
|
||||||
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
|
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
|
||||||
// TODO: Verify error
|
// TODO: Verify error
|
||||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||||
|
@ -353,10 +352,10 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
||||||
thread->wait_address = 0;
|
thread->wait_address = 0;
|
||||||
thread->name = std::move(name);
|
thread->name = std::move(name);
|
||||||
thread_manager->wakeup_callback_table[thread->thread_id] = thread.get();
|
thread_manager->wakeup_callback_table[thread->thread_id] = thread.get();
|
||||||
thread->owner_process = &owner_process;
|
thread->owner_process = owner_process;
|
||||||
|
|
||||||
// Find the next available TLS index, and mark it as used
|
// Find the next available TLS index, and mark it as used
|
||||||
auto& tls_slots = owner_process.tls_slots;
|
auto& tls_slots = owner_process->tls_slots;
|
||||||
|
|
||||||
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
||||||
|
|
||||||
|
@ -372,13 +371,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
||||||
"Not enough space in region to allocate a new TLS page for thread");
|
"Not enough space in region to allocate a new TLS page for thread");
|
||||||
return ERR_OUT_OF_MEMORY;
|
return ERR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
owner_process.memory_used += Memory::PAGE_SIZE;
|
owner_process->memory_used += Memory::PAGE_SIZE;
|
||||||
|
|
||||||
tls_slots.emplace_back(0); // The page is completely available at the start
|
tls_slots.emplace_back(0); // The page is completely available at the start
|
||||||
available_page = tls_slots.size() - 1;
|
available_page = tls_slots.size() - 1;
|
||||||
available_slot = 0; // Use the first slot in the new page
|
available_slot = 0; // Use the first slot in the new page
|
||||||
|
|
||||||
auto& vm_manager = owner_process.vm_manager;
|
auto& vm_manager = owner_process->vm_manager;
|
||||||
|
|
||||||
// Map the page to the current process' address space.
|
// Map the page to the current process' address space.
|
||||||
vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
||||||
|
@ -391,7 +390,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
||||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||||
available_slot * Memory::TLS_ENTRY_SIZE;
|
available_slot * Memory::TLS_ENTRY_SIZE;
|
||||||
|
|
||||||
memory.ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
|
memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
|
||||||
|
|
||||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||||
// to initialize the context
|
// to initialize the context
|
||||||
|
@ -438,7 +437,7 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
|
||||||
// Initialize new "main" thread
|
// Initialize new "main" thread
|
||||||
auto thread_res =
|
auto thread_res =
|
||||||
kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
|
kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
|
||||||
Memory::HEAP_VADDR_END, *owner_process);
|
Memory::HEAP_VADDR_END, owner_process);
|
||||||
|
|
||||||
std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
|
std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,15 @@ enum class ThreadWakeupReason {
|
||||||
Timeout // The thread was woken up due to a wait timeout.
|
Timeout // The thread was woken up due to a wait timeout.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Thread;
|
||||||
|
|
||||||
|
class WakeupCallback {
|
||||||
|
public:
|
||||||
|
virtual ~WakeupCallback() = default;
|
||||||
|
virtual void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<WaitObject> object) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class ThreadManager {
|
class ThreadManager {
|
||||||
public:
|
public:
|
||||||
explicit ThreadManager(Kernel::KernelSystem& kernel);
|
explicit ThreadManager(Kernel::KernelSystem& kernel);
|
||||||
|
@ -300,7 +309,7 @@ public:
|
||||||
/// Mutexes that this thread is currently waiting for.
|
/// Mutexes that this thread is currently waiting for.
|
||||||
boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes;
|
boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes;
|
||||||
|
|
||||||
Process* owner_process; ///< Process that owns this thread
|
std::shared_ptr<Process> owner_process; ///< Process that owns this thread
|
||||||
|
|
||||||
/// Objects that the thread is waiting on, in the same order as they were
|
/// Objects that the thread is waiting on, in the same order as they were
|
||||||
// passed to WaitSynchronization1/N.
|
// passed to WaitSynchronization1/N.
|
||||||
|
@ -310,12 +319,10 @@ public:
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
using WakeupCallback = void(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
|
||||||
std::shared_ptr<WaitObject> object);
|
|
||||||
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
||||||
// was waiting via WaitSynchronizationN then the object will be the last object that became
|
// was waiting via WaitSynchronizationN then the object will be the last object that became
|
||||||
// available. In case of a timeout, the object will be nullptr.
|
// available. In case of a timeout, the object will be nullptr.
|
||||||
std::function<WakeupCallback> wakeup_callback;
|
std::shared_ptr<WakeupCallback> wakeup_callback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ThreadManager& thread_manager;
|
ThreadManager& thread_manager;
|
||||||
|
|
|
@ -80,7 +80,7 @@ void WaitObject::WakeupAllWaitingThreads() {
|
||||||
|
|
||||||
// Invoke the wakeup callback before clearing the wait objects
|
// Invoke the wakeup callback before clearing the wait objects
|
||||||
if (thread->wakeup_callback)
|
if (thread->wakeup_callback)
|
||||||
thread->wakeup_callback(ThreadWakeupReason::Signal, thread, SharedFrom(this));
|
thread->wakeup_callback->WakeUp(ThreadWakeupReason::Signal, thread, SharedFrom(this));
|
||||||
|
|
||||||
for (auto& object : thread->wait_objects)
|
for (auto& object : thread->wait_objects)
|
||||||
object->RemoveWaitingThread(thread.get());
|
object->RemoveWaitingThread(thread.get());
|
||||||
|
|
|
@ -71,12 +71,7 @@ void File::Read(Kernel::HLERequestContext& ctx) {
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)};
|
std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)};
|
||||||
ctx.SleepClientThread("file::read", read_timeout_ns,
|
ctx.SleepClientThread("file::read", read_timeout_ns, nullptr);
|
||||||
[](std::shared_ptr<Kernel::Thread> /*thread*/,
|
|
||||||
Kernel::HLERequestContext& /*ctx*/,
|
|
||||||
Kernel::ThreadWakeupReason /*reason*/) {
|
|
||||||
// Nothing to do here
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::Write(Kernel::HLERequestContext& ctx) {
|
void File::Write(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
|
@ -76,12 +76,7 @@ void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_ERROR(Service_FS, "failed to get a handle for file {}", file_path.DebugStr());
|
LOG_ERROR(Service_FS, "failed to get a handle for file {}", file_path.DebugStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SleepClientThread("fs_user::open", open_timeout_ns,
|
ctx.SleepClientThread("fs_user::open", open_timeout_ns, nullptr);
|
||||||
[](std::shared_ptr<Kernel::Thread> /*thread*/,
|
|
||||||
Kernel::HLERequestContext& /*ctx*/,
|
|
||||||
Kernel::ThreadWakeupReason /*reason*/) {
|
|
||||||
// Nothing to do here
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
|
void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -134,12 +129,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
|
||||||
file_path.DebugStr(), mode.hex, attributes);
|
file_path.DebugStr(), mode.hex, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SleepClientThread("fs_user::open_directly", open_timeout_ns,
|
ctx.SleepClientThread("fs_user::open_directly", open_timeout_ns, nullptr);
|
||||||
[](std::shared_ptr<Kernel::Thread> /*thread*/,
|
|
||||||
Kernel::HLERequestContext& /*ctx*/,
|
|
||||||
Kernel::ThreadWakeupReason /*reason*/) {
|
|
||||||
// Nothing to do here
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) {
|
void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
|
@ -1170,6 +1170,29 @@ void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NWM, "called");
|
LOG_DEBUG(Service_NWM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NWM_UDS::ThreadCallback : public Kernel::HLERequestContext::WakeupCallback {
|
||||||
|
public:
|
||||||
|
ThreadCallback(u16 command_id_) : command_id(command_id_) {}
|
||||||
|
|
||||||
|
void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
|
||||||
|
Kernel::ThreadWakeupReason reason) {
|
||||||
|
// TODO(B3N30): Add error handling for host full and timeout
|
||||||
|
IPC::RequestBuilder rb(ctx, command_id, 1, 0);
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
LOG_DEBUG(Service_NWM, "connection sequence finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ThreadCallback() = default;
|
||||||
|
u16 command_id;
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& command_id;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
||||||
const u8* network_info_buffer, std::size_t network_info_size,
|
const u8* network_info_buffer, std::size_t network_info_size,
|
||||||
u8 connection_type, std::vector<u8> passphrase) {
|
u8 connection_type, std::vector<u8> passphrase) {
|
||||||
|
@ -1183,15 +1206,8 @@ void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
||||||
// Since this timing is handled by core_timing it could differ from the 'real world' time
|
// Since this timing is handled by core_timing it could differ from the 'real world' time
|
||||||
static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000};
|
static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000};
|
||||||
|
|
||||||
connection_event = ctx.SleepClientThread(
|
connection_event = ctx.SleepClientThread("uds::ConnectToNetwork", UDSConnectionTimeout,
|
||||||
"uds::ConnectToNetwork", UDSConnectionTimeout,
|
std::make_shared<ThreadCallback>(command_id));
|
||||||
[command_id](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
|
|
||||||
Kernel::ThreadWakeupReason reason) {
|
|
||||||
// TODO(B3N30): Add error handling for host full and timeout
|
|
||||||
IPC::RequestBuilder rb(ctx, command_id, 1, 0);
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
LOG_DEBUG(Service_NWM, "connection sequence finished");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) {
|
void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -1418,3 +1434,5 @@ NWM_UDS::~NWM_UDS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::NWM
|
} // namespace Service::NWM
|
||||||
|
|
||||||
|
SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_UDS::ThreadCallback)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/serialization/export.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
@ -127,6 +128,8 @@ public:
|
||||||
explicit NWM_UDS(Core::System& system);
|
explicit NWM_UDS(Core::System& system);
|
||||||
~NWM_UDS();
|
~NWM_UDS();
|
||||||
|
|
||||||
|
class ThreadCallback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
@ -560,3 +563,4 @@ private:
|
||||||
|
|
||||||
SERVICE_CONSTRUCT(Service::NWM::NWM_UDS)
|
SERVICE_CONSTRUCT(Service::NWM::NWM_UDS)
|
||||||
BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_UDS)
|
BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_UDS)
|
||||||
|
BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_UDS::ThreadCallback)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include "common/archives.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
@ -71,6 +72,46 @@ void SRV::EnableNotification(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_SRV, "(STUBBED) called");
|
LOG_WARNING(Service_SRV, "(STUBBED) called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SRV::ThreadCallback : public Kernel::HLERequestContext::WakeupCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
ThreadCallback(Core::System& system_, std::string name_) : system(system_), name(name_) {}
|
||||||
|
|
||||||
|
void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
|
||||||
|
Kernel::ThreadWakeupReason reason) {
|
||||||
|
LOG_ERROR(Service_SRV, "called service={} wakeup", name);
|
||||||
|
auto client_port = system.ServiceManager().GetServicePort(name);
|
||||||
|
|
||||||
|
auto session = client_port.Unwrap()->Connect();
|
||||||
|
if (session.Succeeded()) {
|
||||||
|
LOG_DEBUG(Service_SRV, "called service={} -> session={}", name,
|
||||||
|
(*session)->GetObjectId());
|
||||||
|
IPC::RequestBuilder rb(ctx, 0x5, 1, 2);
|
||||||
|
rb.Push(session.Code());
|
||||||
|
rb.PushMoveObjects(std::move(session).Unwrap());
|
||||||
|
} else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED) {
|
||||||
|
LOG_ERROR(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name);
|
||||||
|
UNREACHABLE();
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, session.Code().raw);
|
||||||
|
IPC::RequestBuilder rb(ctx, 0x5, 1, 0);
|
||||||
|
rb.Push(session.Code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::System& system;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
ThreadCallback() : system(Core::Global<Core::System>()) {}
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& name;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SRV::GetServiceHandle service function
|
* SRV::GetServiceHandle service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -100,28 +141,7 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
// TODO(yuriks): Permission checks go here
|
// TODO(yuriks): Permission checks go here
|
||||||
|
|
||||||
auto get_handle = [name, this](std::shared_ptr<Kernel::Thread> thread,
|
auto get_handle = std::make_shared<ThreadCallback>(system, name);
|
||||||
Kernel::HLERequestContext& ctx,
|
|
||||||
Kernel::ThreadWakeupReason reason) {
|
|
||||||
LOG_ERROR(Service_SRV, "called service={} wakeup", name);
|
|
||||||
auto client_port = system.ServiceManager().GetServicePort(name);
|
|
||||||
|
|
||||||
auto session = client_port.Unwrap()->Connect();
|
|
||||||
if (session.Succeeded()) {
|
|
||||||
LOG_DEBUG(Service_SRV, "called service={} -> session={}", name,
|
|
||||||
(*session)->GetObjectId());
|
|
||||||
IPC::RequestBuilder rb(ctx, 0x5, 1, 2);
|
|
||||||
rb.Push(session.Code());
|
|
||||||
rb.PushMoveObjects(std::move(session).Unwrap());
|
|
||||||
} else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED) {
|
|
||||||
LOG_ERROR(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name);
|
|
||||||
UNREACHABLE();
|
|
||||||
} else {
|
|
||||||
LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, session.Code().raw);
|
|
||||||
IPC::RequestBuilder rb(ctx, 0x5, 1, 0);
|
|
||||||
rb.Push(session.Code());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto client_port = system.ServiceManager().GetServicePort(name);
|
auto client_port = system.ServiceManager().GetServicePort(name);
|
||||||
if (client_port.Failed()) {
|
if (client_port.Failed()) {
|
||||||
|
@ -266,3 +286,5 @@ SRV::SRV(Core::System& system) : ServiceFramework("srv:", 4), system(system) {
|
||||||
SRV::~SRV() = default;
|
SRV::~SRV() = default;
|
||||||
|
|
||||||
} // namespace Service::SM
|
} // namespace Service::SM
|
||||||
|
|
||||||
|
SERIALIZE_EXPORT_IMPL(Service::SM::SRV::ThreadCallback)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <boost/serialization/export.hpp>
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -25,6 +26,8 @@ public:
|
||||||
explicit SRV(Core::System& system);
|
explicit SRV(Core::System& system);
|
||||||
~SRV();
|
~SRV();
|
||||||
|
|
||||||
|
class ThreadCallback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RegisterClient(Kernel::HLERequestContext& ctx);
|
void RegisterClient(Kernel::HLERequestContext& ctx);
|
||||||
void EnableNotification(Kernel::HLERequestContext& ctx);
|
void EnableNotification(Kernel::HLERequestContext& ctx);
|
||||||
|
@ -40,3 +43,5 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::SM
|
} // namespace Service::SM
|
||||||
|
|
||||||
|
BOOST_CLASS_EXPORT_KEY(Service::SM::SRV::ThreadCallback)
|
||||||
|
|
|
@ -37,7 +37,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
IPC::MakeHeader(0x1234, 0, 0),
|
IPC::MakeHeader(0x1234, 0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
REQUIRE(context.CommandBuffer()[0] == 0x12340000);
|
REQUIRE(context.CommandBuffer()[0] == 0x12340000);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0xAABBCCDD,
|
0xAABBCCDD,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(output[1] == 0x12345678);
|
REQUIRE(output[1] == 0x12345678);
|
||||||
|
@ -67,7 +67,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
a_handle,
|
a_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
||||||
|
@ -83,7 +83,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
a_handle,
|
a_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
||||||
|
@ -103,7 +103,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
process->handle_table.Create(c).Unwrap(),
|
process->handle_table.Create(c).Unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
REQUIRE(context.GetIncomingHandle(output[2]) == a);
|
||||||
|
@ -118,7 +118,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto result = context.PopulateFromIncomingCommandBuffer(input, *process);
|
auto result = context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
REQUIRE(result == RESULT_SUCCESS);
|
REQUIRE(result == RESULT_SUCCESS);
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
|
@ -132,7 +132,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
0x98989898,
|
0x98989898,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
REQUIRE(context.CommandBuffer()[2] == process->process_id);
|
REQUIRE(context.CommandBuffer()[2] == process->process_id);
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
target_address,
|
target_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
CHECK(context.GetStaticBuffer(0) == mem->Vector());
|
CHECK(context.GetStaticBuffer(0) == mem->Vector());
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
target_address,
|
target_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
std::vector<u8> other_buffer(buffer.GetSize());
|
std::vector<u8> other_buffer(buffer.GetSize());
|
||||||
context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer.GetSize());
|
context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer.GetSize());
|
||||||
|
@ -219,7 +219,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
target_address_mapped,
|
target_address_mapped,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input, *process);
|
context.PopulateFromIncomingCommandBuffer(input, process);
|
||||||
|
|
||||||
auto* output = context.CommandBuffer();
|
auto* output = context.CommandBuffer();
|
||||||
CHECK(output[1] == 0x12345678);
|
CHECK(output[1] == 0x12345678);
|
||||||
|
@ -365,7 +365,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
target_address,
|
target_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process);
|
context.PopulateFromIncomingCommandBuffer(input_cmdbuff, process);
|
||||||
|
|
||||||
context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size());
|
context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue