citra-emu
/
citra-canary
Archived
1
0
Fork 0

Services/GSP: Assign a thread id to each connected session when the session is created.

Most applications call AcquireRight before calling RegisterInterruptRelayQueue so we can't assign the thread id there.
This fixes the bug with LLE applets not launching properly.
This commit is contained in:
Subv 2018-01-02 12:07:26 -05:00
parent fbef978b98
commit d17f148e48
2 changed files with 24 additions and 9 deletions

View File

@ -53,6 +53,17 @@ constexpr ResultCode ERR_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorM
/// Maximum number of threads that can be registered at the same time in the GSP module. /// Maximum number of threads that can be registered at the same time in the GSP module.
constexpr u32 MaxGSPThreads = 4; constexpr u32 MaxGSPThreads = 4;
/// Thread ids currently in use by the sessions connected to the GSPGPU service.
static std::array<bool, MaxGSPThreads> used_thread_ids = {false, false, false, false};
static u32 GetUnusedThreadId() {
for (u32 id = 0; id < MaxGSPThreads; ++id) {
if (!used_thread_ids[id])
return id;
}
ASSERT_MSG(false, "All GSP threads are in use");
}
/// Gets a pointer to a thread command buffer in GSP shared memory /// Gets a pointer to a thread command buffer in GSP shared memory
static inline u8* GetCommandBuffer(Kernel::SharedPtr<Kernel::SharedMemory> shared_memory, static inline u8* GetCommandBuffer(Kernel::SharedPtr<Kernel::SharedMemory> shared_memory,
u32 thread_id) { u32 thread_id) {
@ -327,11 +338,7 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
interrupt_event->name = "GSP_GSP_GPU::interrupt_event"; interrupt_event->name = "GSP_GSP_GPU::interrupt_event";
u32 thread_id = next_thread_id++;
ASSERT_MSG(thread_id < MaxGSPThreads, "GSP thread id overflow");
SessionData* session_data = GetSessionData(ctx.Session()); SessionData* session_data = GetSessionData(ctx.Session());
session_data->thread_id = thread_id;
session_data->interrupt_event = std::move(interrupt_event); session_data->interrupt_event = std::move(interrupt_event);
session_data->registered = true; session_data->registered = true;
@ -345,7 +352,7 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
rb.Push(thread_id); rb.Push(session_data->thread_id);
rb.PushCopyObjects(shared_memory); rb.PushCopyObjects(shared_memory);
LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags); LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags);
@ -752,5 +759,14 @@ GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) {
first_initialization = true; first_initialization = true;
}; };
SessionData::SessionData() {
// Assign a new thread id to this session when it connects. Note: In the real GSP service this
// is done through a real thread (svcCreateThread) but we have to simulate it since our HLE
// services don't have threads.
thread_id = GetUnusedThreadId();
used_thread_ids[thread_id] = true;
}
} // namespace GSP } // namespace GSP
} // namespace Service } // namespace Service

View File

@ -180,10 +180,12 @@ struct CommandBuffer {
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
SessionData();
/// Event triggered when GSP interrupt has been signalled /// Event triggered when GSP interrupt has been signalled
Kernel::SharedPtr<Kernel::Event> interrupt_event; Kernel::SharedPtr<Kernel::Event> interrupt_event;
/// Thread index into interrupt relay queue /// Thread index into interrupt relay queue
u32 thread_id = 0; u32 thread_id;
/// Whether RegisterInterruptRelayQueue was called for this session /// Whether RegisterInterruptRelayQueue was called for this session
bool registered = false; bool registered = false;
}; };
@ -363,9 +365,6 @@ private:
/// Returns the session data for the specified registered thread id, or nullptr if not found. /// Returns the session data for the specified registered thread id, or nullptr if not found.
SessionData* FindRegisteredThreadData(u32 thread_id); SessionData* FindRegisteredThreadData(u32 thread_id);
/// Next threadid value to use when RegisterInterruptRelayQueue is called.
u32 next_thread_id = 0;
/// GSP shared memory /// GSP shared memory
Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;