diff --git a/Core/HLE/Plugins.cpp b/Core/HLE/Plugins.cpp index 2373596d65..1092347c1c 100644 --- a/Core/HLE/Plugins.cpp +++ b/Core/HLE/Plugins.cpp @@ -172,7 +172,7 @@ void Init() { } } -bool Load() { +bool Load(PSPModule *pluginWaitingModule, SceUID threadID) { bool started = false; auto sy = GetI18NCategory(I18NCat::SYSTEM); @@ -197,6 +197,10 @@ bool Load() { std::string shortName = Path(filename).GetFilename(); g_OSD.Show(OSDType::MESSAGE_SUCCESS, ApplySafeSubstitutions(sy->T("Loaded plugin: %1"), shortName), 6.0f); started = true; + pluginWaitingModule->startingPlugins.push_back(module); + u32 error; + PSPModule *plugin_module = kernelObjects.Get(module, error); + plugin_module->pluginWaitingThread = threadID; } INFO_LOG(Log::System, "Loaded plugin: %s", filename.c_str()); diff --git a/Core/HLE/Plugins.h b/Core/HLE/Plugins.h index cfb8d15ffb..7c15718465 100644 --- a/Core/HLE/Plugins.h +++ b/Core/HLE/Plugins.h @@ -20,6 +20,7 @@ #include #include #include "Common/Input/KeyCodes.h" +#include "Core/HLE/sceKernelModule.h" class PointerWrap; @@ -28,7 +29,7 @@ namespace HLEPlugins { void Init(); void Shutdown(); -bool Load(); +bool Load(PSPModule *pluginWaitingModule, SceUID threadID); void Unload(); void DoState(PointerWrap &p); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 2efecb0285..2be7c21793 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1659,11 +1659,6 @@ static void __KernelStartModule(PSPModule *m, int args, const char *argp, SceKer SceUID threadID = __KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute); __KernelSetThreadRA(threadID, NID_MODULERETURN); - - if (HLEPlugins::Load()) { - KernelRotateThreadReadyQueue(0); - __KernelReSchedule("Started plugins"); - } } @@ -1797,6 +1792,13 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str __KernelStartIdleThreads(module->GetUID()); + // Wait until plugins are loaded + module->startingPlugins.clear(); + if (HLEPlugins::Load(module, __KernelGetCurThread())) { + __KernelWaitCurThread(WAITTYPE_PLUGIN, module->GetUID(), 1, 0, false, "started plugins"); + __KernelReSchedule("Started plugins"); + } + delete[] param_argp; delete[] param_key; @@ -2311,6 +2313,29 @@ void __KernelReturnFromModuleFunc() { } module->waitingThreads.clear(); + // Check if we need to wake up a plugin waiting thread + if (module->pluginWaitingThread) { + u32 error; + PSPThread *plugin_waiting_thread = kernelObjects.Get(module->pluginWaitingThread, error); + if (plugin_waiting_thread && HLEKernel::VerifyWait(module->pluginWaitingThread, WAITTYPE_PLUGIN, plugin_waiting_thread->moduleId)) { + PSPModule *plugin_waiting_module = kernelObjects.Get(plugin_waiting_thread->moduleId, error); + if (plugin_waiting_module) { + for (auto it = plugin_waiting_module->startingPlugins.begin(), end = plugin_waiting_module->startingPlugins.end(); it < end; ++it) { + if (*it == leftModuleID) { + plugin_waiting_module->startingPlugins.erase(it); + break; + } + } + if (plugin_waiting_module->startingPlugins.empty()) { + INFO_LOG(Log::sceModule, "Resuming LoadExec thread 0x%x", module->pluginWaitingThread); + __KernelResumeThreadFromWait(module->pluginWaitingThread, 0); + } else { + INFO_LOG(Log::sceModule, "LoadExec thread 0x%x still waiting for %ld plugin(s)", module->pluginWaitingThread, plugin_waiting_module->startingPlugins.size()); + } + } + } + } + if (module->nm.status == MODULE_STATUS_UNLOADING) { // TODO: Delete the waiting thread? module->Cleanup(); diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 61ead2a4da..5deb16c5e1 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -191,6 +191,11 @@ public: NativeModule nm{}; std::vector waitingThreads; + // From the plugin's perspective, this is the reference to the thread started by LoadExec + SceUID pluginWaitingThread = 0; + // Thread started by LoadExec is waiting for these plugins + std::vector startingPlugins; + // TODO: Should we store these grouped by moduleName instead? Seems more reasonable. std::vector exportedFuncs; std::vector importedFuncs; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index b2eb4d1011..b3d0c59f3c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -84,6 +84,7 @@ const WaitTypeNames waitTypeNames[] = { { WAITTYPE_MICINPUT, "Microphone input"}, { WAITTYPE_NET, "Network"}, { WAITTYPE_USB, "USB" }, + { WAITTYPE_PLUGIN, "Initial plugin load" }, }; const char *WaitTypeToString(WaitType type) { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index a9cff92d5e..adab093201 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -115,6 +115,7 @@ enum WaitType : int { WAITTYPE_MICINPUT = 24, // fake WAITTYPE_NET = 25, // fake WAITTYPE_USB = 26, // fake + WAITTYPE_PLUGIN = 27, // this is fake, for when LoadExec thread is waiting for plugins to finish loading NUM_WAITTYPES };