feat(servei): reinici real via execv
This commit is contained in:
1 parent
774874deb0
commit
a8ccb3fae1
5 files changed
+97
-11
No files matched your search
@@ -65,6 +65,7 @@ set(ENTITY_SOURCES
|
|||||||
set(APP_SOURCES
|
set(APP_SOURCES
|
||||||
source/main.cpp
|
source/main.cpp
|
||||||
source/core/system/director.cpp
|
source/core/system/director.cpp
|
||||||
|
source/core/system/relaunch.cpp
|
||||||
source/core/audio/audio.cpp
|
source/core/audio/audio.cpp
|
||||||
source/core/audio/audio_adapter.cpp
|
source/core/audio/audio_adapter.cpp
|
||||||
source/core/audio/audio_effects.cpp
|
source/core/audio/audio_effects.cpp
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// relaunch.cpp - Implementació del reinici en calent
|
||||||
|
|
||||||
|
#include "core/system/relaunch.hpp"
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h> // _execv
|
||||||
|
#else
|
||||||
|
#include <unistd.h> // execv
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Estat global (process-scope). Aquesta TU és l'única que gestiona el
|
||||||
|
// reinici, així que els statics interns no s'escapen.
|
||||||
|
char** g_argv = nullptr;
|
||||||
|
bool g_requested = false;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace System::Relaunch {
|
||||||
|
|
||||||
|
void setArgv(int /*argc*/, char** argv) {
|
||||||
|
g_argv = argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void request() {
|
||||||
|
g_requested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execIfRequested() {
|
||||||
|
if (!g_requested || g_argv == nullptr || g_argv[0] == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::cout << "[Relaunch] Reiniciant " << g_argv[0] << "...\n";
|
||||||
|
#ifdef _WIN32
|
||||||
|
_execv(g_argv[0], g_argv);
|
||||||
|
#else
|
||||||
|
execv(g_argv[0], g_argv);
|
||||||
|
#endif
|
||||||
|
// Si arribem aquí, execv ha fallat. Tots els subsistemes ja estan
|
||||||
|
// destruïts; sortim amb error i el shell rebrà el codi.
|
||||||
|
std::cerr << "[Relaunch] Ha fallat: " << std::strerror(errno) << '\n';
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace System::Relaunch
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// relaunch.hpp - Reinici en calent del procés (execv)
|
||||||
|
//
|
||||||
|
// Helper desacoblat perquè el menú de servei demani un reinici sense conèixer
|
||||||
|
// ni Director ni main.cpp. Patró d'ús:
|
||||||
|
//
|
||||||
|
// main() → Relaunch::setArgv(argc, argv) (a l'arrencada)
|
||||||
|
// ServiceMenu → Relaunch::request() (en activar "Reiniciar")
|
||||||
|
// main() → Relaunch::execIfRequested() (al final de SDL_AppQuit)
|
||||||
|
//
|
||||||
|
// L'execv() reemplaça el procés actual: si torna, ha fallat. Es crida després
|
||||||
|
// de destruir el Director per garantir que GPU/àudio/SDL ja són morts.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace System::Relaunch {
|
||||||
|
|
||||||
|
// Emmagatzema l'argv original. Cal cridar-ho una vegada des de main.
|
||||||
|
void setArgv(int argc, char** argv);
|
||||||
|
|
||||||
|
// Demana un reinici (no actua immediatament; només marca el flag).
|
||||||
|
void request();
|
||||||
|
|
||||||
|
// Si hi ha reinici demanat i tenim argv vàlid, fa execv. En cas d'èxit
|
||||||
|
// no torna. Si execv falla, registra l'error per stderr i surt amb
|
||||||
|
// EXIT_FAILURE (no podem reprendre — els subsistemes ja estan destruïts).
|
||||||
|
void execIfRequested();
|
||||||
|
|
||||||
|
} // namespace System::Relaunch
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "core/rendering/screen.hpp"
|
#include "core/rendering/screen.hpp"
|
||||||
#include "core/rendering/text.hpp"
|
#include "core/rendering/text.hpp"
|
||||||
#include "core/system/event_buffer.hpp"
|
#include "core/system/event_buffer.hpp"
|
||||||
|
#include "core/system/relaunch.hpp"
|
||||||
#include "core/ui/ui_config.hpp"
|
#include "core/ui/ui_config.hpp"
|
||||||
#include "game/gameplay_config.hpp"
|
#include "game/gameplay_config.hpp"
|
||||||
#include "game/options.hpp"
|
#include "game/options.hpp"
|
||||||
@@ -1228,18 +1229,17 @@ auto ServiceMenu::buildSystem() -> Page {
|
|||||||
page.items.push_back(makeLabel(
|
page.items.push_back(makeLabel(
|
||||||
std::string("ver.") + Texts::VERSION + " (" + Version::GIT_HASH + ")"));
|
std::string("ver.") + Texts::VERSION + " (" + Version::GIT_HASH + ")"));
|
||||||
|
|
||||||
// Reiniciar el joc: tornem al LOGO amb `reset=true` perquè LogoScene
|
// Reinici real del procés: marquem el flag i empenyem QUIT. SDL_AppQuit
|
||||||
// ature música i sons abans de mostrar-se. Tanquem el menú a la
|
// destruirà tots els subsistemes i llavors farà execv (al final, amb tot
|
||||||
// mateixa acció — Director recollirà la transició al final del frame
|
// net) per substituir el binari per ell mateix. Si execv falla, el procés
|
||||||
// via `takePendingSceneRequest()` i reconstruirà l'escena.
|
// surt amb error.
|
||||||
page.items.push_back(makeAction(
|
page.items.push_back(makeAction(
|
||||||
"menu.items.restart",
|
"menu.items.restart",
|
||||||
[]() {
|
[]() {
|
||||||
ServiceMenu::get().requestSceneTransition(ExitRequest{
|
System::Relaunch::request();
|
||||||
.next = SceneId::LOGO,
|
SDL_Event quit_event{};
|
||||||
.params = LogoParams{.reset = true},
|
quit_event.type = SDL_EVENT_QUIT;
|
||||||
});
|
EventBuffer::events.push_back(quit_event);
|
||||||
ServiceMenu::get().close();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
page.items.push_back(makeAction(
|
page.items.push_back(makeAction(
|
||||||
|
|||||||
+8
-2
@@ -7,11 +7,13 @@
|
|||||||
|
|
||||||
#include "core/system/director.hpp"
|
#include "core/system/director.hpp"
|
||||||
#include "core/system/event_buffer.hpp"
|
#include "core/system/event_buffer.hpp"
|
||||||
|
#include "core/system/relaunch.hpp"
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
|
|
||||||
auto SDL_AppInit(void** appstate, int argc, char* argv[]) -> SDL_AppResult {
|
auto SDL_AppInit(void** appstate, int argc, char* argv[]) -> SDL_AppResult {
|
||||||
(void)argc;
|
// Desem argv perquè el menú de servei pugui demanar un reinici en calent
|
||||||
(void)argv;
|
// (execv) sense haver de conèixer ni Director ni main.
|
||||||
|
System::Relaunch::setArgv(argc, argv);
|
||||||
|
|
||||||
// Logger primer de tot perquè l'arrencada del Director ja emet logs.
|
// Logger primer de tot perquè l'arrencada del Director ja emet logs.
|
||||||
Log::init();
|
Log::init();
|
||||||
@@ -45,6 +47,10 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
|||||||
{
|
{
|
||||||
std::unique_ptr<Director> director(static_cast<Director*>(appstate));
|
std::unique_ptr<Director> director(static_cast<Director*>(appstate));
|
||||||
}
|
}
|
||||||
|
// Si el menú va demanar reinici, fem execv ara que tot està net. En èxit
|
||||||
|
// no torna (el procés és reemplaçat) i el "Bye!" no s'imprimeix — correcte,
|
||||||
|
// no és una sortida.
|
||||||
|
System::Relaunch::execIfRequested();
|
||||||
// Marcador de fi: ha de ser l'ÚLTIMA línia de log del programa.
|
// Marcador de fi: ha de ser l'ÚLTIMA línia de log del programa.
|
||||||
Log::raw(Log::Level::INFO, "Bye!");
|
Log::raw(Log::Level::INFO, "Bye!");
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user