1 /*
2    This test makes sure the thread exit notification signals don't
3    interfere with the stack growth signals.
4 
5    Thread death notifications are sent as RT signals, which are
6    queued.  In general, these notifications are ignored, since they're
7    only used by the main thread if it has exited and is still waiting
8    for the rest to exit.
9 
10    The system has a finite limit to the number of RT signals which can
11    be queued (typically 1024), and beyond that it stops queueing
12    siginfo.  We rely on getting SIGSEGVs with siginfo information to
13    grow the stack.  If we don't get the siginfo, then it just looks
14    like the program crashed.
15 
16    The extra complication in this test is making sure that the
17    unwanted signals are discarded while the main thread is blocked in
18    a syscall.  So, to check this, main creates a new process, which
19    attempts to grow the stack once all the threads have been created
20    and exited.  main() itself is blocked waiting for the child
21    process.
22 
23    Oh, and this test also makes sure that thread resources are cleaned
24    up properly.
25  */
26 #include <pthread.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <sys/wait.h>
33 
34 static int grower;
35 
handler(int sig)36 static void handler(int sig)
37 {
38 }
39 
thr(void * v)40 static void *thr(void *v)
41 {
42 	return 0;
43 }
44 
45 #define FRAME 4096
46 
grow(int depth)47 static void grow(int depth)
48 {
49 	volatile char frame[FRAME];
50 
51 	memset((char *)frame, 0xff, sizeof(frame));
52 
53 	if (depth > 1)
54 		grow(depth-1);
55 }
56 
maker(void * v)57 static void *maker(void *v)
58 {
59 	int i;
60 
61 	sleep(1);
62 
63 	/* Create lots of threads */
64 	printf("creating threads...\n");
65 	for(i = 0; i < 1300; i++) {
66 		pthread_t t;
67 		int ret;
68 
69 		if (i % 100 == 0)
70 			printf("%d...\n", i);
71 
72 		ret = pthread_create(&t, NULL, thr, NULL);
73 		if (ret) {
74 			printf("pthread_create failed: %s\n", strerror(ret));
75 			exit(1);
76 		}
77 
78 		ret = pthread_join(t, NULL);
79 		if (ret) {
80 			printf("pthread_join failed: %s\n", strerror(ret));
81 			exit(1);
82 		}
83 	}
84 
85 	kill(grower, SIGUSR1);
86 
87 	return NULL;
88 }
89 
main()90 int main()
91 {
92 	pthread_t pth;
93 	sigset_t mask;
94 	int status;
95 	struct sigaction sa;
96 
97 	sigemptyset(&mask);
98 	sigaddset(&mask, SIGCHLD);
99 	sigprocmask(SIG_BLOCK, &mask, NULL);
100 
101 	sa.sa_handler = handler;
102 	sa.sa_flags = 0;
103 	sigfillset(&sa.sa_mask);
104 	sigaction(SIGUSR1, &sa, NULL);
105 
106 	grower = fork();
107 
108 	if (grower == -1) {
109 		perror("fork");
110 		exit(1);
111 	}
112 
113 	if (grower == 0) {
114 		pause();	/* child - wait for SIGUSR1 */
115 		grow(10);
116 		printf("stack grew OK\n");
117 		exit(0);
118 	}
119 
120 	pthread_create(&pth, NULL, maker, NULL);
121 
122 	/* wait for child */
123 	if (waitpid(grower, &status, 0) != grower)
124 		printf("FAILED\n");
125 	else if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
126 		printf("PASS: child OK\n");
127 	else
128 		printf("FAILED: exit status=%d\n", status);
129 
130 	pthread_join(pth, NULL);
131 
132 	return 0;
133 }
134