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/) // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <csignal> #include <csignal>
#include <pthread.h>
#include <unistd.h> #include <unistd.h>
#include <sys/resource.h>
#include <android/log.h> #include <android/log.h>
#include "skyline/loader/loader.h" #include "skyline/loader/loader.h"
#include "skyline/common.h" #include "skyline/common.h"
@ -21,8 +21,7 @@ std::weak_ptr<skyline::gpu::GPU> GpuWeak;
std::weak_ptr<skyline::input::Input> InputWeak; 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) { 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; Fps = FrameTime = 0;
FrameTime = 0;
pthread_setname_np(pthread_self(), "EmuMain"); pthread_setname_np(pthread_self(), "EmuMain");
@ -65,31 +64,39 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
close(romFd); 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()}; auto os{OsWeak.lock()};
while (!os) if (!os)
os = OsWeak.lock(); return false;
auto process{os->state.process}; auto process{os->state.process};
while (!process) { if (!process)
__sync_synchronize(); return false;
process = os->state.process;
}
process->Kill(true, false, true); 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()}; auto gpu{GpuWeak.lock()};
while (!gpu) if (!gpu)
gpu = GpuWeak.lock(); return false;
gpu->presentation.UpdateSurface(surface); gpu->presentation.UpdateSurface(surface);
return true;
} }
extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *, jobject) { extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_updatePerformanceStatistics(JNIEnv *env, jobject thiz) {
return Fps; static jclass clazz{};
} if (!clazz)
clazz = env->GetObjectClass(thiz);
extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *, jobject) { static jfieldID fpsField{};
return static_cast<float>(FrameTime) / 100; 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) { 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> template<class T>
T PointerValue(T item) { T PointerValue(T item) {
@ -144,6 +144,17 @@ namespace skyline {
return reinterpret_cast<uintptr_t>(item); 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 * @return The value aligned up to the next multiple
* @note The multiple needs to be a power of 2 * @note The multiple needs to be a power of 2
@ -151,7 +162,7 @@ namespace skyline {
template<typename TypeVal, typename TypeMul> template<typename TypeVal, typename TypeMul>
constexpr TypeVal AlignUp(TypeVal value, TypeMul multiple) { constexpr TypeVal AlignUp(TypeVal value, TypeMul multiple) {
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> template<typename TypeVal, typename TypeMul>
constexpr TypeVal AlignDown(TypeVal value, TypeMul multiple) { 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 constexpr u16 instructionCount{20}; // The amount of previous instructions to print
auto offset{ctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))}; auto offset{ctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))};
span instructions(reinterpret_cast<u32 *>(offset), instructionCount); 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) { for (auto &instruction : instructions) {
instruction = __builtin_bswap32(instruction); instruction = __builtin_bswap32(instruction);
@ -75,7 +75,7 @@ namespace skyline::nce {
state.logger->Debug("Process Trace:{}", trace); state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw); state.logger->Debug("Raw Instructions: 0x{}", raw);
} else { } 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) if (ctx.fault_address)
@ -85,7 +85,7 @@ namespace skyline::nce {
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp); cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp);
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2) 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); 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) 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 * 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 * @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 private external fun updatePerformanceStatistics()
/**
* This returns the current frame-time of the application
*/
private external fun getFrametime() : Float
/** /**
* This initializes a guest controller in libskyline * This initializes a guest controller in libskyline
@ -170,7 +169,10 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
emulationThread = Thread { emulationThread = Thread {
executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), applicationContext.filesDir.canonicalPath + "/") executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), applicationContext.filesDir.canonicalPath + "/")
if (shouldFinish) if (shouldFinish)
runOnUiThread { finish() } runOnUiThread {
emulationThread.join()
finish()
}
} }
emulationThread.start() emulationThread.start()
@ -203,7 +205,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
if (settings.perfStats) { if (settings.perfStats) {
perf_stats.postDelayed(object : Runnable { perf_stats.postDelayed(object : Runnable {
override fun run() { 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) perf_stats.postDelayed(this, 250)
} }
}, 250) }, 250)
@ -234,7 +237,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
super.onNewIntent(intent) super.onNewIntent(intent)
shouldFinish = false shouldFinish = false
stopEmulation() while (emulationThread.isAlive)
if (stopEmulation())
emulationThread.join() emulationThread.join()
shouldFinish = true shouldFinish = true
@ -246,7 +250,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
super.onDestroy() super.onDestroy()
shouldFinish = false shouldFinish = false
stopEmulation() while (emulationThread.isAlive)
if (stopEmulation())
emulationThread.join() emulationThread.join()
vibrators.forEach { (_, vibrator) -> vibrator.cancel() } vibrators.forEach { (_, vibrator) -> vibrator.cancel() }
@ -259,7 +264,9 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
override fun surfaceCreated(holder : SurfaceHolder) { override fun surfaceCreated(holder : SurfaceHolder) {
Log.d(Tag, "surfaceCreated Holder: $holder") Log.d(Tag, "surfaceCreated Holder: $holder")
surface = holder.surface 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) { override fun surfaceDestroyed(holder : SurfaceHolder) {
Log.d(Tag, "surfaceDestroyed Holder: $holder") Log.d(Tag, "surfaceDestroyed Holder: $holder")
surface = null surface = null
setSurface(surface) while (emulationThread.isAlive)
if (setSurface(surface))
return
} }
/** /**