mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Strict mode checking - no way to forget detaching now.
And if we forget to attach, boom. Hopefully I caught all of them.
This commit is contained in:
parent
916404f0e4
commit
b56eef487c
17 changed files with 84 additions and 19 deletions
|
@ -141,6 +141,8 @@ void PathBrowser::HandlePath() {
|
|||
pendingThread_ = std::thread([&] {
|
||||
SetCurrentThreadName("PathBrowser");
|
||||
|
||||
AndroidJNIThreadContext jniContext; // destructor detaches
|
||||
|
||||
std::unique_lock<std::mutex> guard(pendingLock_);
|
||||
std::vector<File::FileInfo> results;
|
||||
Path lastPath("NONSENSE THAT WONT EQUAL A PATH");
|
||||
|
@ -177,8 +179,6 @@ void PathBrowser::HandlePath() {
|
|||
ready_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
DetachThreadFromJNI();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -526,6 +526,9 @@ std::string Download::RedirectLocation(const std::string &baseUrl) {
|
|||
|
||||
void Download::Do() {
|
||||
SetCurrentThreadName("Downloader::Do");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
resultCode_ = 0;
|
||||
|
||||
std::string downloadURL = url_;
|
||||
|
|
|
@ -133,6 +133,10 @@ static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread)
|
|||
}
|
||||
SetCurrentThreadName(thread->name);
|
||||
|
||||
if (thread->type == TaskType::IO_BLOCKING) {
|
||||
AttachThreadToJNI();
|
||||
}
|
||||
|
||||
const bool isCompute = thread->type == TaskType::CPU_COMPUTE;
|
||||
const auto global_queue_size = [isCompute, &global]() -> int {
|
||||
return isCompute ? global->compute_queue_size.load() : global->io_queue_size.load();
|
||||
|
@ -187,7 +191,9 @@ static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread)
|
|||
}
|
||||
|
||||
// In case it got attached to JNI, detach it. Don't think this has any side effects if called redundantly.
|
||||
DetachThreadFromJNI();
|
||||
if (thread->type == TaskType::IO_BLOCKING) {
|
||||
DetachThreadFromJNI();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) {
|
||||
|
|
|
@ -67,6 +67,15 @@ static EXCEPTION_DISPOSITION NTAPI ignore_handler(EXCEPTION_RECORD *rec,
|
|||
}
|
||||
#endif
|
||||
|
||||
void AttachThreadToJNI() {
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
Android_AttachThreadToJNI();
|
||||
#else
|
||||
// Do nothing
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void DetachThreadFromJNI() {
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
Android_DetachThreadFromJNI();
|
||||
|
|
|
@ -14,13 +14,20 @@ const char *GetCurrentThreadName();
|
|||
// exactly what it is is badly specified and not useful for anything.
|
||||
int GetCurrentThreadIdForDebug();
|
||||
|
||||
// When you know that a thread potentially will make JNI calls, call this after setting its name.
|
||||
void AttachThreadToJNI();
|
||||
|
||||
// Call when leaving threads. On Android, calls DetachCurrentThread.
|
||||
// Threads that use scoped storage I/O end up attached as JNI threads, and will thus
|
||||
// need this in order to follow the rules correctly. Some devices seem to enforce this.
|
||||
void DetachThreadFromJNI();
|
||||
|
||||
// Utility to call the above two functions.
|
||||
class AndroidJNIThreadContext {
|
||||
public:
|
||||
AndroidJNIThreadContext() {
|
||||
AttachThreadToJNI();
|
||||
}
|
||||
~AndroidJNIThreadContext() {
|
||||
DetachThreadFromJNI();
|
||||
}
|
||||
|
|
|
@ -1736,6 +1736,9 @@ void Config::RemoveRecent(const std::string &file) {
|
|||
void Config::CleanRecent() {
|
||||
private_->SetRecentIsosThread([this] {
|
||||
SetCurrentThreadName("RecentISOs");
|
||||
|
||||
AndroidJNIThreadContext jniContext; // destructor detaches
|
||||
|
||||
double startTime = time_now_d();
|
||||
|
||||
std::lock_guard<std::mutex> guard(private_->recentIsosLock);
|
||||
|
@ -1766,8 +1769,6 @@ void Config::CleanRecent() {
|
|||
|
||||
INFO_LOG(SYSTEM, "CleanRecent took %0.2f", time_now_d() - startTime);
|
||||
recentIsos = cleanedRecent;
|
||||
|
||||
DetachThreadFromJNI();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -269,6 +269,8 @@ void CachingFileLoader::StartReadAhead(s64 pos) {
|
|||
aheadThread_ = std::thread([this, pos] {
|
||||
SetCurrentThreadName("FileLoaderReadAhead");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
std::unique_lock<std::recursive_mutex> guard(blocksMutex_);
|
||||
s64 cacheStartPos = pos >> BLOCK_SHIFT;
|
||||
s64 cacheEndPos = cacheStartPos + BLOCK_READAHEAD - 1;
|
||||
|
|
|
@ -227,6 +227,8 @@ void RamCachingFileLoader::StartReadAhead(s64 pos) {
|
|||
aheadThread_ = std::thread([this] {
|
||||
SetCurrentThreadName("FileLoaderReadAhead");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
while (aheadRemaining_ != 0 && !aheadCancel_) {
|
||||
// Where should we look?
|
||||
const u32 cacheStartPos = NextAheadBlock();
|
||||
|
|
|
@ -579,6 +579,7 @@ static void __IoAsyncEndCallback(SceUID threadID, SceUID prevCallbackId) {
|
|||
|
||||
static void __IoManagerThread() {
|
||||
SetCurrentThreadName("IO");
|
||||
AndroidJNIThreadContext jniContext;
|
||||
while (ioManagerThreadEnabled && coreState != CORE_BOOT_ERROR && coreState != CORE_RUNTIME_ERROR && coreState != CORE_POWERDOWN) {
|
||||
ioManager.RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000));
|
||||
}
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Compatibility.h"
|
||||
|
@ -97,6 +99,10 @@ static void MemoryStick_CalcInitialFree() {
|
|||
std::unique_lock<std::mutex> guard(freeCalcMutex);
|
||||
freeCalcStatus = FreeCalcStatus::RUNNING;
|
||||
freeCalcThread = std::thread([] {
|
||||
SetCurrentThreadName("CalcInitialFree");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
memstickInitialFree = pspFileSystem.FreeSpace("ms0:/") + pspFileSystem.ComputeRecursiveDirectorySize("ms0:/PSP/SAVEDATA/");
|
||||
|
||||
std::unique_lock<std::mutex> guard(freeCalcMutex);
|
||||
|
|
|
@ -307,7 +307,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
|
|||
//in case we didn't go through EmuScreen::boot
|
||||
g_Config.loadGameConfig(id, g_paramSFO.GetValueString("TITLE"));
|
||||
host->SendUIMessage("config_loaded", "");
|
||||
INFO_LOG(LOADER,"Loading %s...", bootpath.c_str());
|
||||
INFO_LOG(LOADER, "Loading %s...", bootpath.c_str());
|
||||
|
||||
PSPLoaders_Shutdown();
|
||||
// Note: this thread reads the game binary, loads caches, and links HLE while UI spins.
|
||||
|
@ -319,6 +319,8 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
|
|||
if (coreState != CORE_POWERUP)
|
||||
return;
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
PSP_SetLoading("Loading executable...");
|
||||
// TODO: We can't use the initial error_string pointer.
|
||||
bool success = __KernelLoadExec(bootpath.c_str(), 0, &PSP_CoreParameter().errorString);
|
||||
|
@ -455,6 +457,8 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) {
|
|||
if (coreState != CORE_POWERUP)
|
||||
return;
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
bool success = __KernelLoadExec(finalName.c_str(), 0, &PSP_CoreParameter().errorString);
|
||||
if (success && coreState == CORE_POWERUP) {
|
||||
coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING;
|
||||
|
@ -479,6 +483,8 @@ bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) {
|
|||
if (coreState != CORE_POWERUP)
|
||||
return;
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
bool success = __KernelLoadGEDump("disc0:/data.ppdmp", &PSP_CoreParameter().errorString);
|
||||
if (success && coreState == CORE_POWERUP) {
|
||||
coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING;
|
||||
|
|
|
@ -111,6 +111,8 @@ namespace Reporting
|
|||
static int CalculateCRCThread() {
|
||||
SetCurrentThreadName("ReportCRC");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename));
|
||||
BlockDevice *blockDevice = constructBlockDevice(fileLoader);
|
||||
|
||||
|
|
|
@ -164,6 +164,9 @@ namespace SaveState
|
|||
compressThread_.join();
|
||||
compressThread_ = std::thread([=]{
|
||||
SetCurrentThreadName("SaveStateCompress");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
|
||||
Compress(*result, *state, *base);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -314,6 +314,8 @@ static void ForwardDebuggerRequest(const http::Request &request) {
|
|||
static void ExecuteWebServer() {
|
||||
SetCurrentThreadName("HTTPServer");
|
||||
|
||||
AndroidJNIThreadContext context; // Destructor detaches.
|
||||
|
||||
auto http = new http::Server(new NewThreadExecutor());
|
||||
http->RegisterHandler("/", &HandleListing);
|
||||
// This lists all the (current) recent ISOs.
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Common/Net/HTTPClient.h"
|
||||
#include "Common/Net/Resolve.h"
|
||||
#include "Common/Net/URL.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
|
||||
#include "Common/File/PathBrowser.h"
|
||||
#include "Common/Data/Format/JSONReader.h"
|
||||
|
@ -366,6 +367,7 @@ RemoteISOConnectScreen::RemoteISOConnectScreen() {
|
|||
scanAborted = false;
|
||||
|
||||
scanThread_ = new std::thread([](RemoteISOConnectScreen *thiz) {
|
||||
SetCurrentThreadName("RemoteISOScan");
|
||||
thiz->ExecuteScan();
|
||||
}, this);
|
||||
}
|
||||
|
|
|
@ -236,17 +236,7 @@ void AndroidLogger::Log(const LogMessage &message) {
|
|||
JNIEnv* getEnv() {
|
||||
JNIEnv *env;
|
||||
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||
if (status < 0) {
|
||||
// TODO: We should have a version of getEnv that doesn't allow auto-attach.
|
||||
INFO_LOG(SYSTEM, "Thread '%s' not attached to JVM, attaching.", GetCurrentThreadName());
|
||||
JavaVMAttachArgs args{};
|
||||
args.version = JNI_VERSION_1_6;
|
||||
args.name = GetCurrentThreadName();
|
||||
status = gJvm->AttachCurrentThread(&env, &args);
|
||||
if (status < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
_assert_msg_(status >= 0, "'%s': Can only call getEnv if you've attached the thread already!", GetCurrentThreadName());
|
||||
return env;
|
||||
}
|
||||
|
||||
|
@ -270,9 +260,31 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
|
|||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
void Android_AttachThreadToJNI() {
|
||||
JNIEnv *env;
|
||||
int status = gJvm->GetEnv((void **)&env, JNI_VERSION_1_6);
|
||||
if (status < 0) {
|
||||
// TODO: We should have a version of getEnv that doesn't allow auto-attach.
|
||||
INFO_LOG(SYSTEM, "Attaching thread '%s' (not already attached) to JNI.", GetCurrentThreadName());
|
||||
JavaVMAttachArgs args{};
|
||||
args.version = JNI_VERSION_1_6;
|
||||
args.name = GetCurrentThreadName();
|
||||
status = gJvm->AttachCurrentThread(&env, &args);
|
||||
|
||||
if (status < 0) {
|
||||
// bad, but wh
|
||||
}
|
||||
} else {
|
||||
WARN_LOG(SYSTEM, "Thread %s was already attached to JNI.", GetCurrentThreadName());
|
||||
}
|
||||
}
|
||||
|
||||
void Android_DetachThreadFromJNI() {
|
||||
INFO_LOG(SYSTEM, "Detaching thread from JNI: '%s'", GetCurrentThreadName());
|
||||
gJvm->DetachCurrentThread();
|
||||
if (gJvm->DetachCurrentThread() == JNI_OK) {
|
||||
INFO_LOG(SYSTEM, "Detached thread from JNI: '%s'", GetCurrentThreadName());
|
||||
} else {
|
||||
WARN_LOG(SYSTEM, "Failed to detach thread '%s' from JNI - never attached?", GetCurrentThreadName());
|
||||
}
|
||||
}
|
||||
|
||||
// Only used in OpenGL mode.
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
};
|
||||
#endif
|
||||
|
||||
void Android_AttachThreadToJNI();
|
||||
void Android_DetachThreadFromJNI();
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue