| /* Copyright (c) 2016 Google, Inc. |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. */ |
| |
| #include <utest/utest.h> |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| /* This tests a bug where if a thread other than thread0 registered an atexit() |
| * function, we'd GPF when thread0 exited. Due to the way our infrastructure |
| * prints tests results before the program exited, you may see this say that the |
| * test succeeded, but then fail later with a GPF or other assertion. */ |
| |
| TEST_SUITE("AT-EXIT"); |
| |
| /* <--- Begin definition of test cases ---> */ |
| |
| static bool child_ran_atexit = FALSE; |
| |
| static void child_atexit(void) |
| { |
| child_ran_atexit = TRUE; |
| } |
| |
| static void *child_func(void *arg) |
| { |
| atexit(child_atexit); |
| return 0; |
| } |
| |
| static void main_atexit(void) |
| { |
| /* Using the non-UT assert, since the test_atexit_threads() has already |
| * returned. Also, since the child called atexit() after main, its |
| * handler should run first, according to the man page. */ |
| assert(child_ran_atexit); |
| } |
| |
| bool test_atexit_threads(void) |
| { |
| pthread_t child; |
| void *child_ret; |
| |
| atexit(main_atexit); |
| pthread_create(&child, NULL, &child_func, NULL); |
| pthread_join(child, &child_ret); |
| return TRUE; |
| } |
| |
| /* <--- End definition of test cases ---> */ |
| |
| struct utest utests[] = { |
| UTEST_REG(atexit_threads), |
| }; |
| int num_utests = sizeof(utests) / sizeof(struct utest); |
| |
| int main(int argc, char *argv[]) |
| { |
| char **whitelist = &argv[1]; |
| int whitelist_len = argc - 1; |
| |
| RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len); |
| } |