Optimize startup and fix shutdown logic

This commit is contained in:
JeremyStar™ 2024-07-23 19:32:37 +02:00
parent 2899ba2e8a
commit 86e85356ba
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
5 changed files with 86 additions and 44 deletions

View file

@ -355,6 +355,20 @@ public final class Engine implements SubsystemMainClass {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public synchronized void shutdown(@Range(from = 0, to = 255) int exitCode) { public synchronized void shutdown(@Range(from = 0, to = 255) int exitCode) {
if (shuttingDown) {
logger.error("Already shutting down");
return;
}
// Make engine single-threaded
Properties properties = new Properties();
properties.setProperty("sosengine.base.optimizeLogging", "false");
properties.setProperty("sosengine.base.optimizeEvents", "false");
EngineConfiguration.getInstance().loadConfiguration(properties);
// Flush log messages
Logger.flushLogMessages();
logger.info("Shutting engine down"); logger.info("Shutting engine down");
shuttingDown = true; shuttingDown = true;
@ -365,10 +379,18 @@ public final class Engine implements SubsystemMainClass {
new InternalEngineShutdownEvent().callEvent(); new InternalEngineShutdownEvent().callEvent();
logger.verb("Shutting down JVM with code " + exitCode); logger.verb("Shutting down JVM with code " + exitCode);
Logger.flushLogMessages(); // Flush all log messages before exiting
Runtime.getRuntime().exit(exitCode); Runtime.getRuntime().exit(exitCode);
} }
/**
* Shuts the engine and JVM down.
*
* @since v1-alpha0
*/
public void shutdown() {
shutdown(0);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -393,13 +415,4 @@ public final class Engine implements SubsystemMainClass {
public DependencyVector getDependencyVector() { public DependencyVector getDependencyVector() {
return new DependencyVector("engine", StarOpenSourceVersioningSystem.class, EngineInformation.getVersioningString()); return new DependencyVector("engine", StarOpenSourceVersioningSystem.class, EngineInformation.getVersioningString());
} }
/**
* Shuts the engine and JVM down.
*
* @since v1-alpha0
*/
public synchronized void shutdown() {
shutdown(0);
}
} }

View file

@ -298,7 +298,8 @@ public final class EngineConfiguration implements SubsystemConfiguration {
// Loop through all properties // Loop through all properties
for (String property : properties.stringPropertyNames()) { for (String property : properties.stringPropertyNames()) {
// Check if property name starts with group // Check if property name starts with group
if (!property.startsWith(group)) continue; if (!property.startsWith(group))
continue;
// Skip to important stuff // Skip to important stuff
property = property.substring(group.length()); property = property.substring(group.length());

View file

@ -20,18 +20,17 @@
package de.staropensource.sosengine.graphics.glfw; package de.staropensource.sosengine.graphics.glfw;
import de.staropensource.sosengine.base.annotations.EngineSubsystem; import de.staropensource.sosengine.base.annotations.EngineSubsystem;
import de.staropensource.sosengine.base.annotations.EventListener;
import de.staropensource.sosengine.base.classes.SubsystemMainClass; import de.staropensource.sosengine.base.classes.SubsystemMainClass;
import de.staropensource.sosengine.base.data.info.EngineInformation; import de.staropensource.sosengine.base.data.info.EngineInformation;
import de.staropensource.sosengine.base.data.versioning.StarOpenSourceVersioningSystem; import de.staropensource.sosengine.base.data.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.sosengine.base.internal.events.InternalEngineShutdownEvent;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.CodePart; import de.staropensource.sosengine.base.types.CodePart;
import de.staropensource.sosengine.base.types.DependencyVector; import de.staropensource.sosengine.base.types.DependencyVector;
import de.staropensource.sosengine.base.types.EventPriority;
import de.staropensource.sosengine.base.types.logging.LogIssuer; import de.staropensource.sosengine.base.types.logging.LogIssuer;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.graphics.glfw.events.GraphicsErrorEvent; import de.staropensource.sosengine.graphics.glfw.events.GraphicsErrorEvent;
import de.staropensource.sosengine.graphics.glfw.exceptions.GlfwInitializationException; import de.staropensource.sosengine.graphics.glfw.exceptions.GlfwInitializationException;
import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWErrorCallback;
@ -70,6 +69,15 @@ public class GlfwSubsystem implements SubsystemMainClass {
*/ */
private final LoggerInstance logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE)); private final LoggerInstance logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE));
/**
* The {@link GLFWErrorCallback} to use.
* <p>
* Only declared publicly for freeing during engine shutdown.
*
* @since v1-alpha2
*/
private final GLFWErrorCallback errorCallback = GLFWErrorCallback.create(new GraphicsErrorEvent());
/** /**
* Constructs this subsystem. * Constructs this subsystem.
* *
@ -107,11 +115,16 @@ public class GlfwSubsystem implements SubsystemMainClass {
* @since v1-alpha2 * @since v1-alpha2
*/ */
public void initializeGlfw() { public void initializeGlfw() {
// Set error callback logger.verb("Initializing GLFW");
try (GLFWErrorCallback errorCallback = GLFWErrorCallback.create(new GraphicsErrorEvent())) {
errorCallback.set(); if (!Miscellaneous.onMainThread()) {
logger.crash("Unable to initialize GLFW on a non-main thread", new NotOnMainThreadException(), true);
return;
} }
// Set error callback
errorCallback.set();
// Initialize GLFW // Initialize GLFW
if (!glfwInit()) if (!glfwInit())
throw new GlfwInitializationException(); throw new GlfwInitializationException();
@ -125,19 +138,12 @@ public class GlfwSubsystem implements SubsystemMainClass {
public void terminateGlfw() { public void terminateGlfw() {
logger.verb("Terminating GLFW"); logger.verb("Terminating GLFW");
glfwTerminate(); if (!Miscellaneous.onMainThread()) {
//noinspection DataFlowIssue,resource logger.crash("Unable to terminate GLFW on a non-main thread. Did you call Engine#shutdown or Logger#crash from another thread?", new NotOnMainThreadException(), true);
glfwSetErrorCallback(null).free(); return;
} }
/** glfwTerminate();
* Called when the engine shuts down. errorCallback.free();
*
* @since v1-alpha2
*/
@EventListener(event = InternalEngineShutdownEvent.class, priority = EventPriority.EXTREMELY_UNIMPORTANT)
private static void shutdownApiFromEvent() {
if (instance != null)
instance.terminateGlfw();
} }
} }

View file

@ -29,7 +29,6 @@ import de.staropensource.sosengine.base.internal.events.InternalEngineShutdownEv
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.CodePart; import de.staropensource.sosengine.base.types.CodePart;
import de.staropensource.sosengine.base.types.DependencyVector; import de.staropensource.sosengine.base.types.DependencyVector;
import de.staropensource.sosengine.base.types.EventPriority;
import de.staropensource.sosengine.base.types.logging.LogIssuer; import de.staropensource.sosengine.base.types.logging.LogIssuer;
import de.staropensource.sosengine.base.utility.ListFormatter; import de.staropensource.sosengine.base.utility.ListFormatter;
import de.staropensource.sosengine.base.utility.Miscellaneous; import de.staropensource.sosengine.base.utility.Miscellaneous;
@ -161,12 +160,17 @@ public final class GraphicsSubsystem implements SubsystemMainClass {
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
@EventListener(event = InternalEngineShutdownEvent.class, priority = EventPriority.EXTREMELY_UNIMPORTANT) @EventListener(event = InternalEngineShutdownEvent.class)
public static void shutdown() { private static void shutdown() {
LoggerInstance logger = instance.logger; LoggerInstance logger = instance.logger;
logger.verb("Shutting down"); logger.verb("Shutting down");
long shutdownTime = Miscellaneous.measureExecutionTime(() -> new GraphicsApiShutdownEvent().callEvent()); long shutdownTime = Miscellaneous.measureExecutionTime(() -> {
new GraphicsApiShutdownEvent().callEvent();
if (instance.api != null)
instance.api.shutdownApi();
});
logger.info("Shut down in " + shutdownTime + "ms"); logger.info("Shut down in " + shutdownTime + "ms");
} }
@ -201,7 +205,7 @@ public final class GraphicsSubsystem implements SubsystemMainClass {
// Check if registered apis are compatible // Check if registered apis are compatible
for (String apiName : registeredApis.keySet()) for (String apiName : registeredApis.keySet())
if (registeredApis.get(apiName).isCompatible()) { if (registeredApis.get(apiName).isCompatible()) {
logger.diag("" + apiName + " is compatible"); logger.diag(apiName + " is compatible");
compatibleApis.add(apiName); compatibleApis.add(apiName);
} else } else
logger.diag(apiName + " is not compatible"); logger.diag(apiName + " is not compatible");

View file

@ -20,16 +20,20 @@
package de.staropensource.sosengine.testapp; package de.staropensource.sosengine.testapp;
import de.staropensource.sosengine.base.Engine; import de.staropensource.sosengine.base.Engine;
import de.staropensource.sosengine.base.annotations.EventListener;
import de.staropensource.sosengine.base.events.ThrowableCatchEvent;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.CodePart; import de.staropensource.sosengine.base.types.CodePart;
import de.staropensource.sosengine.base.types.logging.LogIssuer; import de.staropensource.sosengine.base.types.logging.LogIssuer;
import de.staropensource.sosengine.base.types.vectors.Vec2i; import de.staropensource.sosengine.base.types.vectors.Vec2i;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.graphics.GraphicsSubsystem; import de.staropensource.sosengine.graphics.GraphicsSubsystem;
import de.staropensource.sosengine.graphics.classes.ApiMainClass; import de.staropensource.sosengine.graphics.classes.ApiMainClass;
import de.staropensource.sosengine.graphics.classes.ApiManagementClass; import de.staropensource.sosengine.graphics.classes.ApiManagementClass;
import de.staropensource.sosengine.graphics.classes.Window; import de.staropensource.sosengine.graphics.classes.Window;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
/** /**
* The initialization class for sos!engine's development application. * The initialization class for sos!engine's development application.
@ -78,7 +82,7 @@ public class Main {
/** /**
* The program's entrypoint. * The program's entrypoint.
* Calls {@code run()} after invocation. * Calls {@link #run(String[])} after invocation.
* *
* @see Main#run(String[]) * @see Main#run(String[])
* @param args program's command line arguments * @param args program's command line arguments
@ -88,15 +92,15 @@ public class Main {
} }
/** /**
* The program's entrypoint but not static. * The program's entrypoint except it's not static.
* Here's where the "real magic" happens- * Here's where the "real magic" happens.
* *
* @see Main#main(String[]) * @see Main#main(String[])
* @param args program's command line arguments * @param args program's command line arguments
*/ */
@SneakyThrows @SneakyThrows
public void run(String[] args) { public void run(String[] args) {
try { Miscellaneous.executeSafely(() -> {
// Initialize sos!engine // Initialize sos!engine
engine = new Engine(); engine = new Engine();
@ -124,13 +128,27 @@ public class Main {
} }
// Sleep for five seconds // Sleep for five seconds
try {
Thread.sleep(5000); Thread.sleep(5000);
} catch (InterruptedException exception) {
logger.crash("Was unable to sleep for 5000ms", exception);
}
// Shutdown // Shutdown
Engine.getInstance().shutdown(0); Engine.getInstance().shutdown();
} catch (Throwable throwable) { }, "mainThread");
Thread.ofVirtual().start(() -> Engine.getInstance().shutdown(69)); }
throw throwable;
/**
* Crashes the application when a throwable
* is thrown in {@link #run(String[])}.
*
* @since v1-alpha2
*/
@EventListener(event = ThrowableCatchEvent.class)
public static void onThrowable(@NotNull Throwable throwable, @NotNull String identifier) {
if (identifier.equals("mainThread")) {
instance.logger.crash("The main thread threw an exception", throwable);
} }
} }
} }