Update Application.Client shutdown process

We can't actually override GLib.Application::quit in a robust way since
it's not virtual, so move as much of the shutdown process as possible to
::shutdown which can be overridden.
This commit is contained in:
Michael Gratton 2020-01-08 21:46:50 +11:00 committed by Michael James Gratton
parent b30e639022
commit 25976dd218

View file

@ -462,10 +462,30 @@ public class Application.Client : Gtk.Application {
}
public override void shutdown() {
try {
this.engine.close();
} catch (GLib.Error error) {
warning("Error shutting down the engine: %s", error.message);
bool controller_closed = false;
this.destroy_controller.begin((obj, res) => {
this.destroy_controller.end(res);
controller_closed = true;
});
// GApplication will stop the main loop, so we need to keep
// pumping here to allow destroy_controller() to exit. To
// avoid bug(s) where Geary hangs at exit, shut the whole
// thing down if it takes too long to complete
int64 start_usec = get_monotonic_time();
while (!controller_closed) {
Gtk.main_iteration();
int64 delta_usec = get_monotonic_time() - start_usec;
if (delta_usec >= FORCE_SHUTDOWN_USEC) {
// Use a warning here so a) it's usually logged
// and b) we can run under gdb with
// G_DEBUG=fatal-warnings and have it break when
// this happens, and maybe debug it.
warning("Forcing shutdown of Geary, %ss passed...",
(delta_usec / USEC_PER_SEC).to_string());
Posix.exit(2);
}
}
this.engine = null;
@ -474,6 +494,7 @@ public class Application.Client : Gtk.Application {
Util.Date.terminate();
Geary.Logging.clear();
base.shutdown();
}
@ -742,35 +763,7 @@ public class Application.Client : Gtk.Application {
public new void quit() {
if (this.controller == null ||
this.controller.check_open_composers()) {
this.last_active_main_window = null;
bool controller_closed = false;
this.destroy_controller.begin((obj, res) => {
this.destroy_controller.end(res);
controller_closed = true;
});
// Give asynchronous destroy_controller() a chance to
// complete, but to avoid bug(s) where Geary hangs at exit,
// shut the whole thing down if destroy_controller() takes too
// long to complete
int64 start_usec = get_monotonic_time();
while (!controller_closed && Gtk.events_pending()) {
Gtk.main_iteration();
int64 delta_usec = get_monotonic_time() - start_usec;
if (delta_usec >= FORCE_SHUTDOWN_USEC) {
// Use a warning here so a) it's usually logged
// and b) we can run under gdb with
// G_DEBUG=fatal-warnings and have it break when
// this happens, and maybe debug it.
warning("Forcing shutdown of Geary, %ss passed...",
(delta_usec / USEC_PER_SEC).to_string());
Posix.exit(2);
}
}
base.quit();
}
}
@ -901,7 +894,13 @@ public class Application.Client : Gtk.Application {
}
this.controller_mutex.release(ref mutex_token);
} catch (GLib.Error err) {
debug("Error destroying controller: %s", err.message);
warning("Error destroying controller: %s", err.message);
}
try {
this.engine.close();
} catch (GLib.Error error) {
warning("Error shutting down the engine: %s", error.message);
}
}
@ -1192,7 +1191,7 @@ public class Application.Client : Gtk.Application {
// application, manually work out if the application should
// quit here.
if (!this.is_background_service && get_windows().length() == 0) {
this.quit();
quit();
}
}