From: KOSAKI Motohiro Date: 2011-02-15T19:38:03+09:00 Subject: [ruby-core:35248] Re: [Ruby 1.9-Bug#4400][Open] nested at_exit hooks run in strange order 2011/2/15 Suraj Kurapati : > Bug #4400: nested at_exit hooks run in strange order > http://redmine.ruby-lang.org/issues/show/4400 > > Author: Suraj Kurapati > Status: Open, Priority: Normal > Category: core > ruby -v: ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-linux] > > Hello, > > The documentation for Kernel#at_exit says "If multiple [at_exit] handlers are > registered, they are executed in reverse order of registration". �However, does > not seem to be true for nested at_exit hooks (registering an at_exit hook inside > another at_exit hook). �For example consider this code: > > at_exit { puts :outer0 } > at_exit { puts :outer1_begin; at_exit { puts :inner1 }; puts :outer1_end } > at_exit { puts :outer2_begin; at_exit { puts :inner2 }; puts :outer2_end } > at_exit { puts :outer3 } > > Here is the output of running this code with two Rubies: > > ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-linux] > outer3 > outer2_begin > outer2_end > outer1_begin > outer1_end > outer0 > inner1 > inner2 > > ruby 1.8.7 (2010-08-16 patchlevel 302) [x86_64-linux] > outer3 > outer2_begin > outer2_end > outer1_begin > outer1_end > outer0 > inner1 > inner2 > > Observe how inner1 and inner2 are executed in registration order after all > non-nested hooks are executed in reverse registration order. �This seems very > strange to me; I would expect nested at_exit hooks to be executed immediately > (as follows) because we are already inside the at_exit phase of the program: > > outer3 > outer2_begin > inner2 > outer2_end > outer1_begin > inner1 > outer1_end > outer0 > > What do you think? �Thanks for your consideration. btw, C's atexit() has different behavior. at_exit.c ------------------------------------------------------------------ #include #include static void func0(void) { printf("outer0\n"); } static void func1_inner(void) { printf("inner1\n"); } static void func1(void) { printf("outer1_begin\n"); atexit(func1_inner); printf("outer1_end\n"); } static void func2_inner(void) { printf("inner2\n"); } static void func2(void) { printf("outer2_begin\n"); atexit(func2_inner); printf("outer2_end\n"); } static void func3(void) { printf("outer3\n"); } main() { atexit(func0); atexit(func1); atexit(func2); atexit(func3); } ------------------------------------------------------------------ % gcc at_exit.c; ./a.out outer3 outer2_begin outer2_end inner2 outer1_begin outer1_end inner1 outer0