mirror of
https://github.com/obhq/obliteration.git
synced 2024-10-06 16:03:22 +00:00
Extracts kernel into a separated process
This commit is contained in:
parent
d5d7f8c167
commit
18bc1ad606
1
.obliteration-development
Normal file
1
.obliteration-development
Normal file
@ -0,0 +1 @@
|
||||
This file used for detection of development binary in src/main_window.cpp.
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,5 +1,8 @@
|
||||
{
|
||||
"cmake.configureOnOpen": true,
|
||||
"cmake.debugConfig": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.trimTrailingWhitespace": true
|
||||
|
@ -6,19 +6,22 @@ find_package(Qt6 COMPONENTS Widgets REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Setup Rust target.
|
||||
set(RUST_OUTPUTS $<IF:$<CONFIG:Debug>,${CMAKE_CURRENT_SOURCE_DIR}/target/debug,${CMAKE_CURRENT_SOURCE_DIR}/target/release>)
|
||||
set(KERNEL ${RUST_OUTPUTS}/obliteration-kernel${CMAKE_EXECUTABLE_SUFFIX})
|
||||
|
||||
if(WIN32)
|
||||
set(LIBCORE $<IF:$<CONFIG:Debug>,${CMAKE_CURRENT_SOURCE_DIR}/target/debug/core.lib,${CMAKE_CURRENT_SOURCE_DIR}/target/release/core.lib>)
|
||||
set(LIBCORE ${RUST_OUTPUTS}/core.lib)
|
||||
else()
|
||||
set(LIBCORE $<IF:$<CONFIG:Debug>,${CMAKE_CURRENT_SOURCE_DIR}/target/debug/libcore.a,${CMAKE_CURRENT_SOURCE_DIR}/target/release/libcore.a>)
|
||||
set(LIBCORE ${RUST_OUTPUTS}/libcore.a)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(libcore
|
||||
ExternalProject_Add(core
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND cargo build $<IF:$<CONFIG:Debug>,-v,--release>
|
||||
BUILD_IN_SOURCE ON
|
||||
BUILD_ALWAYS ON
|
||||
BUILD_BYPRODUCTS ${LIBCORE}
|
||||
BUILD_BYPRODUCTS ${KERNEL} ${LIBCORE}
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND cargo test
|
||||
TEST_EXCLUDE_FROM_MAIN ON)
|
||||
@ -40,7 +43,7 @@ if(WIN32)
|
||||
target_sources(obliteration PRIVATE resources.rc)
|
||||
endif()
|
||||
|
||||
add_dependencies(obliteration libcore)
|
||||
add_dependencies(obliteration core)
|
||||
|
||||
set_target_properties(obliteration PROPERTIES AUTOMOC ON AUTORCC ON)
|
||||
|
||||
@ -67,4 +70,5 @@ else()
|
||||
install(TARGETS obliteration DESTINATION bin)
|
||||
endif()
|
||||
|
||||
install(PROGRAMS ${KERNEL} TYPE BIN)
|
||||
install(SCRIPT post-install.cmake)
|
||||
|
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
@ -100,7 +100,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"context",
|
||||
"error",
|
||||
"kernel",
|
||||
"pkg",
|
||||
]
|
||||
|
||||
|
@ -9,4 +9,4 @@ members = [
|
||||
"util"
|
||||
]
|
||||
|
||||
default-members = ["core"]
|
||||
default-members = ["core", "kernel"]
|
||||
|
@ -9,5 +9,4 @@ crate-type = ["staticlib"]
|
||||
[dependencies]
|
||||
context = { path = "../context" }
|
||||
error = { path = "../error" }
|
||||
kernel = { path = "../kernel" }
|
||||
pkg = { path = "../pkg" }
|
||||
|
@ -3,5 +3,4 @@
|
||||
// of those APIs here.
|
||||
pub use context::*;
|
||||
pub use error::*;
|
||||
pub use kernel::*;
|
||||
pub use pkg::*;
|
||||
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "error.hpp"
|
||||
|
||||
struct kernel;
|
||||
struct kernel_rootfs;
|
||||
struct kernel_pfs;
|
||||
|
||||
typedef void (*kernel_logger_t) (int pid, int err, const char *msg, void *ud);
|
||||
|
||||
extern "C" {
|
||||
// The returned kernel will take the ownership of rootfs.
|
||||
kernel *kernel_new(kernel_rootfs *rootfs, error **err);
|
||||
void kernel_shutdown(kernel *krn);
|
||||
|
||||
void kernel_set_logger(kernel *krn, kernel_logger_t logger, void *ud);
|
||||
|
||||
kernel_rootfs *kernel_rootfs_new(error **err);
|
||||
void kernel_rootfs_free(kernel_rootfs *fs);
|
||||
}
|
@ -3,6 +3,10 @@ name = "kernel"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "obliteration-kernel"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
error = { path = "../error" }
|
||||
memmap2 = "0.5"
|
||||
|
@ -1,39 +0,0 @@
|
||||
use self::rootfs::RootFs;
|
||||
use std::ffi::c_void;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
|
||||
pub mod fs;
|
||||
pub mod rootfs;
|
||||
|
||||
pub type Logger = extern "C" fn(c_int, c_int, *const c_char, ud: *mut c_void);
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kernel_new(
|
||||
rootfs: *mut RootFs<'static>,
|
||||
_: *mut *mut error::Error,
|
||||
) -> *mut Kernel {
|
||||
let krn = Box::new(Kernel {
|
||||
rootfs: unsafe { *Box::from_raw(rootfs) },
|
||||
logger: None,
|
||||
});
|
||||
|
||||
Box::into_raw(krn)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kernel_shutdown(krn: *mut Kernel) {
|
||||
unsafe { Box::from_raw(krn) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kernel_set_logger(krn: &mut Kernel, logger: Option<Logger>, ud: *mut c_void) {
|
||||
krn.logger = match logger {
|
||||
Some(v) => Some((v, ud)),
|
||||
None => None,
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Kernel {
|
||||
rootfs: RootFs<'static>,
|
||||
logger: Option<(Logger, *mut c_void)>,
|
||||
}
|
3
src/kernel/src/main.rs
Normal file
3
src/kernel/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
loop {}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include "pkg.hpp"
|
||||
#include "progress_dialog.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "string.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <QAction>
|
||||
@ -12,6 +13,7 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QGuiApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QIcon>
|
||||
#include <QListView>
|
||||
@ -25,6 +27,8 @@
|
||||
#include <QToolBar>
|
||||
#include <QUrl>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
MainWindow::MainWindow(context *context) :
|
||||
m_context(context),
|
||||
m_tab(nullptr),
|
||||
@ -147,9 +151,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
// Shutdown.
|
||||
kernel_shutdown(m_kernel);
|
||||
m_kernel = nullptr;
|
||||
killKernel();
|
||||
}
|
||||
|
||||
// Save gometry.
|
||||
@ -293,44 +295,6 @@ void MainWindow::aboutObliteration()
|
||||
QMessageBox::about(this, "About Obliteration", "Obliteration is a free and open-source software for playing your PlayStation 4 titles on PC.");
|
||||
}
|
||||
|
||||
void MainWindow::startGame(const QModelIndex &index)
|
||||
{
|
||||
if (!requireEmulatorStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get target game.
|
||||
auto model = reinterpret_cast<GameListModel *>(m_games->model());
|
||||
auto game = model->get(index.row()); // Qt already guaranteed the index is valid.
|
||||
|
||||
// Setup rootfs.
|
||||
Error error;
|
||||
|
||||
auto rootfs = kernel_rootfs_new(&error);
|
||||
|
||||
if (!rootfs) {
|
||||
QMessageBox::critical(this, "Error", QString("Failed to create rootfs: %1").arg(error.message()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup kernel.
|
||||
m_kernel = kernel_new(rootfs, &error);
|
||||
|
||||
if (!m_kernel) {
|
||||
kernel_rootfs_free(rootfs);
|
||||
QMessageBox::critical(this, "Error", QString("Failed to create kernel: %1").arg(error.message()));
|
||||
return;
|
||||
}
|
||||
|
||||
kernel_set_logger(m_kernel, [](int pid, int err, const char *msg, void *ud) {
|
||||
reinterpret_cast<MainWindow *>(ud)->appendLog(pid, err, msg);
|
||||
}, this);
|
||||
|
||||
// Clear previous log and switch to log view.
|
||||
m_log->clear();
|
||||
m_tab->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void MainWindow::requestGamesContextMenu(const QPoint &pos)
|
||||
{
|
||||
// Get item index.
|
||||
@ -362,6 +326,107 @@ void MainWindow::requestGamesContextMenu(const QPoint &pos)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::startGame(const QModelIndex &index)
|
||||
{
|
||||
if (!requireEmulatorStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get target game.
|
||||
auto model = reinterpret_cast<GameListModel *>(m_games->model());
|
||||
auto game = model->get(index.row()); // Qt already guaranteed the index is valid.
|
||||
|
||||
// Clear previous log and switch to log view.
|
||||
m_log->clear();
|
||||
m_tab->setCurrentIndex(1);
|
||||
|
||||
// Get full path to kernel binary.
|
||||
QString path;
|
||||
|
||||
if (QFile::exists(".obliteration-development")) {
|
||||
auto b = std::filesystem::current_path();
|
||||
|
||||
b /= S("src");
|
||||
b /= S("target");
|
||||
#ifdef NDEBUG
|
||||
b /= S("release");
|
||||
#else
|
||||
b /= S("debug");
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
b /= L"obliteration-kernel.exe";
|
||||
path = QString::fromStdWString(b.wstring());
|
||||
#else
|
||||
b /= "obliteration-kernel";
|
||||
path = QString::fromStdString(b.string());
|
||||
#endif
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
std::filesystem::path b(QCoreApplication::applicationDirPath().toStdString(), std::filesystem::path::native_format);
|
||||
b /= L"bin";
|
||||
b /= L"obliteration-kernel.exe";
|
||||
path = QString::fromStdWString(b.wstring());
|
||||
#else
|
||||
std::filesystem::path b(QCoreApplication::applicationDirPath().toStdString(), std::filesystem::path::native_format);
|
||||
b /= "obliteration-kernel";
|
||||
path = QString::fromStdString(b.string());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Prepare kernel launching.
|
||||
m_kernel = new QProcess(this);
|
||||
m_kernel->setProgram(path);
|
||||
m_kernel->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
connect(m_kernel, &QProcess::errorOccurred, this, &MainWindow::kernelError);
|
||||
connect(m_kernel, &QIODevice::readyRead, this, &MainWindow::kernelOutput);
|
||||
connect(m_kernel, &QProcess::finished, this, &MainWindow::kernelTerminated);
|
||||
|
||||
// Launch kernel.
|
||||
m_kernel->start(QIODeviceBase::ReadOnly | QIODeviceBase::Text);
|
||||
}
|
||||
|
||||
void MainWindow::kernelError(QProcess::ProcessError error)
|
||||
{
|
||||
// Display error.
|
||||
QString msg;
|
||||
|
||||
switch (error) {
|
||||
case QProcess::FailedToStart:
|
||||
msg = QString("Failed to launch %1.").arg(m_kernel->program());
|
||||
break;
|
||||
case QProcess::Crashed:
|
||||
msg = "The kernel crashed.";
|
||||
break;
|
||||
default:
|
||||
msg = "An unknown error occurred on the kernel";
|
||||
}
|
||||
|
||||
QMessageBox::critical(this, "Error", msg);
|
||||
|
||||
// Destroy object.
|
||||
m_kernel->deleteLater();
|
||||
m_kernel = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::kernelOutput()
|
||||
{
|
||||
while (m_kernel->canReadLine()) {
|
||||
auto line = QString::fromUtf8(m_kernel->readLine());
|
||||
|
||||
m_log->appendPlainText(line);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::kernelTerminated(int, QProcess::ExitStatus)
|
||||
{
|
||||
kernelOutput();
|
||||
|
||||
m_kernel->deleteLater();
|
||||
m_kernel = nullptr;
|
||||
}
|
||||
|
||||
bool MainWindow::loadGame(const QString &gameId)
|
||||
{
|
||||
auto gamesDirectory = readGamesDirectorySetting();
|
||||
@ -391,19 +456,16 @@ bool MainWindow::loadGame(const QString &gameId)
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::appendLog(int pid, int err, const char *msg)
|
||||
void MainWindow::killKernel()
|
||||
{
|
||||
m_log->appendHtml(QString("<strong>[PID:%1]:</strong> ").arg(pid));
|
||||
// We need to disconnect all slots first otherwise the application will be freezing.
|
||||
disconnect(m_kernel, nullptr, nullptr, nullptr);
|
||||
|
||||
if (err) {
|
||||
m_log->appendHtml(R"(<span style="color:red">)");
|
||||
}
|
||||
m_kernel->kill();
|
||||
m_kernel->waitForFinished(-1);
|
||||
|
||||
m_log->appendPlainText(msg);
|
||||
|
||||
if (err) {
|
||||
m_log->appendHtml(R"(</span>)");
|
||||
}
|
||||
delete m_kernel;
|
||||
m_kernel = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::restoreGeometry()
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "context.hpp"
|
||||
#include "kernel.hpp"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QProcess>
|
||||
|
||||
class QListView;
|
||||
class QPlainTextEdit;
|
||||
@ -23,12 +23,15 @@ private slots:
|
||||
void installPkg();
|
||||
void reportIssue();
|
||||
void aboutObliteration();
|
||||
void startGame(const QModelIndex &index);
|
||||
void requestGamesContextMenu(const QPoint &pos);
|
||||
void startGame(const QModelIndex &index);
|
||||
void kernelError(QProcess::ProcessError error);
|
||||
void kernelOutput();
|
||||
void kernelTerminated(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
private:
|
||||
bool loadGame(const QString &gameId);
|
||||
void appendLog(int pid, int err, const char *msg);
|
||||
void killKernel();
|
||||
void restoreGeometry();
|
||||
bool requireEmulatorStopped();
|
||||
|
||||
@ -37,5 +40,5 @@ private:
|
||||
QTabWidget *m_tab;
|
||||
QListView *m_games;
|
||||
QPlainTextEdit *m_log;
|
||||
kernel *m_kernel;
|
||||
QProcess *m_kernel;
|
||||
};
|
||||
|
7
src/string.hpp
Normal file
7
src/string.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define S(x) L##x
|
||||
#else
|
||||
#define S(x) x
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user