kernel: Synchronize
This commit is contained in:
		| @@ -338,6 +338,15 @@ public: | ||||
|         return m_parent != nullptr; | ||||
|     } | ||||
|  | ||||
|     std::span<KSynchronizationObject*> GetSynchronizationObjectBuffer() { | ||||
|         return m_sync_object_buffer.sync_objects; | ||||
|     } | ||||
|  | ||||
|     std::span<Handle> GetHandleBuffer() { | ||||
|         return {m_sync_object_buffer.handles.data() + Svc::ArgumentHandleCountMax, | ||||
|                 Svc::ArgumentHandleCountMax}; | ||||
|     } | ||||
|  | ||||
|     u16 GetUserDisableCount() const; | ||||
|     void SetInterruptFlag(); | ||||
|     void ClearInterruptFlag(); | ||||
| @@ -855,6 +864,7 @@ private: | ||||
|     u32* m_light_ipc_data{}; | ||||
|     KProcessAddress m_tls_address{}; | ||||
|     KLightLock m_activity_pause_lock; | ||||
|     SyncObjectBuffer m_sync_object_buffer{}; | ||||
|     s64 m_schedule_count{}; | ||||
|     s64 m_last_scheduled_tick{}; | ||||
|     std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> m_per_core_priority_queue_entry{}; | ||||
|   | ||||
| @@ -38,22 +38,31 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha | ||||
|  | ||||
| Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles, | ||||
|                        Handle reply_target, s64 timeout_ns) { | ||||
|     // Ensure number of handles is valid. | ||||
|     R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); | ||||
|  | ||||
|     // Get the synchronization context. | ||||
|     auto& kernel = system.Kernel(); | ||||
|     auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); | ||||
|     auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer(); | ||||
|     auto handles = GetCurrentThread(kernel).GetHandleBuffer(); | ||||
|  | ||||
|     R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); | ||||
|     R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange( | ||||
|                  handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), | ||||
|              ResultInvalidPointer); | ||||
|     // Copy user handles. | ||||
|     if (num_handles > 0) { | ||||
|         // Ensure we can try to get the handles. | ||||
|         R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange( | ||||
|                      handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), | ||||
|                  ResultInvalidPointer); | ||||
|  | ||||
|     std::array<Handle, Svc::ArgumentHandleCountMax> handles; | ||||
|     GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); | ||||
|         // Get the handles. | ||||
|         GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), | ||||
|                                            sizeof(Handle) * num_handles); | ||||
|  | ||||
|     // Convert handle list to object table. | ||||
|     std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs; | ||||
|     R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(), | ||||
|                                                                      num_handles), | ||||
|              ResultInvalidHandle); | ||||
|         // Convert the handles to objects. | ||||
|         R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( | ||||
|                      objs.data(), handles.data(), num_handles), | ||||
|                  ResultInvalidHandle); | ||||
|     } | ||||
|  | ||||
|     // Ensure handles are closed when we're done. | ||||
|     SCOPE_EXIT({ | ||||
|   | ||||
| @@ -47,21 +47,35 @@ Result ResetSignal(Core::System& system, Handle handle) { | ||||
|     R_THROW(ResultInvalidHandle); | ||||
| } | ||||
|  | ||||
| static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles, | ||||
|                                   int32_t num_handles, int64_t timeout_ns) { | ||||
| /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | ||||
| Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles, | ||||
|                            int32_t num_handles, int64_t timeout_ns) { | ||||
|     LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles, | ||||
|               num_handles, timeout_ns); | ||||
|  | ||||
|     // Ensure number of handles is valid. | ||||
|     R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); | ||||
|  | ||||
|     // Get the synchronization context. | ||||
|     auto& kernel = system.Kernel(); | ||||
|     auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); | ||||
|     std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs; | ||||
|     auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer(); | ||||
|     auto handles = GetCurrentThread(kernel).GetHandleBuffer(); | ||||
|  | ||||
|     // Copy user handles. | ||||
|     if (num_handles > 0) { | ||||
|         // Ensure we can try to get the handles. | ||||
|         R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange( | ||||
|                      user_handles, static_cast<u64>(sizeof(Handle) * num_handles)), | ||||
|                  ResultInvalidPointer); | ||||
|  | ||||
|         // Get the handles. | ||||
|         GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(), | ||||
|                                            sizeof(Handle) * num_handles); | ||||
|  | ||||
|         // Convert the handles to objects. | ||||
|         R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, | ||||
|                                                                          num_handles), | ||||
|         R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( | ||||
|                      objs.data(), handles.data(), num_handles), | ||||
|                  ResultInvalidHandle); | ||||
|     } | ||||
|  | ||||
| @@ -80,23 +94,6 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons | ||||
|     R_RETURN(res); | ||||
| } | ||||
|  | ||||
| /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | ||||
| Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles, | ||||
|                            int32_t num_handles, int64_t timeout_ns) { | ||||
|     LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles, | ||||
|               num_handles, timeout_ns); | ||||
|  | ||||
|     // Ensure number of handles is valid. | ||||
|     R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); | ||||
|     std::array<Handle, Svc::ArgumentHandleCountMax> handles; | ||||
|     if (num_handles > 0) { | ||||
|         GetCurrentMemory(system.Kernel()) | ||||
|             .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); | ||||
|     } | ||||
|  | ||||
|     R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns)); | ||||
| } | ||||
|  | ||||
| /// Resumes a thread waiting on WaitSynchronization | ||||
| Result CancelSynchronization(Core::System& system, Handle handle) { | ||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user