|
29 | 29 |
|
30 | 30 | #include <limits> |
31 | 31 | #include <string> |
| 32 | +#include <thread> |
32 | 33 |
|
33 | 34 | #include <android-base/file.h> |
34 | 35 | #include <android-base/macros.h> |
@@ -650,6 +651,58 @@ TEST(stdlib, at_quick_exit) { |
650 | 651 | AssertChildExited(pid, 99); |
651 | 652 | } |
652 | 653 |
|
| 654 | +static void exit_from_atexit_func4() { |
| 655 | + std::thread([] { exit(4); }).detach(); |
| 656 | + usleep(1000); |
| 657 | + fprintf(stderr, "4"); |
| 658 | +} |
| 659 | + |
| 660 | +static void exit_from_atexit_func3() { |
| 661 | + std::thread([] { exit(3); }).detach(); |
| 662 | + fprintf(stderr, "3"); |
| 663 | + usleep(1000); |
| 664 | + // This should cause us to exit with status 99, |
| 665 | + // but not before printing "4", |
| 666 | + // and without re-running the previous atexit handlers. |
| 667 | + exit(99); |
| 668 | +} |
| 669 | + |
| 670 | +static void exit_from_atexit_func2() { |
| 671 | + std::thread([] { exit(2); }).detach(); |
| 672 | + fprintf(stderr, "2"); |
| 673 | + usleep(1000); |
| 674 | + // Register another atexit handler from within an atexit handler. |
| 675 | + atexit(exit_from_atexit_func3); |
| 676 | +} |
| 677 | + |
| 678 | +static void exit_from_atexit_func1() { |
| 679 | + // These atexit handlers all spawn another thread that tries to exit, |
| 680 | + // and sleep to try to lose the race. |
| 681 | + // The lock in exit() should ensure that only the first thread to call |
| 682 | + // exit() can ever win (but see exit_from_atexit_func3() for a subtelty). |
| 683 | + std::thread([] { exit(1); }).detach(); |
| 684 | + usleep(1000); |
| 685 | + fprintf(stderr, "1"); |
| 686 | +} |
| 687 | + |
| 688 | +static void exit_torturer() { |
| 689 | + atexit(exit_from_atexit_func4); |
| 690 | + // We deliberately don't register exit_from_atexit_func3() here; |
| 691 | + // see exit_from_atexit_func2(). |
| 692 | + atexit(exit_from_atexit_func2); |
| 693 | + atexit(exit_from_atexit_func1); |
| 694 | + exit(0); |
| 695 | +} |
| 696 | + |
| 697 | +TEST(stdlib, exit_torture) { |
| 698 | + // Test that the atexit() handlers are run in the defined order (reverse |
| 699 | + // order of registration), even though one of them is registered by another |
| 700 | + // when it runs, and that we get the exit code from the last call to exit() |
| 701 | + // on the first thread to call exit() (rather than one of the other threads |
| 702 | + // or a deadlock from the second call on the same thread). |
| 703 | + ASSERT_EXIT(exit_torturer(), testing::ExitedWithCode(99), "1234"); |
| 704 | +} |
| 705 | + |
653 | 706 | TEST(unistd, _Exit) { |
654 | 707 | pid_t pid = fork(); |
655 | 708 | ASSERT_NE(-1, pid) << strerror(errno); |
|
0 commit comments