| /* 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); | 
 | } |