From 7d82a57c82f9a5359468680f36aa1026243e6f9e Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Thu, 12 Sep 2013 12:48:05 +0200 Subject: [PATCH] fix Issue 10976 - thread_joinAll after main exit performed too late - Move thread_joinAll out of rt_term and call it immediately after exiting from main instead. - Make it an error to call rt_term when other non-daemon threads are still running. - It was not a good idea to call thread_joinAll in rt_term because with DLLs threads could have been attached and outlive the runtime. - As a side effect it will be called before `static ~this()` of the main thread is run. --- src/core/runtime.d | 9 ++++++--- src/rt/dmain2.d | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/core/runtime.d b/src/core/runtime.d index acef617760c..9a7a56adb7f 100644 --- a/src/core/runtime.d +++ b/src/core/runtime.d @@ -117,9 +117,12 @@ struct Runtime /** - * Terminates the runtime. This call is to be used in instances where the - * standard program termination process will not be not executed. This is - * most often in shared libraries or in libraries linked to a C program. + * Terminates the runtime. This call is to be used in instances + * where the standard program termination process will not be not + * executed. This is most often in shared libraries or in + * libraries linked to a C program. All non-daemon threads must be + * joined or detached prior to calling this function. See also + * $(CXREF thread, thread_joinAll) and $(CXREF thread, thread_detachThis). * * Params: * dg = A delegate which will receive any exception thrown during the diff --git a/src/rt/dmain2.d b/src/rt/dmain2.d index 2efaf32cb7b..aefcdcbe7ed 100644 --- a/src/rt/dmain2.d +++ b/src/rt/dmain2.d @@ -201,8 +201,21 @@ extern (C) bool rt_term(ExceptionHandler dg = null) { try { + /* Check that all other non-daemon threads have finished + * execution before calling the shared module destructors. + * Calling thread_joinAll here would be too late because other + * shared libraries might have already been + * destructed/unloaded. + */ + import core.thread : Thread; + auto tthis = Thread.getThis(); + foreach (t; Thread) + { + if (t !is tthis && t.isRunning && !t.isDaemon) + assert(0, "Can only call rt_term when all non-daemon threads have been joined or detached."); + } + rt_moduleTlsDtor(); - thread_joinAll(); rt_moduleDtor(); gc_term(); finiSections(); @@ -481,6 +494,8 @@ extern (C) int _d_run_main(int argc, char **argv, MainFunc mainFunc) tryExec({ result = mainFunc(args); }); else result = EXIT_FAILURE; + + tryExec({thread_joinAll();}); } void runMainWithInit() @@ -490,6 +505,8 @@ extern (C) int _d_run_main(int argc, char **argv, MainFunc mainFunc) else result = EXIT_FAILURE; + tryExec({thread_joinAll();}); + if (!rt_term()) result = (result == EXIT_SUCCESS) ? EXIT_FAILURE : result; }