Bug 19556 – main thread static ctor/dtor should run both shared and thread-local simultaneously

Status
NEW
Severity
enhancement
Priority
P4
Component
druntime
Product
D
Version
D2
Platform
All
OS
All
Creation time
2019-01-07T22:15:49Z
Last change time
2024-12-07T13:39:08Z
Assigned to
No Owner
Creator
Steven Schveighoffer
Moved to GitHub: dmd#17380 →

Comments

Comment #0 by schveiguy — 2019-01-07T22:15:49Z
A classic chicken and egg problem. Let's say each thread establishes a Logger object: Logger tlsLogger; static this() { tlsLogger = new Logger(Thread.getThis); } Now, we have a problem that in shared static constructors, tlsLogger is uninitialized, so: import logger; shared static this() { tlsLogger.logInfo("initializing module doodad"); // segfault } But really, this is a problem with how shared constructors and destructors are run -- the main thread is instantiated by the OS, and so we really should run those thread static ctors first. But those static ctors may be written to depend on the shared static ctors! There is an easy solution, which requires no changes to the language or compiler. Instead of running module shared static constructors *as a whole group* in the main thread, and then running the thread local static constructors *as a whole group*, run both per module in the right order, only for the main thread. Subsequent threads can just run the thread local ctors/dtors. Cleanup has to be performed in the same way as well. This puts the dependency in the right place -- the module depends on its imported modules, no matter how the static data is initialized. And it continues to allow the thread local constructors to rely on the shared data being initialized. Thanks to Dru for the idea: https://forum.dlang.org/post/[email protected]
Comment #1 by schveiguy — 2019-01-08T16:44:46Z
Working on a PR for this, and I've run into a couple of snags. 1. Because thread local and shared static ctors will be combined, it will cause cycles in code which has no cycles if you run them separate. This means we need to deprecate the behavior, and introduce it under a DRT switch, potentially permanently as non-default. This may cause cycles in Phobos, haven't checked yet. 2. There is an existing artificial requirement that the TLS destructors of the main thread run before any of the child threads. However, this is not a correct requirement. It stems from issue #11309. Regarding item 2, what happens is this: 1. The main thread's TLS destructors are run. 2. The TLS destructor in std.concurrency sends a message to all owned threads that the thread is shutting down. 3. All threads waiting on OwnerTerminated exit (hopefully?), because the message will cascade down to all child threads as they exit and run TLS destructors. 4. All child threads are joined in reverse order of creation, but that order really doesn't matter. However, this requirement is incorrectly identified in the test case here: https://github.com/dlang/druntime/blob/1705cc1119703d13c9e17368c68b46f8010387de/test/init_fini/src/thread_join.d as "Owner threads should run TLS before child threads". There's no such actual requirement, and in fact, all threads EXCEPT daemon threads run TLS destructors as part of execution (after the thread function exits), not dependent on when child or owner threads run theirs. What really is required is that the main thread should notify all child thread mailboxes that the owner is terminating. It doesn't have to do so via TLS a dtor, but this means we need a hook from std.concurrency to druntime. A sort of "main thread is terminating" hook. So a more drawn-out change needs to happen. First, we need a registration system for such things in core.Runtime. Then we need to have std.concurrency register the shutdown of the mailbox when it is created, or in a shared static ctor. Finally, we can change the calling of ctor/dtor calls to follow the new regime.
Comment #2 by robert.schadek — 2024-12-07T13:39:08Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/17380 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB