Fix Native-Initiated Exiting

This commit is contained in:
◱ PixelyIon 2020-11-19 01:17:09 +05:30 committed by ◱ PixelyIon
parent d155e9cd71
commit a5927c5c7b
4 changed files with 69 additions and 42 deletions

View File

@ -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) {

View File

@ -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));
}
/**

View File

@ -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);
}

View File

@ -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
}
/**