mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 06:35:30 +03:00
Fix Native-Initiated Exiting
This commit is contained in:
parent
d155e9cd71
commit
a5927c5c7b
@ -2,8 +2,8 @@
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/resource.h>
|
||||
#include <android/log.h>
|
||||
#include "skyline/loader/loader.h"
|
||||
#include "skyline/common.h"
|
||||
@ -21,8 +21,7 @@ std::weak_ptr<skyline::gpu::GPU> GpuWeak;
|
||||
std::weak_ptr<skyline::input::Input> InputWeak;
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(JNIEnv *env, jobject instance, jstring romUriJstring, jint romType, jint romFd, jint preferenceFd, jstring appFilesPathJstring) {
|
||||
Fps = 0;
|
||||
FrameTime = 0;
|
||||
Fps = FrameTime = 0;
|
||||
|
||||
pthread_setname_np(pthread_self(), "EmuMain");
|
||||
|
||||
@ -65,31 +64,39 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
||||
close(romFd);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_stopEmulation(JNIEnv *, jobject) {
|
||||
extern "C" JNIEXPORT jboolean Java_emu_skyline_EmulationActivity_stopEmulation(JNIEnv *, jobject) {
|
||||
auto os{OsWeak.lock()};
|
||||
while (!os)
|
||||
os = OsWeak.lock();
|
||||
if (!os)
|
||||
return false;
|
||||
auto process{os->state.process};
|
||||
while (!process) {
|
||||
__sync_synchronize();
|
||||
process = os->state.process;
|
||||
}
|
||||
if (!process)
|
||||
return false;
|
||||
process->Kill(true, false, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *, jobject, jobject surface) {
|
||||
extern "C" JNIEXPORT jboolean Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *, jobject, jobject surface) {
|
||||
auto gpu{GpuWeak.lock()};
|
||||
while (!gpu)
|
||||
gpu = GpuWeak.lock();
|
||||
if (!gpu)
|
||||
return false;
|
||||
gpu->presentation.UpdateSurface(surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *, jobject) {
|
||||
return Fps;
|
||||
}
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_updatePerformanceStatistics(JNIEnv *env, jobject thiz) {
|
||||
static jclass clazz{};
|
||||
if (!clazz)
|
||||
clazz = env->GetObjectClass(thiz);
|
||||
|
||||
extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *, jobject) {
|
||||
return static_cast<float>(FrameTime) / 100;
|
||||
static jfieldID fpsField{};
|
||||
if (!fpsField)
|
||||
fpsField = env->GetFieldID(clazz, "fps", "I");
|
||||
env->SetIntField(thiz, fpsField, Fps);
|
||||
|
||||
static jfieldID frametimeField{};
|
||||
if (!frametimeField)
|
||||
frametimeField = env->GetFieldID(clazz, "frametime", "F");
|
||||
env->SetFloatField(thiz, frametimeField, static_cast<float>(FrameTime) / 100);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setController(JNIEnv *, jobject, jint index, jint type, jint partnerIndex) {
|
||||
|
@ -132,7 +132,7 @@ namespace skyline {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A way to implicitly convert a pointer to size_t and leave it unaffected if it isn't a pointer
|
||||
* @brief A way to implicitly convert a pointer to uintptr_t and leave it unaffected if it isn't a pointer
|
||||
*/
|
||||
template<class T>
|
||||
T PointerValue(T item) {
|
||||
@ -144,6 +144,17 @@ namespace skyline {
|
||||
return reinterpret_cast<uintptr_t>(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A way to implicitly convert an integral to a pointer, if the return type is a pointer
|
||||
*/
|
||||
template<class Return, class T>
|
||||
Return ValuePointer(T item) {
|
||||
if constexpr (std::is_pointer<Return>::value)
|
||||
return reinterpret_cast<Return>(item);
|
||||
else
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value aligned up to the next multiple
|
||||
* @note The multiple needs to be a power of 2
|
||||
@ -151,7 +162,7 @@ namespace skyline {
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
constexpr TypeVal AlignUp(TypeVal value, TypeMul multiple) {
|
||||
multiple--;
|
||||
return (PointerValue(value) + multiple) & ~(multiple);
|
||||
return ValuePointer<TypeVal>((PointerValue(value) + multiple) & ~(multiple));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,7 +171,7 @@ namespace skyline {
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
constexpr TypeVal AlignDown(TypeVal value, TypeMul multiple) {
|
||||
return PointerValue(value) & ~(multiple - 1);
|
||||
return ValuePointer<TypeVal>(PointerValue(value) & ~(multiple - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@ namespace skyline::nce {
|
||||
constexpr u16 instructionCount{20}; // The amount of previous instructions to print
|
||||
auto offset{ctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))};
|
||||
span instructions(reinterpret_cast<u32 *>(offset), instructionCount);
|
||||
if (mprotect(instructions.data(), instructions.size_bytes(), PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
|
||||
if (mprotect(util::AlignDown(instructions.data(), PAGE_SIZE), util::AlignUp(instructions.size_bytes(), PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
|
||||
for (auto &instruction : instructions) {
|
||||
instruction = __builtin_bswap32(instruction);
|
||||
|
||||
@ -75,7 +75,7 @@ namespace skyline::nce {
|
||||
state.logger->Debug("Process Trace:{}", trace);
|
||||
state.logger->Debug("Raw Instructions: 0x{}", raw);
|
||||
} else {
|
||||
cpuContext += fmt::format("\nPC: 0x{:X}", ctx.pc);
|
||||
cpuContext += fmt::format("\nPC: 0x{:X} ('mprotect' failed with '{}')", ctx.pc, strerror(errno));
|
||||
}
|
||||
|
||||
if (ctx.fault_address)
|
||||
@ -85,7 +85,7 @@ namespace skyline::nce {
|
||||
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp);
|
||||
|
||||
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2)
|
||||
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? ' ' : '\0', index + 1, ctx.regs[index]);
|
||||
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? 'X' : '\0', index + 1, ctx.regs[index]);
|
||||
|
||||
state.logger->Debug("CPU Context:{}", cpuContext);
|
||||
}
|
||||
|
@ -68,26 +68,25 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
private external fun executeApplication(romUri : String, romType : Int, romFd : Int, preferenceFd : Int, appFilesPath : String)
|
||||
|
||||
/**
|
||||
* Terminate of all emulator threads and cause [emulationThread] to return
|
||||
* @return If it successfully caused the [emulationThread] to gracefully stop
|
||||
*/
|
||||
private external fun stopEmulation()
|
||||
private external fun stopEmulation() : Boolean
|
||||
|
||||
/**
|
||||
* This sets the surface object in libskyline to the provided value, emulation is halted if set to null
|
||||
*
|
||||
* @param surface The value to set surface to
|
||||
* @return If the value was successfully set
|
||||
*/
|
||||
private external fun setSurface(surface : Surface?)
|
||||
private external fun setSurface(surface : Surface?) : Boolean
|
||||
|
||||
var fps : Int = 0
|
||||
var frametime : Float = 0.0f
|
||||
|
||||
/**
|
||||
* This returns the current FPS of the application
|
||||
* Writes the current performance statistics into [fps] and [frametime] fields
|
||||
*/
|
||||
private external fun getFps() : Int
|
||||
|
||||
/**
|
||||
* This returns the current frame-time of the application
|
||||
*/
|
||||
private external fun getFrametime() : Float
|
||||
private external fun updatePerformanceStatistics()
|
||||
|
||||
/**
|
||||
* This initializes a guest controller in libskyline
|
||||
@ -170,7 +169,10 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
emulationThread = Thread {
|
||||
executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), applicationContext.filesDir.canonicalPath + "/")
|
||||
if (shouldFinish)
|
||||
runOnUiThread { finish() }
|
||||
runOnUiThread {
|
||||
emulationThread.join()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
emulationThread.start()
|
||||
@ -203,7 +205,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
if (settings.perfStats) {
|
||||
perf_stats.postDelayed(object : Runnable {
|
||||
override fun run() {
|
||||
perf_stats.text = "${getFps()} FPS\n${getFrametime()}ms"
|
||||
updatePerformanceStatistics()
|
||||
perf_stats.text = "$fps FPS\n${frametime}ms"
|
||||
perf_stats.postDelayed(this, 250)
|
||||
}
|
||||
}, 250)
|
||||
@ -234,8 +237,9 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
super.onNewIntent(intent)
|
||||
shouldFinish = false
|
||||
|
||||
stopEmulation()
|
||||
emulationThread.join()
|
||||
while (emulationThread.isAlive)
|
||||
if (stopEmulation())
|
||||
emulationThread.join()
|
||||
|
||||
shouldFinish = true
|
||||
|
||||
@ -246,8 +250,9 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
super.onDestroy()
|
||||
shouldFinish = false
|
||||
|
||||
stopEmulation()
|
||||
emulationThread.join()
|
||||
while (emulationThread.isAlive)
|
||||
if (stopEmulation())
|
||||
emulationThread.join()
|
||||
|
||||
vibrators.forEach { (_, vibrator) -> vibrator.cancel() }
|
||||
vibrators.clear()
|
||||
@ -259,7 +264,9 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
override fun surfaceCreated(holder : SurfaceHolder) {
|
||||
Log.d(Tag, "surfaceCreated Holder: $holder")
|
||||
surface = holder.surface
|
||||
setSurface(surface)
|
||||
while (emulationThread.isAlive)
|
||||
if (setSurface(surface))
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
@ -275,7 +282,9 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
||||
override fun surfaceDestroyed(holder : SurfaceHolder) {
|
||||
Log.d(Tag, "surfaceDestroyed Holder: $holder")
|
||||
surface = null
|
||||
setSurface(surface)
|
||||
while (emulationThread.isAlive)
|
||||
if (setSurface(surface))
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user