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
@@ -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/text.hpp"
|
||||
#include "core/system/event_buffer.hpp"
|
||||
#include "core/system/relaunch.hpp"
|
||||
#include "core/ui/ui_config.hpp"
|
||||
#include "game/gameplay_config.hpp"
|
||||
#include "game/options.hpp"
|
||||
@@ -1228,18 +1229,17 @@ auto ServiceMenu::buildSystem() -> Page {
|
||||
page.items.push_back(makeLabel(
|
||||
std::string("ver.") + Texts::VERSION + " (" + Version::GIT_HASH + ")"));
|
||||
|
||||
// Reiniciar el joc: tornem al LOGO amb `reset=true` perquè LogoScene
|
||||
// ature música i sons abans de mostrar-se. Tanquem el menú a la
|
||||
// mateixa acció — Director recollirà la transició al final del frame
|
||||
// via `takePendingSceneRequest()` i reconstruirà l'escena.
|
||||
// Reinici real del procés: marquem el flag i empenyem QUIT. SDL_AppQuit
|
||||
// destruirà tots els subsistemes i llavors farà execv (al final, amb tot
|
||||
// net) per substituir el binari per ell mateix. Si execv falla, el procés
|
||||
// surt amb error.
|
||||
page.items.push_back(makeAction(
|
||||
"menu.items.restart",
|
||||
[]() {
|
||||
ServiceMenu::get().requestSceneTransition(ExitRequest{
|
||||
.next = SceneId::LOGO,
|
||||
.params = LogoParams{.reset = true},
|
||||
});
|
||||
ServiceMenu::get().close();
|
||||
System::Relaunch::request();
|
||||
SDL_Event quit_event{};
|
||||
quit_event.type = SDL_EVENT_QUIT;
|
||||
EventBuffer::events.push_back(quit_event);
|
||||
}));
|
||||
|
||||
page.items.push_back(makeAction(
|
||||
|
||||
+8
-2
@@ -7,11 +7,13 @@
|
||||
|
||||
#include "core/system/director.hpp"
|
||||
#include "core/system/event_buffer.hpp"
|
||||
#include "core/system/relaunch.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
auto SDL_AppInit(void** appstate, int argc, char* argv[]) -> SDL_AppResult {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
// Desem argv perquè el menú de servei pugui demanar un reinici en calent
|
||||
// (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.
|
||||
Log::init();
|
||||
@@ -45,6 +47,10 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
||||
{
|
||||
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.
|
||||
Log::raw(Log::Level::INFO, "Bye!");
|
||||
}
|
||||
Reference in new issue
Block a user