forked from StarOpenSource/Engine
Optimize startup and fix shutdown logic
This commit is contained in:
parent
2899ba2e8a
commit
86e85356ba
5 changed files with 86 additions and 44 deletions
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue