mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 12:25:28 +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/)
|
// 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) {
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user