Resolve segfault on exit

* As reported by @bpozdena , @aothmane-control - a segfault exists on exit, which has been tracked back to the threaded logging functions. This commit should resolve this segfault on exit.

This commit has been developed and tested using Arch Linux:

NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://archlinux.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux.org/"
BUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues"
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
LOGO=archlinux-logo

Installed using archlinux-2024.05.01-x86_64.iso

The version of 'ldc' that was installed, as detected by 'configure' was 1.37.0

-----------------------------------------
checking for a BSD-compatible install... /usr/bin/install -c
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for dmd... no
checking for ldc2... ldc2
checking version of D compiler... 1.37.0
checking for curl... yes
checking for sqlite... yes
checking for notify... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: creating contrib/pacman/PKGBUILD
config.status: creating contrib/spec/onedrive.spec
config.status: creating onedrive.1
config.status: creating contrib/systemd/onedrive.service
config.status: creating contrib/systemd/onedrive@.service
-----------------------------------------
This commit is contained in:
abraunegg 2024-05-09 20:41:39 +10:00
parent e408145e08
commit 28a6dd7acc
4 changed files with 29 additions and 24 deletions

2
configure vendored
View file

@ -2007,7 +2007,7 @@ $as_echo "no" >&6; }
fi
fi
for ac_prog in dmd ldmd2 ldc2
for ac_prog in dmd ldc2 ldmd2
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2

View file

@ -53,24 +53,21 @@ class LogBuffer {
flushThread.start();
}
// The destructor should only clean up resources owned directly by this instance
~this() {
object.destroy(bufferLock);
object.destroy(condReady);
object.destroy(flushThread);
}
// Shutdown logging
void shutdown() {
synchronized(bufferLock) {
if (!isRunning) return; // Prevent multiple shutdowns
isRunning = false;
condReady.notifyAll(); // Wake up all waiting threads
}
flushThread.join(); // Wait for the flush thread to finish
// Wait for the flush thread to finish outside of the synchronized block to avoid deadlocks
if (flushThread.isRunning()) {
flushThread.join();
}
flush(); // Perform a final flush to ensure all data is processed
}
shared void logThisMessage(string message, string[] levels = ["info"]) {
shared void logThisMessage(string message, string[] levels = ["info"]) {
// Generate the timestamp for this log entry
auto timeStamp = leftJustify(Clock.currTime().toString(), 28, '0');
@ -174,6 +171,11 @@ void addLogEntry(string message = "", string[] levels = ["info"]) {
logBuffer.logThisMessage(message, levels);
}
// Is logging still active
bool loggingActive() {
return logBuffer.isRunning;
}
void addProcessingLogHeaderEntry(string message, long verbosityCount) {
if (verbosityCount == 0) {
addLogEntry(message, ["logFileOnly"]);

View file

@ -100,6 +100,7 @@ int main(string[] cliArgs) {
addLogEntry("Exit scope was called", ["debug"]);
// Perform synchronised exit
performSynchronisedExitProcess("exitScope");
exit(EXIT_SUCCESS);
}
scope(failure) {
@ -107,6 +108,7 @@ int main(string[] cliArgs) {
addLogEntry("Failure scope was called", ["debug"]);
// Perform synchronised exit
performSynchronisedExitProcess("failureScope");
exit(EXIT_FAILURE);
}
// Read in application options as passed in
@ -774,7 +776,7 @@ int main(string[] cliArgs) {
syncEngineInstance.scanLocalFilesystemPathForNewData(path);
} catch (CurlException e) {
addLogEntry("Offline, cannot create remote dir: " ~ path, ["verbose"]);
} catch(Exception e) {
} catch (Exception e) {
addLogEntry("Cannot create remote directory: " ~ e.msg, ["info", "notify"]);
}
}
@ -796,13 +798,13 @@ int main(string[] cliArgs) {
syncEngineInstance.deleteByPath(path);
} catch (CurlException e) {
addLogEntry("Offline, cannot delete item: " ~ path, ["verbose"]);
} catch(SyncException e) {
} catch (SyncException e) {
if (e.msg == "The item to delete is not in the local database") {
addLogEntry("Item cannot be deleted from Microsoft OneDrive because it was not found in the local database", ["verbose"]);
} else {
addLogEntry("Cannot delete remote item: " ~ e.msg, ["info", "notify"]);
}
} catch(Exception e) {
} catch (Exception e) {
addLogEntry("Cannot delete remote item: " ~ e.msg, ["info", "notify"]);
}
};
@ -820,7 +822,7 @@ int main(string[] cliArgs) {
}
} catch (CurlException e) {
addLogEntry("Offline, cannot move item !", ["verbose"]);
} catch(Exception e) {
} catch (Exception e) {
addLogEntry("Cannot move item: " ~ e.msg, ["info", "notify"]);
}
};
@ -1361,7 +1363,7 @@ extern(C) nothrow @nogc @system void exitHandler(int value) {
try {
assumeNoGC ( () {
addLogEntry("\nReceived termination signal, initiating cleanup");
addLogEntry("\nReceived termination signal, initiating cleanup");
// Wait for all parallel jobs that depend on the database to complete
addLogEntry("Waiting for any existing upload|download process to complete");
syncEngineInstance.shutdown();
@ -1369,7 +1371,7 @@ extern(C) nothrow @nogc @system void exitHandler(int value) {
// Perform the shutdown process
performSynchronisedExitProcess("exitHandler");
})();
} catch(Exception e) {
} catch (Exception e) {
// Any output here will cause a GC allocation
// - Error: `@nogc` function `main.exitHandler` cannot call non-@nogc function `std.stdio.writeln!string.writeln`
// - Error: cannot use operator `~` in `@nogc` function `main.exitHandler`
@ -1408,7 +1410,10 @@ void performSynchronisedExitProcess(string scopeCaller = null) {
}
// Finalise all logging and destroy log buffer
shutdownApplicationLogging();
if (loggingActive()) {
// Shutdown application logging
shutdownApplicationLogging();
}
// Perform Garbage Cleanup
GC.collect();

View file

@ -316,10 +316,10 @@ class SyncEngine {
}
// The destructor should only clean up resources owned directly by this instance
~this() {
shutdownProcessPool();
processPool = null;
}
//~this() {
// //shutdownProcessPool();
// processPool = null;
//}
// Initialise the Sync Engine class
bool initialise() {
@ -425,13 +425,11 @@ class SyncEngine {
// https://dlang.org/library/std/parallelism/task_pool.stop.html
processPool.finish(); // If we flag 'true' here, the application segfaults on exit
processPool.stop(); // Signals to all worker threads to terminate as soon as they are finished with their current Task, or immediately if they are not executing a Task.
//processPool = new TaskPool(to!int(0)); // Reinitialise processPool to a zero size
} else {
// Normal TaskPool shutdown process
addLogEntry("Shutting down processPool in a thread blocking manner", ["debug"]);
processPool.finish(true); // If blocking argument is true, wait for all worker threads to terminate before returning.
processPool.stop(); // Signals to all worker threads to terminate as soon as they are finished with their current Task, or immediately if they are not executing a Task.
//processPool = new TaskPool(to!int(0)); // Reinitialise processPool to a zero size
}
}
}