Date: Tue, 11 Mar 2025 15:06:25 -0700 From: Michael Cheponis <michael.chepo...@gmail.com> Message-ID: <caoax04p4copuaiss1ofutr-7sbhsbowrka1b7yswmu0oyb0...@mail.gmail.com>
| It's a function of the call order of the initializers, be they constructors | or other routines that establish the runtime. Yes. pthread_atfork() isn't a pthread function really, despite its name. It is a function so that code which depends upon no fork happening (without its knowledge) can enable itself to survive in the case of some other thread (which might, or might not exist) happens to fork() at a "bad" time. Since libc (and many other library) functions need to work when threads are being used, and when they're not, they need to prepare for the worst. | I suppose there is no way to force the order so that malloc is first? That's what Jörg suggested making happen. But how to accomplish that is out of my league as well, so if someone wants to make that happen, please do. If it can be guaranteed that malloc() will be correctly initialised before pthread_atfork() can possibly be called, by making its constructor run first -- assuming that is how it initialises itself, and not a simple if (!initialised) init(); type thing in each regular call, and assuming that we can force this to be true for all malloc versions that might possibly use constructors, including any an application might provide for itself - I believe bash often uses its own malloc() implementation for example, but I doubt it uses constructors) then the pthread_atfork() that we have now would not need to be changed, and it can malloc() whenever it needs to. Or so I believe, but others who understand all this better than I might know why this might not be true. Unless someone does that (ie: orders the constructors, somehow), or has some other objection to the code I proposed, I will commit it, probably over this coming weekend. For completeness, before this was made public, Taylor wondered about my choice of sticking a small header block at the start of each allocated page rather than just using an extra global variable or two; since only the current (most recently allocated) page is ever referenced by this code, that would be an easy change to make. [Data in earlier pages, if any, continue to be used, by fork(), it is just no longer relevant to pthread_atfork().] I did it the way I posted, as I prefer less globals over more, but it does mean one less atfork handler can be registered in each page of allocated memory. That doesn't bother me, as I find it hard to imagine a case where more than one page is ever going to be needed, pthread_atfork() just isn't used that much (the actual need isn't common) -- the size of a page dwarfs the size of each block used from it to register a handler. kre