mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	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
 | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| // MS compatible compilers support #pragma once
 | // MS compatible compilers support #pragma once
 | ||||||
| #if defined(_MSC_VER) | #if defined(_MSC_VER) | ||||||
| # pragma once | #pragma once | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
 | ||||||
|  | @ -24,20 +24,20 @@ | ||||||
| 
 | 
 | ||||||
| #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 | ||||||
| #define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V==4 || V==5) | #define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| namespace boost { | namespace boost { | ||||||
|  | @ -48,33 +48,23 @@ 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; | ||||||
|     ar >> BOOST_SERIALIZATION_NVP(count); |     ar >> BOOST_SERIALIZATION_NVP(count); | ||||||
|     if(boost::archive::library_version_type(3) < library_version){ |     if (boost::archive::library_version_type(3) < library_version) { | ||||||
|         ar >> BOOST_SERIALIZATION_NVP(item_version); |         ar >> BOOST_SERIALIZATION_NVP(item_version); | ||||||
|     } |     } | ||||||
|     t.reserve(count); |     t.reserve(count); | ||||||
|  | @ -83,107 +73,77 @@ 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); | ||||||
|     unsigned int item_version=0; |     unsigned int item_version = 0; | ||||||
|     if(BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) { |     if (BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) { | ||||||
|         ar >> BOOST_SERIALIZATION_NVP(item_version); |         ar >> BOOST_SERIALIZATION_NVP(item_version); | ||||||
|     } |     } | ||||||
|     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; | ||||||
| ){ |     save(ar, t, file_version, 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()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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 |     load(ar, t, file_version, use_optimized()); | ||||||
|     >::type 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,16 +80,18 @@ 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.
 | ||||||
|     waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread), |     waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread), | ||||||
|                           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) { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue