On Saturday, 13 November 2021 at 14:34:43 UTC, Steven Schveighoffer wrote:
> Whether it does this or pushes it off to another thread is incidental. The running of finalizers is a function of the GC, not the caller.
:)
> The part you are not getting is that this is not something being called by the pure code, it's being run by the GC.
import someLibrary;
// someLibrary defines a module-global
// int threadLocal;
void main()
{
someLibrary.threadLocal = () pure nothrow {
return someLibrary.blah(42);
} ();
auto old = someLibrary.threadLocal;
auto someInts = () pure { return new int[1000]; } ();
assert(someLibrary.threadLocal == old);
}
That assert may fail. Or you may even crash before getting to it, and not with an OutOfMemoryError
, but with a FinalizeError
, depending to the value of threadLocal
. Or it can be totally fine if the GC doesn't collect. What am I not getting?..
> Imagine it like a context switch to another thread that runs the GC code, and then switches back to the pure code.
If I imagine that, the assert above should always hold. Because there should be no way that imaginary "another thread" would access main thread's threadLocal
. Somehow, reality contradicts imagination.
> In fact, the GC could do this ALREADY, because it could use one of the other threads that it has paused do the collection. But it doesn't really make any difference conceptually which thread runs it. One of those other threads could be in the middle of a pure function.
Could be != is.
> It's similar to running some kernel code, or signal code -- it's initiated by a separate entity, in this case the GC.
> Unless that changed and GC isn't doing that anymore, that's a bug that's been open for some years now.
It should be closed as invalid. Which bug is that?
https://issues.dlang.org/show_bug.cgi?id=19316
Feel free to close it as invalid, if the code above either:
- dies with an OutOfMemoryError
- passes the assert
regardless of value of threadLocal
.
someLibrary
can be this for testing:
module someLibrary;
int threadLocal;
class Good
{
int calc(int input) pure nothrow { return input * 2; }
}
class Bad {
int calc(int input) pure nothrow { return input + 14; }
~this() {
// I agree with Walter, dtors should always be nothrow,
// alas current language allows this
if (threadLocal == 56) throw new Exception("ugh");
threadLocal = 0;
}
}
int blah(int input) pure nothrow {
if (input <= 25)
return (new Good).calc(input);
else
return (new Bad).calc(input);
}
Contrived? Maybe. Feel free to substitute threadLocal
with errno
, and make a syscall in Bad.~this
.