mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30: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
				
			
		|  | @ -96,6 +96,7 @@ add_library(common STATIC | |||
|     serialization/atomic.h | ||||
|     serialization/boost_discrete_interval.hpp | ||||
|     serialization/boost_flat_set.h | ||||
|     serialization/boost_small_vector.hpp | ||||
|     serialization/boost_vector.hpp | ||||
|     string_util.cpp | ||||
|     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
 | ||||
|  | @ -1,9 +1,9 @@ | |||
| #ifndef  BOOST_SERIALIZATION_BOOST_VECTOR_HPP | ||||
| #ifndef BOOST_SERIALIZATION_BOOST_VECTOR_HPP | ||||
| #define BOOST_SERIALIZATION_BOOST_VECTOR_HPP | ||||
| 
 | ||||
| // MS compatible compilers support #pragma once
 | ||||
| #if defined(_MSC_VER) | ||||
| # pragma once | ||||
| #pragma once | ||||
| #endif | ||||
| 
 | ||||
| /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
 | ||||
|  | @ -24,20 +24,20 @@ | |||
| 
 | ||||
| #include <boost/archive/detail/basic_iarchive.hpp> | ||||
| #include <boost/serialization/access.hpp> | ||||
| #include <boost/serialization/nvp.hpp> | ||||
| #include <boost/serialization/collection_size_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/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) | ||||
| #define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5) | ||||
| #endif | ||||
| 
 | ||||
| namespace boost { | ||||
|  | @ -48,33 +48,23 @@ namespace serialization { | |||
| 
 | ||||
| // the default versions
 | ||||
| 
 | ||||
| template<class Archive, class U, class Allocator> | ||||
| inline void save( | ||||
|     Archive & ar, | ||||
|     const boost::container::vector<U, Allocator> &t, | ||||
|     const unsigned int /* file_version */, | ||||
|     mpl::false_ | ||||
| ){ | ||||
|     boost::serialization::stl::save_collection<Archive, boost::container::vector<U, Allocator> >( | ||||
|         ar, t | ||||
|     ); | ||||
| template <class Archive, class U, class Allocator, class Options> | ||||
| inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t, | ||||
|                  const unsigned int /* file_version */, mpl::false_) { | ||||
|     boost::serialization::stl::save_collection<Archive, | ||||
|                                                boost::container::vector<U, Allocator, Options>>(ar, | ||||
|                                                                                                 t); | ||||
| } | ||||
| 
 | ||||
| template<class Archive, class U, class Allocator> | ||||
| inline void load( | ||||
|     Archive & ar, | ||||
|     boost::container::vector<U, Allocator> &t, | ||||
|     const unsigned int /* file_version */, | ||||
|     mpl::false_ | ||||
| ){ | ||||
|     const boost::archive::library_version_type library_version( | ||||
|         ar.get_library_version() | ||||
|     ); | ||||
| template <class Archive, class U, class Allocator, class Options> | ||||
| inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& 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){ | ||||
|     if (boost::archive::library_version_type(3) < library_version) { | ||||
|         ar >> BOOST_SERIALIZATION_NVP(item_version); | ||||
|     } | ||||
|     t.reserve(count); | ||||
|  | @ -83,107 +73,77 @@ inline void load( | |||
| 
 | ||||
| // the optimized versions
 | ||||
| 
 | ||||
| template<class Archive, class U, class Allocator> | ||||
| inline void save( | ||||
|     Archive & ar, | ||||
|     const boost::container::vector<U, Allocator> &t, | ||||
|     const unsigned int /* file_version */, | ||||
|     mpl::true_ | ||||
| ){ | ||||
| template <class Archive, class U, class Allocator, class Options> | ||||
| inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& 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 | ||||
|         ); | ||||
|         ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]), | ||||
|                                                                        count); | ||||
| } | ||||
| 
 | ||||
| template<class Archive, class U, class Allocator> | ||||
| inline void load( | ||||
|     Archive & ar, | ||||
|     boost::container::vector<U, Allocator> &t, | ||||
|     const unsigned int /* file_version */, | ||||
|     mpl::true_ | ||||
| ){ | ||||
| template <class Archive, class U, class Allocator, class Options> | ||||
| inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& 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())) { | ||||
|     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 | ||||
|         ); | ||||
|   } | ||||
|         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, class Allocator> | ||||
| inline void save( | ||||
|     Archive & ar, | ||||
|     const boost::container::vector<U, Allocator> &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, class Allocator, class Options> | ||||
| inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& 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, class Allocator> | ||||
| inline void load( | ||||
|     Archive & ar, | ||||
|     boost::container::vector<U, Allocator> &t, | ||||
|     const unsigned int file_version | ||||
| ){ | ||||
| template <class Archive, class U, class Allocator, class Options> | ||||
| inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& 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; | ||||
|     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()); | ||||
|     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, class Allocator> | ||||
| inline void serialize( | ||||
|     Archive & ar, | ||||
|     boost::container::vector<U, Allocator> & t, | ||||
|     const unsigned int file_version | ||||
| ){ | ||||
| template <class Archive, class U, class Allocator, class Options> | ||||
| inline void serialize(Archive& ar, boost::container::vector<U, Allocator, Options>& 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, class Allocator> | ||||
| inline void serialize( | ||||
|     Archive & ar, | ||||
|     boost::container::vector<bool, Allocator> & t, | ||||
|     const unsigned int file_version | ||||
| ){ | ||||
| template <class Archive, class Allocator, class Options> | ||||
| inline void serialize(Archive& ar, boost::container::vector<bool, Allocator, Options>& t, | ||||
|                       const unsigned int file_version) { | ||||
|     boost::serialization::split_free(ar, t, file_version); | ||||
| } | ||||
| 
 | ||||
| } // serialization
 | ||||
| } // namespace serialization
 | ||||
| } // namespace boost
 | ||||
| 
 | ||||
| #include <boost/serialization/collection_traits.hpp> | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                             std::shared_ptr<WaitObject> object) { | ||||
|     ASSERT(reason == ThreadWakeupReason::Timeout); | ||||
|     // 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.end()); | ||||
| }; | ||||
| 
 | ||||
| ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, | ||||
|                                             VAddr address, s32 value, u64 nanoseconds) { | ||||
| 
 | ||||
|     auto timeout_callback = [this](ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                                    std::shared_ptr<WaitObject> object) { | ||||
|         ASSERT(reason == ThreadWakeupReason::Timeout); | ||||
|         // 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.end()); | ||||
|     }; | ||||
|     auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this()); | ||||
| 
 | ||||
|     switch (type) { | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| #include <boost/serialization/vector.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| // Address arbiters are an underlying kernel synchronization object that can be created/used via
 | ||||
|  | @ -34,7 +35,7 @@ enum class ArbitrationType : u32 { | |||
|     DecrementAndWaitIfLessThanWithTimeout, | ||||
| }; | ||||
| 
 | ||||
| class AddressArbiter final : public Object { | ||||
| class AddressArbiter final : public Object, public WakeupCallback { | ||||
| public: | ||||
|     explicit AddressArbiter(KernelSystem& kernel); | ||||
|     ~AddressArbiter() override; | ||||
|  | @ -56,6 +57,9 @@ public: | |||
|     ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address, | ||||
|                                 s32 value, u64 nanoseconds); | ||||
| 
 | ||||
|     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                 std::shared_ptr<WaitObject> object); | ||||
| 
 | ||||
| private: | ||||
|     KernelSystem& kernel; | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,46 @@ | |||
| 
 | ||||
| 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, | ||||
|                                                 std::unique_ptr<SessionDataBase> data) | ||||
|     : session(std::move(session)), data(std::move(data)) {} | ||||
|  | @ -33,34 +73,16 @@ void SessionRequestHandler::ClientDisconnected(std::shared_ptr<ServerSession> se | |||
|         connected_sessions.end()); | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& reason, | ||||
|                                                             std::chrono::nanoseconds timeout, | ||||
|                                                             WakeupCallback&& callback) { | ||||
| std::shared_ptr<Event> HLERequestContext::SleepClientThread( | ||||
|     const std::string& reason, std::chrono::nanoseconds timeout, | ||||
|     std::shared_ptr<WakeupCallback> callback) { | ||||
|     // Put the client thread to sleep until the wait event is signaled or the timeout expires.
 | ||||
|     thread->wakeup_callback = [context = *this, | ||||
|                                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)); | ||||
|     }; | ||||
|     thread->wakeup_callback = std::make_shared<ThreadCallback>(shared_from_this(), callback); | ||||
| 
 | ||||
|     auto event = kernel.CreateEvent(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); | ||||
|     thread->status = ThreadStatus::WaitHleEvent; | ||||
|     thread->wait_objects = {event}; | ||||
|     event->AddWaitingThread(SharedFrom(thread)); | ||||
|     event->AddWaitingThread(thread); | ||||
| 
 | ||||
|     if (timeout.count() > 0) | ||||
|         thread->WakeAfterDelay(timeout.count()); | ||||
|  | @ -68,8 +90,10 @@ std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& r | |||
|     return event; | ||||
| } | ||||
| 
 | ||||
| HLERequestContext::HLERequestContext() : kernel(Core::Global<KernelSystem>()) {} | ||||
| 
 | ||||
| HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session, | ||||
|                                      Thread* thread) | ||||
|                                      std::shared_ptr<Thread> thread) | ||||
|     : kernel(kernel), session(std::move(session)), thread(thread) { | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, | ||||
|                                                                 Process& src_process) { | ||||
| ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer( | ||||
|     const u32_le* src_cmdbuf, std::shared_ptr<Process> src_process_) { | ||||
|     auto& src_process = *src_process_; | ||||
|     IPC::Header header{src_cmdbuf[0]}; | ||||
| 
 | ||||
|     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: { | ||||
|             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); | ||||
|             cmd_buf[i++] = next_id; | ||||
|             break; | ||||
|  | @ -170,7 +195,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr | |||
| 
 | ||||
|     if (should_record) { | ||||
|         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)); | ||||
|     } | ||||
| 
 | ||||
|  | @ -248,7 +273,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, | |||
| 
 | ||||
|     if (should_record) { | ||||
|         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)); | ||||
|     } | ||||
| 
 | ||||
|  | @ -262,13 +287,15 @@ MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) { | |||
| 
 | ||||
| void HLERequestContext::ReportUnimplemented() const { | ||||
|     if (kernel.GetIPCRecorder().IsEnabled()) { | ||||
|         kernel.GetIPCRecorder().SetHLEUnimplemented(SharedFrom(thread)); | ||||
|         kernel.GetIPCRecorder().SetHLEUnimplemented(thread); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor, | ||||
|                            VAddr address, u32 id) | ||||
|     : memory(&memory), id(id), address(address), process(&process) { | ||||
| MappedBuffer::MappedBuffer() : memory(&Core::Global<Core::System>().Memory()) {} | ||||
| 
 | ||||
| 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}; | ||||
|     size = desc.size; | ||||
|     perms = desc.perms; | ||||
|  | @ -287,3 +314,5 @@ void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t | |||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| SERIALIZE_EXPORT_IMPL(Kernel::HLERequestContext::ThreadCallback) | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ | |||
| #include <boost/serialization/unique_ptr.hpp> | ||||
| #include <boost/serialization/vector.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "common/serialization/boost_small_vector.hpp" | ||||
| #include "common/swap.h" | ||||
| #include "core/hle/ipc.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
|  | @ -127,7 +128,7 @@ private: | |||
| 
 | ||||
| class MappedBuffer { | ||||
| 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); | ||||
| 
 | ||||
|     // interface for service
 | ||||
|  | @ -151,9 +152,21 @@ private: | |||
|     Memory::MemorySystem* memory; | ||||
|     u32 id; | ||||
|     VAddr address; | ||||
|     const Process* process; | ||||
|     std::size_t size; | ||||
|     std::shared_ptr<Process> process; | ||||
|     u32 size; | ||||
|     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 | ||||
|  * needed in this case, though. | ||||
|  */ | ||||
| class HLERequestContext { | ||||
| class HLERequestContext : std::enable_shared_from_this<HLERequestContext> { | ||||
| 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(); | ||||
| 
 | ||||
|     /// Returns a pointer to the IPC command buffer for this request.
 | ||||
|  | @ -203,8 +217,12 @@ public: | |||
|         return session; | ||||
|     } | ||||
| 
 | ||||
|     using WakeupCallback = std::function<void( | ||||
|         std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; | ||||
|     class WakeupCallback { | ||||
|     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 | ||||
|  | @ -219,7 +237,7 @@ public: | |||
|      */ | ||||
|     std::shared_ptr<Event> SleepClientThread(const std::string& reason, | ||||
|                                              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 | ||||
|  | @ -259,26 +277,43 @@ public: | |||
|     MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf); | ||||
| 
 | ||||
|     /// 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.
 | ||||
|     ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const; | ||||
| 
 | ||||
|     /// Reports an unimplemented function.
 | ||||
|     void ReportUnimplemented() const; | ||||
| 
 | ||||
|     class ThreadCallback; | ||||
|     friend class ThreadCallback; | ||||
| 
 | ||||
| private: | ||||
|     KernelSystem& kernel; | ||||
|     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | ||||
|     std::shared_ptr<ServerSession> session; | ||||
|     Thread* thread; | ||||
|     std::shared_ptr<Thread> thread; | ||||
|     // TODO(yuriks): Check common usage of this and optimize size accordingly
 | ||||
|     boost::container::small_vector<std::shared_ptr<Object>, 8> request_handles; | ||||
|     // The static buffers will be created when the IPC request is translated.
 | ||||
|     std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers; | ||||
|     // The mapped buffers will be created when the IPC request is translated
 | ||||
|     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
 | ||||
| 
 | ||||
| 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) { | ||||
|                     object = src_thread; | ||||
|                 } else if (handle == CurrentProcess) { | ||||
|                     object = SharedFrom(src_process); | ||||
|                     object = src_process; | ||||
|                 } else if (handle != 0) { | ||||
|                     object = src_process->handle_table.GetGeneric(handle); | ||||
|                     if (descriptor == IPC::DescriptorType::MoveHandle) { | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ void Recorder::RegisterRequest(const std::shared_ptr<Kernel::ClientSession>& cli | |||
| 
 | ||||
|     RequestRecord record = {/* id */ ++record_count, | ||||
|                             /* 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_session */ GetObjectInfo(client_session.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); | ||||
| 
 | ||||
|     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()); | ||||
|     } else { | ||||
|         record.is_hle = true; | ||||
|  |  | |||
|  | @ -134,7 +134,7 @@ public: | |||
|      */ | ||||
|     ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point, | ||||
|                                                     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. | ||||
|  |  | |||
|  | @ -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 (hle_handler != nullptr) { | ||||
|         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(), | ||||
|                                 cmd_buf.size() * sizeof(u32)); | ||||
| 
 | ||||
|         Kernel::HLERequestContext context(kernel, SharedFrom(this), thread.get()); | ||||
|         context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), *current_process); | ||||
|         Kernel::HLERequestContext context(kernel, SharedFrom(this), thread); | ||||
|         context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process); | ||||
| 
 | ||||
|         hle_handler->HandleSyncRequest(context); | ||||
| 
 | ||||
|  |  | |||
|  | @ -282,7 +282,7 @@ void SVC::ExitProcess() { | |||
|     // Stop all the process threads that are currently waiting for objects.
 | ||||
|     auto& thread_list = kernel.GetThreadManager().GetThreadList(); | ||||
|     for (auto& thread : thread_list) { | ||||
|         if (thread->owner_process != current_process.get()) | ||||
|         if (thread->owner_process != current_process) | ||||
|             continue; | ||||
| 
 | ||||
|         if (thread.get() == kernel.GetThreadManager().GetCurrentThread()) | ||||
|  | @ -403,6 +403,73 @@ ResultCode SVC::CloseHandle(Handle 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
 | ||||
| ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||||
|     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
 | ||||
|         thread->WakeAfterDelay(nano_seconds); | ||||
| 
 | ||||
|         thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                                      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.
 | ||||
|         }; | ||||
|         thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false); | ||||
| 
 | ||||
|         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
 | ||||
|         thread->WakeAfterDelay(nano_seconds); | ||||
| 
 | ||||
|         thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                                      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.
 | ||||
|         }; | ||||
|         thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false); | ||||
| 
 | ||||
|         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
 | ||||
|         thread->WakeAfterDelay(nano_seconds); | ||||
| 
 | ||||
|         thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                                      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())); | ||||
|         }; | ||||
|         thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(true); | ||||
| 
 | ||||
|         system.PrepareReschedule(); | ||||
| 
 | ||||
|  | @ -730,22 +757,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co | |||
| 
 | ||||
|     thread->wait_objects = std::move(objects); | ||||
| 
 | ||||
|     thread->wakeup_callback = [& kernel = this->kernel, &memory = this->memory]( | ||||
|                                   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())); | ||||
|     }; | ||||
|     thread->wakeup_callback = std::make_shared<SVC_IPCCallback>(system); | ||||
| 
 | ||||
|     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, | ||||
|                    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 | | ||||
|                               FPSCR_ROUND_TOZERO); // 0x03C00000
 | ||||
|  | @ -1020,7 +1032,7 @@ ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) { | |||
|     if (thread == nullptr) | ||||
|         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); | ||||
| 
 | ||||
|  | @ -1611,3 +1623,6 @@ void SVCContext::CallSVC(u32 immediate) { | |||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| SERIALIZE_EXPORT_IMPL(Kernel::SVC_SyncCallback) | ||||
| SERIALIZE_EXPORT_IMPL(Kernel::SVC_IPCCallback) | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <boost/serialization/export.hpp> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Core { | ||||
|  | @ -25,4 +26,10 @@ private: | |||
|     std::unique_ptr<SVC> impl; | ||||
| }; | ||||
| 
 | ||||
| class SVC_SyncCallback; | ||||
| class SVC_IPCCallback; | ||||
| 
 | ||||
| } // 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_address; | ||||
|     ar& name; | ||||
|     // TODO: How the hell to do wakeup_callback
 | ||||
|     ar& wakeup_callback; | ||||
| } | ||||
| 
 | ||||
| SERIALIZE_IMPL(Thread) | ||||
|  | @ -138,8 +138,8 @@ void ThreadManager::SwitchContext(Thread* new_thread) { | |||
|         ready_queue.remove(new_thread->current_priority, new_thread); | ||||
|         new_thread->status = ThreadStatus::Running; | ||||
| 
 | ||||
|         if (previous_process.get() != current_thread->owner_process) { | ||||
|             kernel.SetCurrentProcess(SharedFrom(current_thread->owner_process)); | ||||
|         if (previous_process != current_thread->owner_process) { | ||||
|             kernel.SetCurrentProcess(current_thread->owner_process); | ||||
|         } | ||||
| 
 | ||||
|         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
 | ||||
|         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
 | ||||
|         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
 | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point, | ||||
|                                                               u32 priority, u32 arg, | ||||
|                                                               s32 processor_id, VAddr stack_top, | ||||
|                                                               Process& owner_process) { | ||||
| ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread( | ||||
|     std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top, | ||||
|     std::shared_ptr<Process> owner_process) { | ||||
|     // Check if priority is in ranged. Lowest priority -> highest priority id.
 | ||||
|     if (priority > ThreadPrioLowest) { | ||||
|         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
 | ||||
| 
 | ||||
|     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); | ||||
|         // TODO: Verify error
 | ||||
|         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->name = std::move(name); | ||||
|     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
 | ||||
|     auto& tls_slots = owner_process.tls_slots; | ||||
|     auto& tls_slots = owner_process->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"); | ||||
|             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
 | ||||
|         available_page = tls_slots.size() - 1; | ||||
|         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.
 | ||||
|         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 + | ||||
|                           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
 | ||||
|     // to initialize the context
 | ||||
|  | @ -438,7 +437,7 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u | |||
|     // Initialize new "main" thread
 | ||||
|     auto thread_res = | ||||
|         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(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -59,6 +59,15 @@ enum class ThreadWakeupReason { | |||
|     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 { | ||||
| public: | ||||
|     explicit ThreadManager(Kernel::KernelSystem& kernel); | ||||
|  | @ -300,7 +309,7 @@ public: | |||
|     /// Mutexes that this thread is currently waiting for.
 | ||||
|     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
 | ||||
|     // passed to WaitSynchronization1/N.
 | ||||
|  | @ -310,12 +319,10 @@ public: | |||
| 
 | ||||
|     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
 | ||||
|     // 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.
 | ||||
|     std::function<WakeupCallback> wakeup_callback; | ||||
|     std::shared_ptr<WakeupCallback> wakeup_callback; | ||||
| 
 | ||||
| private: | ||||
|     ThreadManager& thread_manager; | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ void WaitObject::WakeupAllWaitingThreads() { | |||
| 
 | ||||
|         // Invoke the wakeup callback before clearing the wait objects
 | ||||
|         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) | ||||
|             object->RemoveWaitingThread(thread.get()); | ||||
|  |  | |||
|  | @ -71,12 +71,7 @@ void File::Read(Kernel::HLERequestContext& ctx) { | |||
|     rb.PushMappedBuffer(buffer); | ||||
| 
 | ||||
|     std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; | ||||
|     ctx.SleepClientThread("file::read", read_timeout_ns, | ||||
|                           [](std::shared_ptr<Kernel::Thread> /*thread*/, | ||||
|                              Kernel::HLERequestContext& /*ctx*/, | ||||
|                              Kernel::ThreadWakeupReason /*reason*/) { | ||||
|                               // Nothing to do here
 | ||||
|                           }); | ||||
|     ctx.SleepClientThread("file::read", read_timeout_ns, nullptr); | ||||
| } | ||||
| 
 | ||||
| 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()); | ||||
|     } | ||||
| 
 | ||||
|     ctx.SleepClientThread("fs_user::open", open_timeout_ns, | ||||
|                           [](std::shared_ptr<Kernel::Thread> /*thread*/, | ||||
|                              Kernel::HLERequestContext& /*ctx*/, | ||||
|                              Kernel::ThreadWakeupReason /*reason*/) { | ||||
|                               // Nothing to do here
 | ||||
|                           }); | ||||
|     ctx.SleepClientThread("fs_user::open", open_timeout_ns, nullptr); | ||||
| } | ||||
| 
 | ||||
| void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { | ||||
|  | @ -134,12 +129,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { | |||
|                   file_path.DebugStr(), mode.hex, attributes); | ||||
|     } | ||||
| 
 | ||||
|     ctx.SleepClientThread("fs_user::open_directly", open_timeout_ns, | ||||
|                           [](std::shared_ptr<Kernel::Thread> /*thread*/, | ||||
|                              Kernel::HLERequestContext& /*ctx*/, | ||||
|                              Kernel::ThreadWakeupReason /*reason*/) { | ||||
|                               // Nothing to do here
 | ||||
|                           }); | ||||
|     ctx.SleepClientThread("fs_user::open_directly", open_timeout_ns, nullptr); | ||||
| } | ||||
| 
 | ||||
| void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) { | ||||
|  |  | |||
|  | @ -1170,6 +1170,29 @@ void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) { | |||
|     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, | ||||
|                                const u8* network_info_buffer, std::size_t network_info_size, | ||||
|                                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
 | ||||
|     static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000}; | ||||
| 
 | ||||
|     connection_event = ctx.SleepClientThread( | ||||
|         "uds::ConnectToNetwork", UDSConnectionTimeout, | ||||
|         [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"); | ||||
|         }); | ||||
|     connection_event = ctx.SleepClientThread("uds::ConnectToNetwork", UDSConnectionTimeout, | ||||
|                                              std::make_shared<ThreadCallback>(command_id)); | ||||
| } | ||||
| 
 | ||||
| void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { | ||||
|  | @ -1418,3 +1434,5 @@ NWM_UDS::~NWM_UDS() { | |||
| } | ||||
| 
 | ||||
| } // namespace Service::NWM
 | ||||
| 
 | ||||
| SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_UDS::ThreadCallback) | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| #include <boost/optional.hpp> | ||||
| #include <boost/serialization/export.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | @ -127,6 +128,8 @@ public: | |||
|     explicit NWM_UDS(Core::System& system); | ||||
|     ~NWM_UDS(); | ||||
| 
 | ||||
|     class ThreadCallback; | ||||
| 
 | ||||
| private: | ||||
|     Core::System& system; | ||||
| 
 | ||||
|  | @ -560,3 +563,4 @@ private: | |||
| 
 | ||||
| SERVICE_CONSTRUCT(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.
 | ||||
| 
 | ||||
| #include <tuple> | ||||
| #include "common/archives.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
|  | @ -71,6 +72,46 @@ void SRV::EnableNotification(Kernel::HLERequestContext& ctx) { | |||
|     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 | ||||
|  *  Inputs: | ||||
|  | @ -100,28 +141,7 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { | |||
| 
 | ||||
|     // TODO(yuriks): Permission checks go here
 | ||||
| 
 | ||||
|     auto get_handle = [name, this](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()); | ||||
|         } | ||||
|     }; | ||||
|     auto get_handle = std::make_shared<ThreadCallback>(system, name); | ||||
| 
 | ||||
|     auto client_port = system.ServiceManager().GetServicePort(name); | ||||
|     if (client_port.Failed()) { | ||||
|  | @ -266,3 +286,5 @@ SRV::SRV(Core::System& system) : ServiceFramework("srv:", 4), system(system) { | |||
| SRV::~SRV() = default; | ||||
| 
 | ||||
| } // namespace Service::SM
 | ||||
| 
 | ||||
| SERIALIZE_EXPORT_IMPL(Service::SM::SRV::ThreadCallback) | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include <memory> | ||||
| #include <unordered_map> | ||||
| #include <boost/serialization/export.hpp> | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Core { | ||||
|  | @ -25,6 +26,8 @@ public: | |||
|     explicit SRV(Core::System& system); | ||||
|     ~SRV(); | ||||
| 
 | ||||
|     class ThreadCallback; | ||||
| 
 | ||||
| private: | ||||
|     void RegisterClient(Kernel::HLERequestContext& ctx); | ||||
|     void EnableNotification(Kernel::HLERequestContext& ctx); | ||||
|  | @ -40,3 +43,5 @@ private: | |||
| }; | ||||
| 
 | ||||
| } // 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), | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         REQUIRE(context.CommandBuffer()[0] == 0x12340000); | ||||
|     } | ||||
|  | @ -50,7 +50,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             0xAABBCCDD, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         auto* output = context.CommandBuffer(); | ||||
|         REQUIRE(output[1] == 0x12345678); | ||||
|  | @ -67,7 +67,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             a_handle, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         auto* output = context.CommandBuffer(); | ||||
|         REQUIRE(context.GetIncomingHandle(output[2]) == a); | ||||
|  | @ -83,7 +83,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             a_handle, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         auto* output = context.CommandBuffer(); | ||||
|         REQUIRE(context.GetIncomingHandle(output[2]) == a); | ||||
|  | @ -103,7 +103,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             process->handle_table.Create(c).Unwrap(), | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         auto* output = context.CommandBuffer(); | ||||
|         REQUIRE(context.GetIncomingHandle(output[2]) == a); | ||||
|  | @ -118,7 +118,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             0, | ||||
|         }; | ||||
| 
 | ||||
|         auto result = context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         auto result = context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         REQUIRE(result == RESULT_SUCCESS); | ||||
|         auto* output = context.CommandBuffer(); | ||||
|  | @ -132,7 +132,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             0x98989898, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         REQUIRE(context.CommandBuffer()[2] == process->process_id); | ||||
|     } | ||||
|  | @ -153,7 +153,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             target_address, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         CHECK(context.GetStaticBuffer(0) == mem->Vector()); | ||||
| 
 | ||||
|  | @ -175,7 +175,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|             target_address, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         std::vector<u8> other_buffer(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, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input, process); | ||||
| 
 | ||||
|         auto* output = context.CommandBuffer(); | ||||
|         CHECK(output[1] == 0x12345678); | ||||
|  | @ -365,7 +365,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | |||
|             target_address, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process); | ||||
|         context.PopulateFromIncomingCommandBuffer(input_cmdbuff, process); | ||||
| 
 | ||||
|         context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size()); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue