The atexit() function internally stores the exit handlers in "atexit_functions" (see src/signal_handler.c). For some reason I don't understand, f_atexit() includes this line:
atexit_functions->flags |= ARRAY_WEAK_FLAG;
This means that if you pass a lambda to atexit() and don't hold any other references to the lambda, it may be garbage collected. This is not documented, and I belive it is bad. At the very least, it is not what I expected.
Here is a sample program. Note that is doesn't print "atexit lambda 0.200 running" unless you remove the gc call.
--- cut here --- #!/usr/bin/env pike
void do_exit() { werror("do_exit function running\n"); exit(0); }
void setup_lambda(float x) { atexit(lambda() { werror("atexit lambda %f running\n", x); } ); }
int main() { call_out(setup_lambda, 0.2, 0.2); call_out(gc, 0.4); call_out(setup_lambda, 0.6, 0.6); call_out(do_exit, 0.8); return -1; }
The atexit() function internally stores the exit handlers in "atexit_functions" (see src/signal_handler.c). For some reason I don't understand, f_atexit() includes this line:
atexit_functions->flags |= ARRAY_WEAK_FLAG;
Hmm... Yes, that's probably not a good idea.
This means that if you pass a lambda to atexit() and don't hold any other references to the lambda, it may be garbage collected. This is not documented, and I belive it is bad. At the very least, it is not what I expected.
Note that the problem isn't with the lambda per se, but with the trampoline:
#!/usr/bin/env pike
void do_exit() { werror("do_exit function running\n"); exit(0); }
void setup_lambda(float x) { atexit(lambda() { werror("atexit lambda %f running\n", x); } ); atexit(lambda() { werror("atexit lambda running\n"); }); }
int main() { call_out(setup_lambda, 0.2, 0.2); call_out(gc, 0.4); call_out(setup_lambda, 0.6, 0.6); call_out(do_exit, 0.8); return -1; }
| $ pike lyslyskom23009413.pike | do_exit function running | atexit lambda running | atexit lambda 0.600 running | atexit lambda running
pike-devel@lists.lysator.liu.se